2010-10-14 2 views
3

J'ai une classe Validator qui crée une instance d'une classe Validations, qui contient toutes les méthodes de validation. Lorsqu'une validation est effectuée, __call dans Validator est utilisé pour envoyer un appel Validator->validate_method à Validations->method. Par exemple, il existe une méthode dans Validations appelée length_of. Lorsque le code suivant est exécuté:Est-il mauvais d'utiliser Reflection dans le code de production?

$v = new Validator(); 
$v->validate_length_of(...); 

la validation length_of dans la classe Validations est exécutée.

Afin de faire en sorte que __call ne cherche pas à être envoyé à une méthode Validation invalide ou non publique, j'utilise ReflectionMethod pour vérifier la méthode spécifiée:

$method = new ReflectionMethod($this->validations, $validation_method); 
if (!$method->isPublic()) 
{ 
    // error 
} 

Je suis sûr que ce soit la seul moyen de déterminer si une méthode est publique ou non, mais je ne suis pas sûr que Reflection est approprié pour avoir dans le code de production. Est-ce une odeur de code?

+0

Les modificateurs de visibilité sont ce qui sent ici. Supprimez simplement "private" et utilisez "method_exists". – user187291

+0

@stereofrog Je n'essaie pas d'accéder à une méthode privée. J'essaie de * ne * pas autoriser l'accès aux méthodes privées. –

Répondre

5

Vous ne devriez vraiment pas utiliser Reflection dans le code de production. Pourquoi n'utilisez-vous pas is_callable ici?

if (!is_callable(array('Validations', $validation_method)) { 
    throw new LogicException('method does not exist'); 
} 

Cette vérifie que la classe Validations a une méthode statique $validation_method et assure que vous pouvez l'appeler du contexte actuel. En fait, cela vous donne encore plus de flexibilité que de réflexion, car cela prend en compte les méthodes et les choses similaires que Reflection ne prend pas en compte.

+0

Désolé, je n'étais pas clair dans ma question, les méthodes dans 'Validations' ne sont pas des méthodes statiques. –

+0

Dans ce cas, au lieu de ''Validations' ', utilisez' new Validations' (ou une instance existante de 'Validations') comme premier élément dans le tableau;) – NikiC

+0

@nikic: J'ai fait, voir http: //www.ideone. com/fnpoQ –

1

Si vous avez besoin de la puissance de l'API Reflection dans votre code, utilisez-la. Mais la réflexion peut être lente et une référence ne peut jamais faire de mal quand vous l'utilisez. En fin de compte seulement vous pouvez décider si cela a trop d'impact sur votre application. Il s'agit encore de microsecondes dont nous parlons. Cependant, pour votre cas spécifique, je ne vois pas pourquoi vous utiliseriez Reflection du tout. Il suffit d'utiliser une interface et de faire des validations dans des classes séparées implémentant cette interface. Voir mon example Validation class. Si vous voulez utiliser __call avec cela (les méthodes magiques sont trop lentes aussi), vous pouvez utiliser class_implements pour vérifier si le validateur implémente l'interface et ensuite vous êtes sûr que la méthode de validation existe, par ex. dans la classe principale Validator ajouter

public function __call($method, $args) 
{ 
    if (class_exists($method)) { 
     $validator = new $method; 
     if($validator instanceof IValidate) { 
      return call_user_func(array($validator, 'validate'), $args); 
     } 
     throw new BadMethodCallException('Class exists but is not a Validator'); 
    } 
    throw new RuntimeException('Method does not exist'); 
} 

Sur un Sidenote: the Zend Framework already has an extensive number of Validators you can build on. Puisque ZF est une bibliothèque de composants, vous pouvez les utiliser sans avoir à migrer l'ensemble de votre application vers ZF. PEAR a aussi un Validation package.

0

À mon humble avis, je m'éloignerais de l'utilisation de la réflexion dans le code de production. Au lieu d'essayer d'appeler validate_ quelque chose je voudrais créer une interface qui a la méthode de validation requise. Ensuite, pour chaque classe de valiadtor, vous appelez simplement $ valid-> validate(). Il serait plus facile pour l'interpréteur de mettre en cache ce code.

+1

"Je voudrais m'éloigner" - possible la plus grande faute de frappe du monde. –

Questions connexes