PHP中的匿名函數怎么實現?針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
在匿名函數出現之前,所有的函數都需要先命名才能使用
function increment($value)
{
return $value + 1;
}
array_map('increment', [1, 2, 3]);有的時候函數可能只需要使用一次,這時候使用匿名函數會使得代碼更加簡潔直觀,同時也避免了函數在其他地方被使用
array_map(function($value){
return $value + 1;
}, [1, 2, 3]);定義和使用
PHP 將閉包和匿名函數視為同等概念(本文統稱為匿名函數),本質上都是偽裝成函數的對象。
匿名函數的本質是對象,因此跟對象一樣可將匿名函數賦值給某一變量
$greet = function(string $name){
echo "hello {$name}";
}
$greet("jack") // hello jack所有的匿名函數都是 Closure 對象的實例
$greet instanceof Closure // true
對象并沒有什么父作用域可言,所以需要使用 use 來手動聲明使用的變量,
$num = 1;
$func = function() use($num){
$num = $num + 1;
echo $num;
}
$func(); // 2
echo $num; // 還是 1如果要讓匿名函數中的變量生效,需要使用引用傳值
$num = 1;
$func = function() use(&$num){
$num = $num + 1;
echo $num;
}
$func(); // 2
echo $num; // 2從 PHP 5.4 開始,在類里面使用匿名函數時,匿名函數的 $this 將自動綁定到當前類
class Foo {
public function bar()
{
return function() {
return $this;
};
}
}
$foo = new Foo();
$obj = $foo->bar(); // Closure()
$obj(); // Foo如果不想讓自動綁定生效,可使用靜態匿名函數
class Foo {
public function bar()
{
return static function() {
return $this;
};
}
}
$foo = new Foo();
$obj = $foo->bar(); // Closure()
$obj(); // Using $this when not in object context匿名函數的本質
匿名函數的本質是 Closure 對象,包括了以下五個方法
Closure {
private __construct ( void )
public static bind ( Closure $closure , object $newthis [, mixed $newscope = "static" ] ) : Closure
public bindTo ( object $newthis [, mixed $newscope = "static" ] ) : Closure
public call ( object $newthis [, mixed $... ] ) : mixed
public static fromCallable ( callable $callable ) : Closure
}__construct - 防止匿名函數被實例化
$closure = new \Closure(); // PHP Error: Instantiation of 'Closure' is not allowed
Closure::bindTo - 復制當前匿名函數對象,綁定指定的 $this 對象和類作用域。通俗的說,就是手動將匿名函數與指定對象綁定,利用這點,可以為擴展對象的功能。
// 定義商品類
class Good {
private $price;
public function __construct(float $price)
{
$this->price = $price;
}
}
// 定義一個匿名函數,計算商品的促銷價
$addDiscount = function(float $discount = 0.8){
return $this->price * $discount;
}
$good = new Good(100);
// 將匿名函數綁定到 $good 實例,同時指定作用域為 Good
$count = $addDiscount->bindTo($good, Good::class);
$count(); // 80
// 將匿名函數綁定到 $good 實例,但是不指定作用域,將無法訪問 $good 的私有屬性
$count = $addDiscount->bindTo($good);
$count(); // 報錯Closure::bind - bindTo 方法的靜態版本,有兩種用法:
用法一:實現與 bindTo 方法同樣的效果
$count = \Closure::bind($addDiscount, $good, Good::class);
用法二:將匿名函數與類(而不是對象)綁定,記得要將第二個參數設置為 null
// 商品庫存為 10
class Good {
static $num = 10;
}
// 每次銷售后返回當前庫存
$sell = static function() {
return"當前庫存為". --static::$num ;
};
// 將靜態匿名函數綁定到 Good 類中
$sold = \Closure::bind($sell, null, Good::class);
$sold(); // 當前庫存為 9
$sold(); // 當前庫存為 8call - PHP 7 新增的 call 方法可以實現綁定并調用匿名函數,除了語法更加簡潔外,性能也更高
// call 版本 $addDiscount->call($good, 0.5); // 綁定并傳入參數 0.5,結果為 50 // bindTo 版本 $count = $addDiscount->bindTo($good, Good::class, 0.5); $count(); // 50
fromCallable - 將給定的 callable 函數轉化成匿名函數
class Good {
private $price;
public function __construct(float $price)
{
$this->price = $price;
}
}
function addDiscount(float $discount = 0.8){
return $this->price * $discount;
}
$closure = \Closure::fromCallable('addDiscount');
$good = new Good(100);
$count = $closure->bindTo($good);
$count = $closure->bindTo($good, Good::class); // 報錯,不能重復綁定作用域
$count(); // 報錯,無法訪問私有屬性fromCallable 等價于
$reflexion = new ReflectionFunction('addDiscount');
$closure = $reflexion->getClosure();這里有一點需要特別注意的是,無論是 fromCallable 轉化成的閉包,還是使用反射得到的閉包,在使用 bindTo 時,如果第二個參數指定綁定類,會報錯
Cannot rebind scope of closure created by ReflectionFunctionAbstract::getClosure()
關于PHP中的匿名函數怎么實現問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。