2009-07-01 14 views
0

Je me suis toujours soucié d'appeler des méthodes en les référençant par des chaînes.Les méthodes de référencement et d'appel par chaînes en PHP sont-elles une mauvaise idée?

Fondamentalement, dans mon scénario actuel, j'utilise des méthodes de mappeur de données statiques pour créer et renvoyer un tableau d'objets de modèle de données (par exemple, SomeDataMapper :: getAll (1234)). Les modèles suivent le modèle de conception Active Record. Dans certains cas, des centaines d'enregistrements peuvent être renvoyés et je ne veux pas tout mettre en mémoire en même temps. Alors, je me sers un itérateur pour passer en revue les dossiers, comme suit

$Iterator = new DataMapperIterator('SomeDataMapper', 'getAll', array(1234)); 

while ($Iterator->hasNext()) { 
    $data = $Iterator->next(); 
} 

Est-ce une bonne façon de le faire? Est-ce une mauvaise idée de transmettre en tant que chaînes le nom de la classe de mappeur et la méthode? Je m'inquiète que cette idée ne soit pas portable dans d'autres langues. Est-ce généralement le cas pour des langages comme Ruby et Python? Si oui, quelqu'un peut-il recommander une bonne alternative?

Pour votre information, pour le refernce de futurs peuples, j'appelle la méthode comme ceci:

$method = new ReflectionMethod($className, $methodName); 
$returnValue = $method->invokeArgs(null, $parameters); 

Répondre

1

Il est un moyen acceptable de le faire. Les deux Python et Ruby le supportent et devraient donc être portables. Python peut le faire aussi facilement que PHP, mais Ruby en a un peu plus. En Python au moins, il est utile lorsque la classe particulière que vous référencez n'a pas encore été importée ni vue dans le fichier (c'est-à-dire que la classe est plus basse dans le même fichier que lorsque vous essayez de la référencer).

Obtenir un objet de classe d'une chaîne en Ruby: http://infovore.org/archives/2006/08/02/getting-a-class-object-in-ruby-from-a-string-containing-that-classes-name/

+0

Bon à savoir. Merci! –

1

PHP ne supporte pas vraiment le passage des fonctions d'une autre manière. Toutes les fonctions d'appel de méthode dynamique en PHP prennent ce qu'elles appellent un "callback" - voir http://us.php.net/manual/en/language.pseudo-types.php#language.types.callback pour la documentation à ce sujet. Comme vous le verrez, ce ne sont que des chaînes ou des tableaux de chaînes dans différents modèles d'utilisation, vous n'êtes donc pas loin.

Il existe cependant des modèles de conception qui fonctionnent autour de cela. Par exemple, vous pouvez définir une interface DataMapper que toutes vos classes de mappeur doivent implémenter. Ensuite, au lieu de passer la classe et la méthode sous forme de chaîne, vous pouvez passer l'instance de mappeur à votre itérateur et, comme elle nécessite l'interface, elle peut appeler directement les méthodes d'interface.

pseudocode:

interface DataMapper 
{ 
    public function mapData($data); 
} 

class DataMapperIterator ... 
{ 
    public function __construct(DataMapper $mapper, ...) 
    { 
    ... 
    } 
    ... 
    public function next() 
    { 
    ... now we can call the method explicitly because of interface ... 
    $this->mapper->mapData($data); 
    } 
} 

class DataMapperImplemenation implements DataMapper 
{ 
    ... 
    public function mapData($data) 
    { 
    ... 
    } 
... 
} 

Appel de méthodes par nom avec passé dans les chaînes n'est pas horrible, il n'y a probablement qu'une pénalité de performance en ce que le bytecode généré ne peut être aussi optimisé - il y aura toujours un symbole recherche - mais je doute que vous remarquerez cela.

+0

Bon point, et j'aimerais le faire, mais les méthodes de mon mappeur sont statiques. En outre, j'ai différentes méthodes de mappeur pour différents types d'ensembles de résultats ... comme :: getById(), getByGroupId(), etc. –

3

Il s'agit essentiellement d'une version du modèle d'usine - Utilisation de chaînes pour créer une instance d'objet.

Cependant, je remets en question l'idée de conception d'utiliser un itérateur pour contrôler la pagination des données - ce n'est pas vraiment le but d'un itérateur. À moins d'avoir une confusion de noms, mais je préférerais probablement voir quelque chose comme ça.

$pager = new DataMapperPager('SomeDataMapper', 'someMethod', array(1234)); 
$pager->setPageNum(1); 
$pager->setPageSize(10); 
$rows = $pager->getResults(); 

foreach ($rows as $row) 
{ 
    // whatever 
} 

Bien sûr, DataMapperPager :: getResults() peut retourner un itérateur ou tout ce que vous voudriez.

+0

Bonne capture.Je pense que je vais renommer cela en * Pager et ensuite le faire retourner un Iterator comme vous l'avez suggéré. –

+0

J'ai fini par implémenter l'interface Iterator de PHP pour pouvoir utiliser cette classe avec foreach. –