2017-07-02 3 views
2

je crée une classe qui utilise un générateur pour renvoyer des valeurs lorsqu'une méthode particulière est appelée, quelque chose comme:générateur ne peut pas être dans une fermeture

class test { 
    protected $generator; 

    private function getValueGenerator() { 
     yield from [1,1,2,3,5,8,13,21]; 
    } 

    public function __construct() { 
     $this->generator = $this->getValueGenerator(); 
    } 

    public function getValue() { 
     while($this->generator->valid()) { 
      $latitude = $this->generator->current(); 
      $this->generator->next(); 
      return $latitude; 
     } 
     throw new RangeException('End of line'); 
    } 
} 

$line = new test(); 

try { 
    for($i = 0; $i < 10; ++$i) { 
     echo $line->getValue(); 
     echo PHP_EOL; 
    } 
} catch (Exception $e) { 
    echo $e->getMessage(); 
} 

Ce qui fonctionne parfaitement bien quand le générateur est défini comme méthode dans la classe elle-même .... mais je veux le rendre plus dynamique et utiliser une fermeture comme le générateur, quelque chose comme:

class test { 
    public function __construct() { 
     $this->generator = function() { 
      yield from [1,1,2,3,5,8,13,21]; 
     }; 
    } 
} 

Malheureusement, lorsque je tente de lancer cela, je reçois

Fatal error: Uncaught Error: Call to undefined method Closure::valid()

dans l'appel à getValue()

Quelqu'un peut-il expliquer la logique réelle des raisons pour lesquelles je ne peux pas appeler le générateur de cette façon? Et comment pourrais-je utiliser une fermeture plutôt qu'une fonction de générateur codée en dur?

+1

Vous initialisez le champ à une fermeture, mais vous voulez le résultat de l'appel de la fermeture. – localheinz

Répondre

5

Dans le premier exemple, vous invoquez la méthode, la création du générateur:

$this->generator = $this->getValueGenerator(); 

Dans le second, vous ne pas invoquer, il est donc simplement une fermeture:

$this->generator = function() { 
    yield from [1,1,2,3,5,8,13,21]; 
}; 

Invoquer que la fermeture devrait créer le générateur (PHP 7 si vous ne voulez pas affecter une variable intermédiaire):

$this->generator = (function() { 
    yield from [1,1,2,3,5,8,13,21]; 
})(); 
+0

Bingo! Bien que l'approche PHP7 ne semble pas fonctionner (même avec des accolades supplémentaires {}}, l'utilisation d'une variable intermédiaire pour que la fermeture soit invocable fonctionne. Merci! –

+0

Ah! gt les parenthèses fonctionnent maintenant –

+0

J'ai modifié la réponse pour obtenir les accolades correctes –