J'ai créé un plugin, et bien sûr, étant moi-même, je voulais utiliser une approche OO agréable. Maintenant, ce que j'ai fait est de créer cette classe puis juste en dessous de créer une instance de cette classe:
class ClassName {
public function __construct(){
}
}
$class_instance = new ClassName();
Je suppose qu'il y a plus de moyens de faire en sorte que cette classe soit initiée par un groupe de travail, puis j'ai rencontré des personnes disant qu'elles préféraient une init()
fonction à une __construct()
autre. Et de même, j'ai trouvé quelques personnes utilisant le crochet suivant:
class ClassName {
public function init(){
}
}
add_action( 'load-plugins.php', array( 'ClassName', 'init' ) );
Qu'est-ce qui est généralement considéré comme le meilleur moyen de créer une instance de classe WP lors du chargement et de la considérer comme une variable accessible de manière globale?
NOTE: En tant que point intéressant, j'ai remarqué que, même s'il register_activation_hook()
peut être appelé de l'intérieur __construct
, il ne peut pas être appelé de l'intérieur init()
du deuxième exemple. Peut-être que quelqu'un pourrait m'éclairer sur ce point.
Edit: Merci pour toutes les réponses, il y a clairement pas mal de débats sur la manière de gérer l'initialisation au sein de la classe elle-même, mais je pense qu'il y a généralement un très bon consensus qui add_action( 'plugins_loaded', ...);
est le meilleur moyen de commencer réellement ...
Edit: Juste pour confondre les choses, j’ai aussi vu cela utilisé (bien que je n’utiliserais pas cette méthode moi-même, car transformer une classe OO en fonction semble contrecarrer son objectif):
// Start up this plugin
add_action( 'init', 'ClassName' );
function ClassName() {
global $class_name;
$class_name = new ClassName();
}
Réponses:
Bonne question, il existe un certain nombre d'approches et cela dépend de ce que vous voulez réaliser.
Je fais souvent;
Un exemple plus complet, approfondi, résultant de discussions récentes sur ce sujet dans la salle de discussion, peut être vu ici par le membre du WPSE, toscho .
L'approche constructeur vide.
Voici un extrait des avantages / inconvénients tirés de l’essentiel ci-dessus, qui illustre parfaitement l’approche constructeur vide.
À mon avis, l’inconvénient est faible, c’est pourquoi il faudrait que ce soit mon approche privilégiée, même si ce n’est pas la seule que j’utilise. En fait, plusieurs autres poids lourds vont sans aucun doute entrer dans le vif du sujet, car ils le feront sous peu car il y a de bonnes opinions sur ce sujet qui méritent d'être exprimées.
Remarque: je dois trouver l’essentiel de l’exemple de toscho qui a comparé 3 ou 4 comparaisons sur la façon d’instancier une classe dans un plugin qui examine les avantages et les inconvénients de chaque classe. les autres exemples contrastent bien avec ce sujet. Espérons que toscho l’a toujours dans son dossier.Remarque: La réponse WPSE à ce sujet avec des exemples et des comparaisons pertinents. Aussi la meilleure solution par exemple une classe dans WordPress.
la source
update.php
fichier core et ne fait pas partie des actions par défaut habituelles sur lesquelles il convient de s'appuyer lorsqu'il est question de la séquence d'événements qui se déclenchent lors de l'initialisation. C'est pourquoi je préfère d'utiliser les crochets qui s'appliquent, dans ce casplugins_loaded
. C’est ce que j’appelle souvent un instantané rapide de ce qui se passe lorsque Action Reference . Mon explication n'est pas complète dans son intégralité.register_activation_hook()
vous devez appeler cette fonction avant que l’plugins_loaded
action ne soit déclenchée.En arrivant ici exactement 2 ans après que la question initiale a été posée, il y a quelques points que je voudrais souligner. (Ne me demandez pas de souligner beaucoup de choses , jamais).
Crochet approprié
Pour instancier une classe de plug-in, le hook approprié doit être utilisé. Il n’ya pas de règle générale, car cela dépend de ce que fait la classe.
Utiliser un hook très précoce comme
"plugins_loaded"
souvent n'a pas de sens car un tel hook est déclenché pour les requêtes admin, frontend et AJAX, mais très souvent, un hook plus récent est bien meilleur car il permet d'instancier les classes de plug-in uniquement lorsque cela est nécessaire.Par exemple, une classe qui fait des choses pour les modèles peut être instanciée
"template_redirect"
.De manière générale, il est très rare qu'une classe ait besoin d'être instanciée avant
"wp_loaded"
d'être renvoyée.Aucune classe de Dieu
La plupart des classes utilisées comme exemples dans les réponses plus anciennes utilisent une classe nommée comme
"Prefix_Example_Plugin"
ou"My_Plugin"
... Cela indique qu'il existe probablement une classe principale pour le plugin.Bien, à moins qu'un plugin ne soit créé par une seule classe (auquel cas le nommer après le nom du plugin est absolument raisonnable), pour créer une classe qui gère l'intégralité du plugin (par exemple, ajouter tous les points d'ancrage dont un plugin a besoin ou instancier toutes les autres classes du plugin. ) peut être considéré comme une mauvaise pratique, à titre d'exemple d' objet divin .
Dans le code de programmation orienté objet, le code devrait avoir tendance à être SOLID, le "S" signifiant "Principe de responsabilité unique" .
Cela signifie que chaque classe devrait faire une seule chose. Dans le développement de plugins WordPress, cela signifie que les développeurs devraient éviter d'utiliser un seul hook pour instancier une classe de plugin principale , mais différents hooks doivent être utilisés pour instancier différentes classes, en fonction de la responsabilité de la classe.
Éviter les crochets dans le constructeur
Cet argument a été introduit dans d'autres réponses ici, cependant, je voudrais faire remarquer ce concept et lier cette autre réponse là où il a été assez largement expliqué dans le domaine des tests unitaires.
Presque 2015: PHP 5.2 est pour les zombies
Depuis le 14 août 2014, PHP 5.3 est arrivé en fin de vie . C'est définitivement mort. PHP 5.4 sera supporté pour tout 2015, cela signifie pour une autre année au moment où j'écris.
Cependant, WordPress supporte toujours PHP 5.2, mais personne ne devrait écrire une seule ligne de code prenant en charge cette version, en particulier si le code est OOP.
Il y a différentes raisons:
Si vous ne voulez pas utiliser le code PHP 5.4+, utilisez au moins 5.3+
Exemple
À ce stade, il est temps de passer en revue les réponses précédentes en fonction de ce que j’avais dit jusqu’ici.
Une fois que nous n’avons plus à nous soucier de la version 5.2, nous pouvons et devrions utiliser des espaces de noms.
Afin de mieux expliquer le principe de responsabilité unique, mon exemple utilisera 3 classes, une qui fait quelque chose sur le frontend, une sur le backend et une troisième utilisée dans les deux cas.
Classe Admin:
Classe frontend:
Interface des outils:
Et une classe Tools, utilisée par les deux autres:
Ayant ces classes, je peux les instancier avec les hooks appropriés. Quelque chose comme:
Inversion de dépendance et injection de dépendance
Dans l'exemple ci-dessus, j'ai utilisé des espaces de noms et des fonctions anonymes pour instancier différentes classes à différents hooks, mettant en pratique ce que j'ai dit ci-dessus.
Notez comment les espaces de noms permettent de créer des classes nommées sans préfixe.
J'ai appliqué un autre concept qui a été indirectement mentionné ci-dessus: Injection de dépendance , c'est une méthode pour appliquer le principe d'inversion de dépendance , le "D" dans l'acronyme SOLID.
La
Tools
classe est "injectée" dans les deux autres classes lorsqu'elles sont instanciées, ce qui permet de séparer les responsabilités.De plus,
AdminStuff
et lesFrontStuff
classes utilisent le type hinting de déclarer qu'ils ont besoin d' une classe qui implémenteToolsInterface
.De cette manière, nous ou les utilisateurs de notre code pouvons utiliser différentes implémentations de la même interface, ce qui fait que notre code n'est pas couplé à une classe concrète mais à une abstraction: c'est exactement ce que dit le principe d'inversion de dépendance.
Cependant, l'exemple ci-dessus peut être encore amélioré. Voyons comment.
Autochargeur
Un bon moyen d'écrire du code POO mieux lisible est de ne pas mélanger la définition des types (interfaces, classes) avec un autre code et de mettre chaque type dans son propre fichier.
Cette règle fait également partie des normes de codage PSR-1 1 .
Cependant, avant de pouvoir utiliser une classe, il faut avoir besoin du fichier qui la contient.
Cela peut être accablant, mais PHP fournit des fonctions utilitaires pour charger automatiquement une classe lorsque cela est nécessaire, en utilisant un rappel qui charge un fichier en fonction de son nom.
Utiliser les espaces de noms devient très simple, car il est maintenant possible de faire correspondre la structure des dossiers à la structure des espaces de noms.
C'est non seulement possible, mais c'est aussi un autre standard PSR (ou mieux 2: PSR-0 maintenant obsolète et PSR-4 ).
En respectant ces normes, il est possible d'utiliser différents outils de gestion du chargement automatique, sans avoir à coder un chargeur automatique personnalisé.
Je dois dire que les normes de codage WordPress ont des règles différentes pour nommer les fichiers.
Ainsi, lors de l'écriture de code pour le noyau WordPress, les développeurs doivent suivre les règles WP, mais lors de l'écriture de code personnalisé, c'est un choix pour les développeurs, mais l'utilisation de la norme PSR est plus facile à utiliser avec les outils déjà écrits 2 .
Modèles d'accès global, de registre et de localisateur de services.
L’un des plus gros problèmes lors de l’instanciation des classes de plugins dans WordPress est de savoir comment y accéder depuis différentes parties du code.
WordPress lui-même utilise l' approche globale : les variables sont enregistrées dans une portée globale, ce qui les rend accessibles partout. Chaque développeur WP tape le mot des
global
milliers de fois dans sa carrière.C’est aussi l’approche que j’ai utilisée pour l’exemple ci-dessus, mais c’est un mal .
Cette réponse est déjà beaucoup trop longue pour me permettre d'expliquer davantage pourquoi, mais la lecture des premiers résultats du SERP pour «variables globales mauvaises» constitue un bon point de départ.
Mais comment est-il possible d'éviter les variables globales?
Il y a différentes manières.
Certaines des réponses plus anciennes ici utilisent l' approche d'instance statique .
C'est facile et très bien, mais cela oblige à mettre en œuvre le modèle pour chaque classe à laquelle nous voulons accéder.
De plus, cette approche est souvent mise à mal, car les développeurs rendent accessible une classe principale à l' aide de cette méthode, puis l'utilisent pour accéder à toutes les autres classes.
J'ai déjà expliqué à quel point une classe de dieu est mauvaise. L'approche d'instance statique est donc un bon choix lorsqu'un plugin n'a besoin que de rendre accessible une ou deux classes.
Cela ne signifie pas qu'il ne peut être utilisé que pour des plugins n'ayant que quelques classes. En fait, lorsque le principe d'injection de dépendance est utilisé correctement, il est possible de créer des applications assez complexes sans avoir à rendre globalement accessible un grand nombre d'objets.
Cependant, parfois, les plugins doivent rendre certaines classes accessibles , et dans ce cas, l'approche d'instance statique est écrasante.
Une autre approche possible consiste à utiliser le modèle de registre .
Ceci est une implémentation très simple:
À l'aide de cette classe, il est possible de stocker des objets dans l'objet de registre à l'aide d'un identifiant. Vous avez donc accès à un registre. Vous pouvez également accéder à tous les objets. Bien sûr, lorsqu'un objet est créé pour la première fois, il doit être ajouté au registre.
Exemple:
L'exemple ci-dessus montre clairement que, pour être utile, le registre doit être accessible de manière globale. Une variable globale pour le registre unique n'est pas très mauvaise, cependant, pour les puristes non globaux, il est possible d'implémenter l'approche d'instance statique pour un registre, ou peut-être une fonction avec une variable statique:
La première fois que la fonction est appelée, elle instanciera le registre, elle sera simplement renvoyée lors d'appels suivants.
Une autre méthode spécifique à WordPress pour rendre une classe accessible globalement renvoie le retour d'une instance d'objet à partir d'un filtre. Quelque chose comme ça:
Après cela, le registre est nécessaire partout:
Un autre modèle pouvant être utilisé est le modèle de localisation de service . Il est similaire au modèle de registre, mais les localisateurs de service sont transmis à différentes classes à l'aide de l'injection de dépendance.
Le principal problème de ce modèle est qu’il masque les dépendances des classes, ce qui rend le code plus difficile à maintenir et à lire.
Conteneurs DI
Quelle que soit la méthode utilisée pour rendre le registre ou le localisateur de services accessible à l’ensemble du monde, les objets doivent y être stockés et, avant d’être stockés, ils doivent être instanciés.
Dans les applications complexes, où il y a beaucoup de classes et beaucoup d'entre elles ont plusieurs dépendances, l'instanciation des classes nécessite beaucoup de code, donc la possibilité de bogues augmente: le code qui n'existe pas ne peut pas avoir de bogues.
Il est apparu ces dernières années des bibliothèques PHP qui aident les développeurs PHP à instancier et à stocker facilement des instances d’objets, en résolvant automatiquement leurs dépendances.
Ces bibliothèques sont appelées conteneurs d'injection de dépendances car elles sont capables d'instancier des classes résolvant des dépendances et également de stocker des objets et de les renvoyer si nécessaire, agissant de la même manière pour un objet de registre.
Habituellement, lors de l'utilisation de conteneurs DI, les développeurs doivent configurer les dépendances pour chaque classe de l'application, puis la première fois qu'une classe est nécessaire dans le code, elle est instanciée avec les dépendances appropriées et la même instance est renvoyée à plusieurs reprises lors de requêtes ultérieures. .
Certains conteneurs DI sont également capables de détecter automatiquement les dépendances sans configuration, mais en utilisant la réflexion PHP .
Certains conteneurs DI bien connus sont:
et plein d'autres.
Je tiens à souligner que pour les plugins simples, qui impliquent seulement quelques classes et que les classes n'ont pas beaucoup de dépendances, l'utilisation de conteneurs DI ne vaut probablement pas la peine: la méthode de l'instance statique ou un registre accessible mondial sont de bonnes solutions, mais pour les plugins complexes l'avantage d'un conteneur DI devient évident.
Bien entendu, même les objets de conteneur DI doivent être accessibles pour pouvoir être utilisés dans l'application. Pour cela, il est possible d'utiliser l'une des méthodes décrites ci-dessus, variable globale, variable d'instance statique, renvoyer un objet via un filtre, etc.
Compositeur
Utiliser un conteneur DI signifie souvent utiliser un code tiers. De nos jours, en PHP, lorsque nous devons utiliser une bibliothèque externe (donc non seulement les conteneurs DI, mais tout code ne faisant pas partie de l'application), le télécharger et le placer dans notre dossier d'application n'est pas considéré comme une bonne pratique. Même si nous sommes les auteurs de cet autre morceau de code.
Découpler un code d'application des dépendances externes est le signe d'une meilleure organisation, d'une meilleure fiabilité et d'une meilleure santé du code.
Composer , est le standard de facto de la communauté PHP pour gérer les dépendances PHP. Loin d’être aussi courant dans la communauté WP, c’est un outil que tous les développeurs PHP et WordPress devraient au moins connaître, sinon utiliser.
Cette réponse a déjà la taille d'un livre pour permettre une discussion plus approfondie. Discuter de Composer ici est probablement hors sujet, elle n'a été mentionnée que par souci d'exhaustivité.
Pour plus d'informations, visitez le site Composer et lisez également ce minisite organisé par @Rarst .
1 PSR sont les règles standards de PHP publiées par le Framework PHP Interop Group
2 Composer (une bibliothèque qui sera mentionnée dans cette réponse) contient entre autres un utilitaire de chargement automatique.
la source
J'utilise la structure suivante:
Remarques:
init
méthode)Déni de responsabilité Je n'utilise pas encore de tests unitaires ( tant de choses sur ma plaque ) et j'entends dire que l'électricité statique peut être moins préférable pour eux. Faites vos recherches à ce sujet si vous devez le tester à l'unité.
la source
Tout dépend de la fonctionnalité.
Une fois, j’ai créé un plugin qui enregistrait les scripts lors de l’appel du constructeur, il a donc fallu l’accrocher au
wp_enqueue_scripts
crochet.Si vous souhaitez l'appeler lorsque votre
functions.php
fichier est chargé, vous pouvez également créer vous-même une instance,$class_instance = new ClassName();
comme vous l'avez mentionné.Vous voudrez peut-être prendre en compte la vitesse et l'utilisation de la mémoire. Je ne suis au courant d'aucun, mais je peux imaginer qu'il y a des hooks non appelés dans certains cas. En créant votre instance à ce raccordement, vous économiserez peut-être certaines ressources du serveur.
la source
init()
méthode statique afin que l'instance de la classe soit appelée dans la portée de la classe au lieu d'une autre portée dans laquelle vous pourriez éventuellement écraser des variables existantes.Je sais que cela fait quelques années, mais en attendant php 5.3 supporte les méthodes anonymes , alors je suis venu avec ceci:
et de toute façon je l'aime le plus. Je peux utiliser des constructeurs normaux et je n'ai pas besoin de définir de méthode "init" ou "on_load" qui gâche mes structures de POO.
la source