PHP 8.5 新特性 閉包可以作為常量表達式了
PHP 8.5 新特性 閉包可以作為常量表達式了
PHP 8.5 又帶來了一個讓人興奮的新特性:閉包現在可以作為常量表達式使用了,這意味著它們可以出現在默認參數或屬性值中。
你是不是也遇到過這種情況:想在 PHP 中把閉包設置為默認參數值,結果只能想各種變通方案?在 PHP 8.5 中,這個煩惱終于沒了。閉包現在可以作為常量表達式——也就是說,它們可以用在任何你之前只能用字面值的地方。
我之前就被這個限制坑過,而且不止一次。現在,你可以在這些地方使用閉包了:
- 默認參數值
- 常量值
- 屬性默認值
- 屬性參數值
- 還有更多
默認值
以前,我會寫這樣的代碼:
function someFunction(mixed $someValue, ?callable $callback = null): bool
{
$callback ??= fn () => true;
return $callback($someValue);
}
或者這樣:
final class SomeClass
{
private Closure $someCallable;
public function __construct()
{
$this->someCallable = function (mixed $value): bool {
// 待實現
return true;
};
}
}
有了閉包常量表達式,這兩個例子都可以簡化成:
function someFunction(
mixed $someValue,
callable $callback = static function () { return true; },
): bool {
return $callback($someValue);
}
final class SomeClass
{
private Closure $someCallable = static function (mixed $value): bool {
// 待實現
return true;
};
}
不用再寫 $callback ??= 這種繞來繞去的代碼了。直接把閉包作為默認參數值是我經常要做的事,現在能夠通過避免像 null 這種無意義的值來精簡公共接口,這個改進真的很棒。
屬性(Attributes)
這是另一個很贊的改變——你現在可以直接在屬性中定義函數了。比如:
#[Attribute(Attribute::TARGET_PROPERTY)]
final readonly class TruthyValidator
{
public function __construct(
public Closure $truthyValidator = static function(mixed $value): bool {
return (bool) $value;
}
) {
}
}
這是一個簡單的驗證器屬性,用來檢查值是否為真值,默認實現就是把它轉成布爾值,讓 PHP 自己處理轉換。但假如你想把字符串 '0' 也當作真值:
#[TruthyValidator(truthyValidator: static function(string|int|null $value): bool {
return $value === '0' || $value;
})]
public string|int|null $someProperty = null;
First-Class Callables
嚴格來說這是一個獨立的 RFC,但它是因為投票原因才拆分的,技術上并不是獨立的,所以我在同一篇文章里一起介紹。
除了標準的閉包(你可以內聯定義函數體),現在你也可以用 first-class callables 作為常量表達式了。這意味著上面所有的例子也都適用于它們。
<?php
// 定義一個默認驗證器
function defaultValidatorFunction(mixed $value): bool
{
return (bool) $value;
}
// 定義驗證器類
#[Attribute(Attribute::TARGET_PROPERTY)]
final readonly class TruthyValidator
{
public function __construct(
// 使用 first-class callable 語法分配默認驗證器
public Closure $truthyValidator = defaultValidatorFunction(...),
) {
}
}
// 定義我們自定義的驗證函數
function truthyValidatorWithoutZeroString(string|int|null $value): bool
{
return $value === '0' || $value;
}
class SomeClassToBeValidated
{
// 用 first-class callable 的方式使用它
#[TruthyValidator(truthyValidator: truthyValidatorWithoutZeroString(...))]
public string|int|null $someProperty = null;
}
總結
我個人真的很喜歡這個新特性,因為它——就像最近的很多其他改進一樣——讓 PHP 變成了一門更簡潔、更一致的語言,減少了各種 hack 和怪異的語法。

浙公網安備 33010602011771號