PHP 5.3 Méthode magique __invoke
Cette rubrique s'étend sur Quand dois/devrais-je utiliser le __construct(), __get(), __set () et __call() en PHP? qui parle de la __construct
__get
et __set
méthodes magiques.
Depuis PHP 5.3, il est une nouvelle Méthode Magique appelé __invoke
. Le __invoke
méthode est appelée lorsqu'un script tente d'appeler un objet comme une fonction.
Maintenant que j'ai fait pour cette méthode, les gens l'assimilent à la méthode Java .run()
- voir L'Interface Runnable.
Avoir pensé à long et dur sur ce que je ne peux pas penser à une raison pourquoi vous appelez $obj();
par opposition à $obj->function();
Même si vous étiez une itération sur un tableau d'objets, vous le savez, le principal nom de la fonction que vous souhaitez exécuter.
Est donc le __invoke
méthode magique un autre exemple de "juste parce que vous pouvez, ne signifie pas que vous devez" raccourci en PHP, ou il y a des cas où ce serait effectivement la bonne chose à faire?
source d'informationauteur Phil Carter
Vous devez vous connecter pour publier un commentaire.
PHP ne permet pas le passage de pointeurs de fonction comme les autres langues. Les fonctions ne sont pas première classe en PHP. Les fonctions de première classe, principalement signifie que vous pouvez enregistrer une fonction à une variable, et de les passer et de l'exécuter à tout moment.
La
__invoke
méthode est une façon que PHP peut accueillir de pseudo-premier de la classe de fonctions.La
__invoke
méthode peut être utilisée pour transmettre une classe qui peut agir comme un fermeture ou un continuationou tout simplement comme une fonction que vous pouvez passer.Beaucoup de la programmation fonctionnelle s'appuie sur la première classe de fonctions. Même normal de programmation impératif pouvez profiter de cette situation.
Dire que vous avez une sorte de routine, mais je voulais pour prendre en charge différentes fonctions de comparaison. Eh bien, vous pouvez avoir différentes de comparer les classes qui implémentent l' __invoquer la fonction et le passer dans les instances de la classe à votre fonction de tri, et il n'a même pas connaître le nom de la fonction.
Vraiment, vous pouvez toujours faire quelque chose comme passage d'une classe et d'avoir un appel de fonction, une méthode, mais vous pouvez maintenant presque parler de passage d'une "fonction" au lieu de passer d'une classe, même si elle n'est pas aussi propre que dans d'autres langues.
L'utilisation de
__invoke
de sens que si vous avez besoin d'un callable qui doit conserver une certaine état interne. Disons que vous voulez trier le tableau suivant:La usort fonction permet de trier un tableau en utilisant une fonction très simple. Toutefois, dans ce cas, nous voulons trier le tableau à l'aide de ses propres tableaux
'value'
clés, ce qui pourrait être fait de cette façon:Maintenant peut-être vous avez besoin de trier le tableau de nouveau, mais cette fois en utilisant
'key'
comme cible clé, il serait nécessaire de réécrire la fonction:Comme vous pouvez le voir, la logique de la fonction est identique à la précédente, cependant nous ne pouvons pas réutiliser la précédente en raison de la nécessité de trier avec une clé différente. Ce problème peut être résolu avec une classe qui encapsule la logique de comparaison dans la
__invoke
méthode et qui définissent la clé pour être utilisé dans son constructeur:Un objet de Classe qui implémente
__invoke
c'est un "callable", il peut être utilisé dans n'importe quel contexte qu'une fonction peut être, alors maintenant, il suffit d'instancierComparator
objets et de les transmettre à l'usort
fonction:Les paragraphes suivants reflètent mon opinion subjective, donc, si vous voulez, vous pouvez arrêter la lecture de la réponse maintenant 😉: Bien que l'exemple précédent a montré une utilisation très intéressante de
__invoke
de tels cas sont rares et je voudrais l'éviter car il peut être vraiment déroutant moyens et en général, il est plus simple de mise en œuvre de solutions de rechange. Un exemple d'une alternative dans le même problème de tri serait l'utilisation d'une fonction qui retourne une fonction de comparaison:Bien que cet exemple nécessite un peu plus d'intimité avec les lambdas | fermetures | fonctions anonymes c'est beaucoup plus concis, car il ne crée pas d'ensemble de la structure de classe juste pour stocker une valeur externe.
Je crois que cette fonctionnalité existe principalement pour soutenir 5.3 la nouvelle de la fermeture de la fonctionnalité. Les fermetures sont exposés comme des instances de la
Closure
classe, et sont directement invokable par exemple$foo = $someClosure();
. Un avantage pratique de__invoke()
est qu'il devient possible de créer un standard type de rappel, plutôt que d'utiliser des combinaisons étranges, des chaînes, des objets et des tableaux selon que vous faites référence à une fonction, une méthode d'instance ou une méthode statique.C'est une combinaison de deux choses l'une. Vous avez correctement identifié l'un d'entre eux déjà. C'est en effet tout comme Java
IRunnable
interface, où chaque "praticable" objet implémente la même méthode. En Java, la méthode est nomméerun
; en PHP, la méthode est nommée__invoke
et vous n'avez pas besoin d'implémenter explicitement tout particulier type d'interface à l'avance.Le deuxième aspect est le sucre syntaxiquedonc au lieu d'appeler
$obj->__invoke()
vous pouvez ignorer le nom de la méthode, il semble comme si vous êtes à l'appel de l'objet directement:$obj()
.La partie clé pour PHP pour avoir des fermetures est le premier. La langue a besoin de quelque méthode établie pour appeler à une fermeture de l'objet pour en faire sa chose. Le sucre syntaxique est juste un moyen de le rendre moins moche, comme c'est le cas avec tous les "spéciaux", des fonctions avec un double trait de soulignement préfixes.
Vraiment vous ne devez pas appeler
$obj();
par opposition à$obj->function();
si vous savez que vous avez affaire avec un certain type d'objet. Cela dit, sauf si vous voulez que vos collègues scratch de leurs têtes.La
__invoke
méthode vient à la vie dans des situations différentes. Surtout quand vous êtes tenu de fournir un générique appelable comme un argument.Imaginez que vous avez une méthode dans une classe (que vous devez utiliser et qui ne peuvent pas changer) qui ne prend qu'un "callable" comme argument.
Maintenant, imaginez que vous souhaitez mettre en cache et réutiliser le résultat d'une opération longue, ou de l'accès précédemment utilisé des arguments de la fonction. Régulièrement des fermetures qui peut être chunky.
Voir, si vous avez besoin d'accéder à la
$argList
de quelque part d'autre, ou tout simplement de nettoyer le cache de l'impasse des entrées, vous êtes en difficulté!Voici
__invoke
à la rescousse:Avec la classe au-dessus de travail avec la mise en cache de données devient un jeu d'enfant.
C'est juste un exemple simple pour illustrer le concept. On peut même aller plus loin et de créer un wrapper générique et la mise en cache de la classe. Et bien plus encore.
Finales (sur la base de tous les ci-dessus)
Généralement je vois __invoke(){...} la méthode magique comme une grande opportunité pour l'abstraction l'utilisation de la classe de l'objet principal de la fonctionnalité ou pour une utilisation intuitive de l'objet de l'installation (la préparation de l'objet avant de l'utiliser de méthodes).
Cas 1 - la Par exemple permet de dire que j'utilise de la troisième partie de l'objet qui implémente __invoquer la magie de méthode en fournissant de cette façon, un accès facile aux principales fonctionnalités de l'instance d'un objet. Pour l'utiliser caractéristique principale que j'ai seulement besoin de savoir quels sont les paramètres __invoquer la méthode attend et ce que serait le résultat final de cette fonction (la fermeture). De cette façon, je suis en mesure d'utiliser la classe de l'objet principal de fonctionnalités avec peu d'efforts pour investygate l'objet capacités (notez que dans cet exemple nous n'avons pas besoin de connaître ou d'utiliser tout nom de la méthode).
Abstraire du réel code...
au lieu de
que nous utilisons aujourd'hui:
Nous pouvons maintenant passer un objet à d'autres fonctions qui attend de ses paramètres pouvant être appelée comme une fonction ordinaire:
au lieu de
que nous utilisons aujourd'hui:
__invoquer fournit une belle utilisation du raccourci alors pourquoi ne pas l'utiliser ?