PHP 8.5 新特性 閉包可以(yi)作為(wei)常量表(biao)達式了
PHP 8.5 新特性 閉包可以作為常量表達式了
PHP 8.5 又帶來了一個讓人(ren)興奮的(de)新特性:閉包現在可以作為常量表達式使(shi)用了,這意(yi)味(wei)著(zhu)它們可以出(chu)現在默認參數或屬性值(zhi)中。
你是(shi)不(bu)是(shi)也(ye)遇到過這(zhe)(zhe)種(zhong)情況(kuang):想(xiang)在(zai) PHP 中(zhong)把閉包(bao)設置為默(mo)認參(can)數值,結果只(zhi)能(neng)想(xiang)各種(zhong)變通方案?在(zai) PHP 8.5 中(zhong),這(zhe)(zhe)個煩惱終(zhong)于沒(mei)了。閉包(bao)現在(zai)可(ke)以作為常量表(biao)達式(shi)——也(ye)就是(shi)說(shuo),它們可(ke)以用在(zai)任何你之前只(zhi)能(neng)用字(zi)面值的地方。
我之前就被這個限制(zhi)坑(keng)過,而且(qie)不止一次。現在,你(ni)可以在這些(xie)地方使(shi)用閉包(bao)了:
- 默認參數值
- 常量值
- 屬性默認值
- 屬性參數值
- 還有更多
默認值
以(yi)前,我會寫(xie)這(zhe)樣的代碼:
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;
};
}
}
有了閉包(bao)常量(liang)表達(da)式,這兩(liang)個例子(zi)都可以簡化成:
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 這種無意義的(de)(de)值來(lai)精簡公共接(jie)口(kou),這個改進真的(de)(de)很棒。
屬性(Attributes)
這是另一個很贊的改變——你現(xian)在(zai)可以直(zhi)接在(zai)屬性中定義函數了(le)。比如:
#[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
嚴格來說(shuo)這是(shi)一(yi)個獨(du)立(li)的 RFC,但它是(shi)因(yin)為(wei)投票原(yuan)因(yin)才(cai)拆分的,技術(shu)上并不是(shi)獨(du)立(li)的,所(suo)以我在同一(yi)篇(pian)文章里一(yi)起介紹。
除了(le)標準的閉(bi)包(你可以(yi)內聯定義函數體(ti)),現在(zai)你也(ye)可以(yi)用(yong) first-class callables 作為常(chang)量表達式了(le)。這意味(wei)著上面所有的例子也(ye)都適用(yong)于它(ta)們(men)。
<?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;
}
總結
我(wo)個人真的(de)很喜歡(huan)這個新特性,因為它——就像最近的(de)很多其他改進(jin)一(yi)(yi)樣——讓 PHP 變成(cheng)了(le)一(yi)(yi)門更簡潔(jie)、更一(yi)(yi)致的(de)語言,減少了(le)各(ge)種 hack 和怪異的(de)語法。
