web-dev-qa-db-fra.com

Comment appeler une fermeture qui est une variable de classe?

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()

Alors, quelle est la syntaxe correcte pour atteindre les variables de classe?

74
rsk82

En PHP, les méthodes et les propriétés sont dans un espace de noms distinct (vous pouvez avoir une méthode et une propriété avec le même nom), et si vous accédez à une propriété ou à une méthode dépend de la syntaxe que vous utilisez pour le faire.

$expr->something() est un appel de méthode, donc PHP recherchera something dans la liste des méthodes de la classe.

$expr->something Est une extraction de propriété, donc PHP recherchera something dans la liste des propriétés de la classe).

$myInstance->lambda(); est analysé comme un appel de méthode, donc PHP recherche une méthode nommée lambda dans votre classe, mais il n'y a pas une telle méthode (d'où la Appel à une méthode non définie erreur).

Vous devez donc utiliser la syntaxe de la propriété fetch pour récupérer le lambda, puis l'appeler.

  • Depuis PHP 7.0, vous pouvez le faire avec ($obj->lambda)():

    ($obj->lambda)();
    

    Les parenthèses s'assurent que PHP analyse ($obj->lambda) Comme récupère la propriété nommée lambda . Ensuite, () Appelle le résultat de la récupération de la propriété.

  • ou vous pouvez le faire avec ->lambda->__invoke():

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

    __invoke est l'une des méthodes magiques de PHP . Lorsqu'un objet implémente cette méthode, il devient invocable: il peut être appelé à l'aide de la syntaxe $var(). Les fonctions anonymes sont des instances de Closure , qui implémente __invoke.

  • Ou affectez-le à une variable locale:

    $lambda = $myInstance->lambda;
    $lambda();
    
  • Ou appelez-le en utilisant call_user_func:

    call_user_func($myInstance->lambda);
    

    call_user_func peut appeler n'importe quel callable , y compris les fonctions anonymes.

  • Alternativement, s'il s'agit d'un modèle courant dans votre code, vous pouvez configurer une méthode __call Pour transférer les appels vers votre lambda:

    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);
        }
    }
    

    Maintenant, cela fonctionne:

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

    Depuis PHP 5.4 vous pouvez même le faire dans un 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();
    
185
Arnaud Le Blanc

Vous pouvez également appeler votre fonction lambda sans changer quelque chose dans votre classe, à l'aide de ReflectionFunction.

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

ou si vous devez passer des arguments alors

$args = array('arg'=>'value');
$lambda->invokeArgs($args);
2
akDeveloper