2015-07-12 1 views
3

J'utilise la classe suivante pour imiter des objets anonymes en PHP:

class AnonymousObject 
{ 
    protected $methods = array(); 

    public function __construct(array $options) { 
     $this->methods = $options; 
    } 

    public function __call($name, $arguments) { 
     $callable = null; 
     if (array_key_exists($name, $this->methods)) 
      $callable = $this->methods[$name]; 
     elseif(isset($this->$name)) 
      $callable = $this->$name; 

     if (!is_callable($callable)) 
      throw new BadMethodCallException("Method {$name} does not exist"); 

     return call_user_func_array($callable, $arguments); 
    } 
} 

(https://gist.github.com/Mihailoff/3700483)

Maintenant, tant que les fonctions déclarées se distinguent par leurs propres moyens tout fonctionne bien, mais chaque fois que je tente d'appeler une fonction de l'autre comme ça ...

$anonymous = new AnonymousObject(array(
    "foo" => function() { $this->bar(); }, 
    "bar" => function() { } 
)); 

alors bien sûr je reçois Fatal error: Using $this when not in object context

Y at-il un moyen de contourner ce problème?

+2

Mise à niveau vers PHP7 et vous obtiendrez de véritables classes anonymes: -D – ircmaxell

Répondre

5

Vous pouvez utiliser bind() ou bindTo() method de l'instance de fermeture qui représente la fonction anonyme.

<?php 
class AnonymousObject 
{ 
    protected $methods = array(); 

    public function __construct(array $options) { 
     $this->methods = $options; 
    } 

    public function __call($name, $arguments) { 
     $callable = null; 
     if (array_key_exists($name, $this->methods)) 
      $callable = $this->methods[$name]; 
     elseif(isset($this->$name)) 
      $callable = $this->$name; 

     if (!is_callable($callable)) 
      throw new BadMethodCallException("Method {$name} does not exists"); 

     $callable = $callable->bindTo($this); 
     return call_user_func_array($callable, $arguments); 
    } 
} 

$anonymous = new AnonymousObject(array(
    "foo" => function() { echo 'foo'; $this->bar(); }, 
    "bar" => function() { echo 'bar'; } 
)); 

$anonymous->foo(); 

(exemple pas tout à fait raison, car elle ne fonctionne qu'avec des fonctions anonymes, non pas avec toutes les autres alternatives appelables() comme par exemple la partie de nom $ this->)

imprime foobar.

+0

Excellent, problème résolu. Je vous remercie! – subarachnid

+0

Y aurait-il un avantage à boucler les options dans le constructeur et à lier à ce point plutôt que dans le __call()? –

+0

Probablement oui. J'ai choisi la voie sûre puisque la référence de la fonction pourrait être disponible en dehors de la définition de la classe et à partir de là liée à un autre objet. – VolkerK