2012-09-26 38 views
8

PHP 5.4.5, aquí. Intento invocar un objeto que está almacenado como miembro de otro objeto. Como esto (muy aproximadamente)Cómo llamar al método __invoke de una variable miembro dentro de una clase

class A { 
    function __invoke() { ... } 
} 

class B { 
    private a = new A(); 
... 
    $this->a(); <-- runtime error here 
} 

Esto produce un error de ejecución, por supuesto, porque no hay un método llamado. Pero si escribo la llamada de esta manera:

($this->a)(); 

me aparece un error de sintaxis.

Por supuesto, puedo escribir

$this->a->__invoke(); 

pero que parece intolerablemente feo, y más bien socava el punto de funtores. Me preguntaba si hay una forma mejor (u oficial).

Respuesta

8

Hay tres maneras:

llamando directamente __invoke, que ya se ha mencionado:

$this->a->__invoke(); 

Al asignar a una variable:

$a = $this->a; 
$a(); 

Mediante el uso de call_user_func:

call_user_func($this->a); 

El último es probablemente lo que estás buscando. Tiene la ventaja de que funciona con cualquier llamante.

+1

Gracias Igor. De los tres, la asignación a la variable parece ser la más clara, pero ninguno de ellos es muy bueno. ¿Alguien entiende por qué la sintaxis "obvia" $ this-> a() no puede encontrar el método __invoke del miembro? ¿Por qué el acceso de los miembros es fundamentalmente diferente a la sintaxis de variable desnuda? –

+1

Porque es ambiguo. '$ this-> a()' podría ser el método 'a' o el miembro' $ a'. En PHP, esos dos están separados bastante fuertemente (a diferencia de JS, por ejemplo). – igorw

+0

Ah. Eso tiene sentido. Gracias. –

3

Sé que esto es una respuesta tardía, pero el uso de una combinación de __call() en la matriz y __invoke() de la subclase:

class A { 
    function __invoke ($msg) { 
    print $msg; 
    } 
} 

class B { 
    private $a; 

    public function __construct() { $this->a = new A(); } 

    function __call($name, $args) 
    { 
     if (property_exists($this, $name)) 
     { 
     $prop = $this->$name; 
     if (is_callable($prop)) 
     { 
      return call_user_func_array($prop, $args); 
     } 
     } 
    } 
} 

, entonces debería ser capaz de lograr el azúcar sintáctico está buscando:

$b = new B(); 
$b->a("Hello World\n"); 
+0

Ese es un enfoque bastante ordenado. Gracias. –

2

FYI en PHP 7+ paréntesis alrededor de una devolución de llamada dentro de un objeto funciona ahora:

class foo {                  
    public function __construct() {            
     $this -> bar = function() {            
      echo "bar!" . PHP_EOL;            
     };                  
    }                   

    public function __invoke() {             
     echo "invoke!" . PHP_EOL;            
    }                   
}                    

(new foo)();                  

$f = new foo;                 
($f -> bar)(); 

Resultado:

invoke! 
bar! 
Cuestiones relacionadas