Vous pouvez utiliser __call. Mais veuillez ne pas utiliser __call. La modification dynamique du comportement d'un objet est un moyen très simple de rendre votre code illisible et non maintenable.
Très, très intelligent mais kludgy dans un projet du monde réel IMO! (et +1 pour contrer le downvoter anonyme)
Pekka
2
@pekka - mais comment, exactement, est-ce kludgy? Bien sûr, je ne dis pas que je suis un expert dans l'extension d'un objet pendant l'exécution en PHP, mais honnêtement, je ne peux pas dire que je vois beaucoup de mal. (peut-être que j'ai juste un mauvais goût)
karim79
16
J'ajouterais une vérification is_callable dans ce cas également (donc vous n'essayez pas accidentellement d'appeler une chaîne). Et lancez également une BadMethodCallException () si vous ne trouvez pas de méthode, donc vous ne l'avez pas renvoyée et pensez qu'elle a réussi. De plus, faites du premier paramètre de la fonction l'objet lui-même, puis faites un array_unshift($args, $this);avant l'appel de la méthode, afin que la fonction obtienne une référence à l'objet sans avoir explicitement besoin de le lier ...
ircmaxell
3
Je pense que les gens manquent le point, l'exigence initiale était d'utiliser un objet sans classe.
thomas-peter
1
Je suggérerais en fait que vous supprimiez complètement le test isset () car si cette fonction n'est pas définie, vous ne voudrez probablement pas revenir en silence.
Alexis Wilke
50
Avec PHP 7, vous pouvez utiliser des classes anonymes
Utiliser simplement __call pour permettre l'ajout de nouvelles méthodes lors de l'exécution présente l'inconvénient majeur que ces méthodes ne peuvent pas utiliser la référence d'instance $ this. Tout fonctionne très bien, jusqu'à ce que les méthodes ajoutées n'utilisent pas $ this dans le code.
Mise à jour: L'approche présentée ici présente un inconvénient majeur: la nouvelle fonction n'est pas un membre pleinement qualifié de la classe; $thisn'est pas présent dans la méthode lorsqu'elle est appelée de cette manière. Cela signifie que vous devrez passer l'objet à la fonction en tant que paramètre si vous souhaitez travailler avec des données ou des fonctions de l'instance d'objet! En outre, vous ne serez pas en mesure d'accéder privateou les protectedmembres de la classe de ces fonctions.
Bonne question et idée intelligente utilisant les nouvelles fonctions anonymes!
Fait intéressant, cela fonctionne: Remplacer
$me->doSomething();// Doesn't work
par call_user_func sur la fonction elle - même :
call_user_func($me->doSomething);// Works!
ce qui ne fonctionne pas est la "bonne" façon:
call_user_func(array($me,"doSomething"));// Doesn't work
s'il est appelé de cette façon, PHP requiert que la méthode soit déclarée dans la définition de classe.
Est-ce un problème de visibilité private/ public/ protected?
Mise à jour: non . Il est impossible d'appeler la fonction de la manière normale même à partir de la classe, ce n'est donc pas un problème de visibilité. Passer la fonction réelle à call_user_func()est la seule façon dont je peux sembler faire ce travail.
Pour voir comment faire cela avec eval, vous pouvez jeter un œil à mon micro-framework PHP, Halcyon, qui est disponible sur github . Il est suffisamment petit pour que vous puissiez le comprendre sans aucun problème - concentrez-vous sur la classe HalcyonClassMunger.
Je suppose (tout comme mon code) que vous utilisez PHP <5.3.0 et que vous avez donc besoin de kludges et de hacks pour que cela fonctionne.
ivans
Demander si quelqu'un aimerait commenter le
vote défavorable
C'est probablement le cas, il y a un vote à la baisse de masse ici. Mais peut-être voulez-vous développer un peu ce que vous avez fait? Comme vous pouvez le voir, c'est une question intéressante sans réponse définitive.
Pekka
1
Sans la __callsolution, vous pouvez utiliser bindTo(PHP> = 5.4), pour appeler la méthode avec $thislié pour $meaimer ceci:
$me =new stdClass;// Property for proving that the method has access to the above object:
$me->message ="I\'ve done something";
$me->doSomething =function(){
echo $this->message;};
call_user_func($me->doSomething->bindTo($me));// "I've done something"
Vous pouvez également affecter la fonction liée à une variable, puis l'appeler sans call_user_func:
Il existe un article similaire sur stackoverflow qui indique que cela n'est réalisable que par la mise en œuvre de certains modèles de conception.
Le seul autre moyen est d'utiliser classkit , une extension php expérimentale. (également dans le post)
Oui, il est possible d'ajouter une méthode à une classe PHP après sa définition. Vous souhaitez utiliser classkit, qui est une extension "expérimentale". Il semble que cette extension ne soit pas activée par défaut cependant, cela dépend donc de la possibilité de compiler un binaire PHP personnalisé ou de charger des DLL PHP sous Windows (par exemple, Dreamhost autorise les binaires PHP personnalisés, et ils sont assez faciles à configurer ).
La réponse karim79 fonctionne mais elle stocke les fonctions anonymes dans les propriétés de la méthode et ses déclarations peuvent écraser les propriétés existantes du même nom ou ne fonctionne pas si la propriété existante privateprovoque une erreur fatale objet inutilisable Je pense que les stocker dans un tableau séparé et utiliser setter est une solution plus propre. Le setter d'injecteur de méthode peut être ajouté automatiquement à chaque objet en utilisant des traits .
PS Bien sûr, c'est un hack qui ne doit pas être utilisé car il viole le principe ouvert fermé de SOLID.
classMyClass{//create array to store all injected methodsprivate $anon_methods = array();//create setter to fill array with injected methods on runtimepublicfunction inject_method($name, $method){
$this->anon_methods[$name]= $method;}//runs when calling non existent or private methods from object instancepublicfunction __call($name, $args){if( key_exists($name, $this->anon_methods)){
call_user_func_array($this->anon_methods[$name], $args);}}}
$MyClass =newMyClass;//method one
$print_txt =function($text){
echo $text . PHP_EOL;};
$MyClass->inject_method("print_txt", $print_txt);//method
$add_numbers =function($n, $e){
echo "$n + $e = ".($n + $e);};
$MyClass->inject_method("add_numbers", $add_numbers);//Use injected methods
$MyClass->print_txt("Hello World");
$MyClass->add_numbers(5,10);
Réponses:
Vous pouvez exploiter
__call
pour cela:la source
array_unshift($args, $this);
avant l'appel de la méthode, afin que la fonction obtienne une référence à l'objet sans avoir explicitement besoin de le lier ...Avec PHP 7, vous pouvez utiliser des classes anonymes
PHP RFC: Classes anonymes
la source
Utiliser simplement __call pour permettre l'ajout de nouvelles méthodes lors de l'exécution présente l'inconvénient majeur que ces méthodes ne peuvent pas utiliser la référence d'instance $ this. Tout fonctionne très bien, jusqu'à ce que les méthodes ajoutées n'utilisent pas $ this dans le code.
Afin de résoudre ce problème, vous pouvez réécrire le motif de cette manière
De cette façon, vous pouvez ajouter de nouvelles méthodes qui peuvent utiliser la référence d'instance
la source
Bonne question et idée intelligente utilisant les nouvelles fonctions anonymes!
Fait intéressant, cela fonctionne: Remplacer
par call_user_func sur la fonction elle - même :
ce qui ne fonctionne pas est la "bonne" façon:
s'il est appelé de cette façon, PHP requiert que la méthode soit déclarée dans la définition de classe.
Est-ce un problème de visibilité
private
/public
/protected
?Mise à jour: non . Il est impossible d'appeler la fonction de la manière normale même à partir de la classe, ce n'est donc pas un problème de visibilité. Passer la fonction réelle à
call_user_func()
est la seule façon dont je peux sembler faire ce travail.la source
vous pouvez également enregistrer des fonctions dans un tableau:
la source
Pour voir comment faire cela avec eval, vous pouvez jeter un œil à mon micro-framework PHP, Halcyon, qui est disponible sur github . Il est suffisamment petit pour que vous puissiez le comprendre sans aucun problème - concentrez-vous sur la classe HalcyonClassMunger.
la source
Sans la
__call
solution, vous pouvez utiliserbindTo
(PHP> = 5.4), pour appeler la méthode avec$this
lié pour$me
aimer ceci:Le script complet pourrait ressembler à ceci:
Vous pouvez également affecter la fonction liée à une variable, puis l'appeler sans
call_user_func
:la source
Il existe un article similaire sur stackoverflow qui indique que cela n'est réalisable que par la mise en œuvre de certains modèles de conception.
Le seul autre moyen est d'utiliser classkit , une extension php expérimentale. (également dans le post)
la source
La réponse karim79 fonctionne mais elle stocke les fonctions anonymes dans les propriétés de la méthode et ses déclarations peuvent écraser les propriétés existantes du même nom ou ne fonctionne pas si la propriété existante
private
provoque une erreur fatale objet inutilisable Je pense que les stocker dans un tableau séparé et utiliser setter est une solution plus propre. Le setter d'injecteur de méthode peut être ajouté automatiquement à chaque objet en utilisant des traits .PS Bien sûr, c'est un hack qui ne doit pas être utilisé car il viole le principe ouvert fermé de SOLID.
la source