提案された
匿名関数が出現する前は、すべての関数は使用する前に名前を付ける必要がありました
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
すべての匿名関数はクロージャ オブジェクトのインスタンスです
$greet instanceof Closure // true
オブジェクトには親スコープがないため、使用する変数を手動で宣言するには use を使用する必要があります。
$num = 1; $func = function() use($num){ $num = $num + 1; echo $num; } $func(); // 2 echo $num; // 还是 1
無名関数内の変数を有効にしたい場合は、参照渡しを使用する必要があります。 -value
$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 オブジェクトです。 5 つのメソッド
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 - 2 つの使用法がある、bindTo メソッドの静的バージョン:
使用法 1:bindTo メソッドと同じ効果を実現するため
$count = \Closure::bind($addDiscount, $good, Good::class);
使用法 2: 匿名関数を (オブジェクトではなく) クラスにバインドします。2 番目のパラメーターを null
// 商品库存为 10 class Good { static $num = 10; } // 每次销售后返回当前库存 $sell = static function() { return"当前库存为". --static::$num ; }; // 将静态匿名函数绑定到 Good 类中 $sold = \Closure::bind($sell, null, Good::class); $sold(); // 当前库存为 9 $sold(); // 当前库存为 8
call に設定することを忘れないでください - PHP 7 New call メソッドは匿名関数をバインドして呼び出すことができます。構文が単純になるだけでなく、パフォーマンスも向上します。
// call 版本 $addDiscount->call($good, 0.5); // 绑定并传入参数 0.5,结果为 50 // bindTo 版本 $count = $addDiscount->bindTo($good, Good::class, 0.5); $count(); // 50
fromCallable - 指定された呼び出し可能関数を匿名関数に変換します
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();
と同等です。ここで特別な注意が必要な点は、bindTo を使用する場合、2 番目のパラメータがバインディングを指定している場合、それが fromCallable から変換されたクロージャであるか、リフレクションを使用して取得されたクロージャであるかということです。クラスの場合、エラーが報告されます
Cannot rebind scope of closure created by ReflectionFunctionAbstract::getClosure()
以上がPHP コア機能の匿名関数の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。