Wie rufe ich einen Abschluss auf, der eine Klassenvariable ist?

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

Wie lautet also die richtige Syntax zum Erreichen von Klassenvariablen?

rsk82
quelle

Antworten:

195

In PHP befinden sich Methoden und Eigenschaften in einem separaten Namespace (Sie können eine Methode und eine Eigenschaft mit demselben Namen haben). Ob Sie auf eine Eigenschaft oder eine Methode zugreifen, hängt von der Syntax ab, die Sie dazu verwenden.

$expr->something()ist ein Methodenaufruf, daher sucht PHP somethingin der Methodenliste der Klasse.

$expr->somethingist ein Eigenschaftsabruf, daher sucht PHP somethingin der Eigenschaftenliste der Klasse.

$myInstance->lambda();wird als Methodenaufruf analysiert, daher sucht PHP nach einer lambdain Ihrer Klasse benannten Methode , es gibt jedoch keine solche Methode (daher der Fehler " Aufruf einer undefinierten Methode" ).

Sie müssen also die Syntax der fetch-Eigenschaft verwenden , um das Lambda abzurufen, und es dann aufrufen.

  • Seit PHP 7.0 können Sie dies tun mit ($obj->lambda)():

    ($obj->lambda)();
    

    Die Klammern stellen Sie sicher , dass PHP Parsen ($obj->lambda)als die Eigenschaft Lambda genannt holen . Dann ()ruft das Ergebnis die Eigenschaft zu holen.

  • oder Sie können dies tun mit ->lambda->__invoke():

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

    __invokeist eine der magischen Methoden von PHP . Wenn ein Objekt diese Methode implementiert, wird sie aufrufbar: Sie kann mithilfe der $var()Syntax aufgerufen werden . Anonyme Funktionen sind Instanzen von Closure, die implementiert werden __invoke.

  • Oder weisen Sie es einer lokalen Variablen zu:

    $lambda = $myInstance->lambda;
    $lambda();
    
  • Oder rufen Sie es mit call_user_func auf:

    call_user_func($myInstance->lambda);
    

    call_user_funckann beliebige callable, auch anonyme Funktionen aufrufen .

  • Wenn dies ein häufiges Muster in Ihrem Code ist, können Sie alternativ eine __callMethode einrichten , um Anrufe an Ihr Lambda weiterzuleiten:

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

    Nun funktioniert das:

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

    Seit PHP 5.4 können Sie dies sogar in einem Merkmal tun:

    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();
    
Arnaud Le Blanc
quelle
Schön, obwohl es schön wäre, __invoke/()gegen call_user_funcNotizen zu sehen .
1
Sie können Eigenschaften für fast alles verwenden, es ist keine Klasse, nur eine lose Packung von Methoden und Requisiten
Thielicious
2

Sie können Ihre Lambda-Funktion auch mit ReflectionFunction aufrufen, ohne etwas in Ihrer Klasse zu ändern.

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

oder wenn Sie dann Argumente übergeben müssen

$args = array('arg'=>'value');
$lambda->invokeArgs($args);
akDeveloper
quelle
1
Dies ist weder die kürzeste noch die effizienteste Vorgehensweise.
Amphetamachine