1. ホーム
  2. php

[解決済み] クラス変数であるクロージャを呼び出すには?

2023-06-05 02:56:11

質問

class MyClass {
  var $lambda;
  function __construct() {
    $this->lambda = function() {echo 'hello world';};
    // no errors here, so I assume that this is legal
  }
}

$myInstance = new MyClass();
$myInstance->lambda();
//Fatal error: Call to undefined method MyClass::lambda()

クラス変数に到達するための正しい文法は何でしょうか?

どのように解決するのですか?

PHPでは、メソッドとプロパティは別の名前空間にあり(同じ名前のメソッドとプロパティを持つことができます)、プロパティとメソッドのどちらにアクセスするかは、それを行うために使用する構文に依存します。

$expr->something() はメソッド呼び出しなので、PHP は something をクラスのメソッド一覧から探します。

$expr->something はプロパティの取得なので、PHP は something をクラスのプロパティの一覧から探します。

$myInstance->lambda(); はメソッド呼び出しとしてパースされるので、PHP はその名前のメソッドを探します。 lambda という名前のメソッドを探しますが、そのようなメソッドはありません (そのため 未定義のメソッドへの呼び出し エラーが発生します)。

というわけで、このような場合は フェッチプロパティ 構文を使ってラムダを取得し、それを呼び出します。

  • PHP 7.0 以降、これを行うには ($obj->lambda)() :

    ($obj->lambda)();
    
    

    括弧は、PHP が ($obj->lambda) として lambda という名前のプロパティを取得します。 . 次に () はプロパティをフェッチした結果を呼び出します。

  • で行うこともできます。 ->lambda->__invoke() :

    $myInstance = new MyClass();
    $myInstance->lambda->__invoke();
    
    

    __invoke PHP のマジックメソッド . オブジェクトがこのメソッドを実装すると、呼び出すことができるようになります。 $var() 構文で呼び出すことができます。匿名関数は Closure を実装している __invoke .

  • またはローカル変数に代入します。

    $lambda = $myInstance->lambda;
    $lambda();
    
    
  • またはcall_user_funcを使って呼び出します。

    call_user_func($myInstance->lambda);
    
    

    call_user_func は、任意の callable を、無名関数を含めて呼び出すことができます。

  • あるいは、これがあなたのコードで一般的なパターンである場合、あなたのコードに __call メソッドを設定して、ラムダへの呼び出しを転送することもできます。

    class MyClass
    {
        private $lambda;
    
        public function __construct()
        {
            $this->lambda = function() {
                echo "Hello world!\n";
            };
        }
    
        public function __call($name, $args)
        {
            return call_user_func_array($this->$name, $args);
        }
    }
    
    

    これでうまくいきました。

    $myInstance = new MyClass();
    $myInstance->lambda();
    
    

    PHP 5.4以降では、traitの中でそれを行うこともできます。

    trait LambdasAsMethods
    {
        public function __call($name, $args)
        {
            return call_user_func_array($this->$name, $args);
        }
    }
    
    class MyClass
    {
        use LambdasAsMethods;
    
        private $lambda;
    
        public function __construct()
        {
            $this->lambda = function() {
                echo "Hello World!\n";
            };
        }
    }
    
    $myInstance = new MyClass();
    $myInstance->lambda();