Chargement automatique orienté objet dans WordPress, partie 2

Dans le tutoriel précédent, nous avons abordé une poignée de concepts, qui seront tous nécessaires pour bien comprendre ce que nous faisons dans ce tutoriel..

Plus précisément, nous avons abordé les sujets suivants:

  • interfaces orientées objet
  • le principe de responsabilité unique
  • à quoi ça ressemble en PHP
  • où nous nous dirigeons avec notre plugin

Dans certaines séries, il est facile de sauter des tutoriels qui ne peuvent pas être construits les uns sur les autres; Cependant, cette série n'est pas destinée à être comme ça. Au lieu de cela, il est conçu pour être lu dans un ordre séquentiel et pour renforcer le contenu de chaque tutoriel précédent..

Cela dit, je suppose que vous êtes tous rattrapés. 

Commencer

Même si j'ai peut-être mentionné cela dans le premier tutoriel, j'aime toujours m'assurer que nous sommes tous sur la même page en ce qui concerne ce que nous faisons dans chaque tutoriel et avec quel logiciel vous allez avoir besoin..

Notre feuille de route

Donc, dans ce tutoriel, le plan est le suivant:

  1. Examiner le code que nous avons écrit jusqu'à présent.
  2. Déterminer comment nous pouvons être en mesure de le refactoriser à l'aide de techniques orientées objet.
  3. Fournir les grandes lignes de notre mise en œuvre.

En fin de compte, nous n'écrirons pas beaucoup code dans ce tutoriel, mais nous allons en écrire. Il s’agit toutefois d’un didacticiel pratique dans la mesure où nous effectuons une analyse et une conception orientées objet. C'est une phase nécessaire pour de nombreux projets à grande échelle (et quelque chose qui devrait arriver pour des projets à petite échelle).

De quoi as-tu besoin

Si vous avez suivi, vous devriez déjà l'avoir mis en place. Mais pour être sûr, voici la version courte de tout ce dont vous avez besoin:

  • un environnement de développement local adapté à votre système d'exploitation
  • un répertoire à partir duquel WordPress 4.6.1 est hébergé
  • un éditeur de texte ou IDE
  • connaissance de l'API du plugin WordPress

Avec tout cela en place, nous sommes prêts à travailler sur le code partagé dans le précédent tutoriel. Alors, commençons.

Analyser le code

La première chose que nous souhaitons faire est d’analyser l’état actuel de notre chargeur automatique. Il peut sembler que beaucoup de code soit collé dans un seul bloc de code, mais cela en soi nous montre que nous avons du travail à faire..

Cela dit, voici l'état actuel de notre chargeur automatique:

 0; $ i--) // Lit le composant actuel de la partie du fichier. $ current = strtolower ($ file_parts [$ i]); $ current = str_ireplace ('_', '-', $ current); // Si nous en sommes à la première entrée, alors nous sommes au nom du fichier. if (count ($ file_parts) - 1 === $ i) / * Si 'interface' est contenu dans les parties du nom du fichier, alors * définissons le $ nom_fichier différemment pour qu'il soit correctement chargé. * Sinon, définissez simplement $ nom_fichier égal à celui de la structure de la classe * nom_fichier. * / if (strpos (strtolower ($ file_parts [count ($ fichiers_fichiers) - 1]), 'interface')) ) Extrait le nom de l'interface de son nom qualifié. $ nom_interface = exploser ('_', $ pièces_fichiers [count ($ pièces_fichiers) - 1]); $ nom_interface = $ nom_interface [0]; $ nom_fichier = "interface- $ nom_interface.php";  else $ nom_fichier = "class- $ current.php";  else $ namespace = '/'. $ actuel. $ namespace;  // Créez maintenant un chemin d'accès au fichier en utilisant un mappage vers l'emplacement du fichier. $ filepath = trailingslashit (dirname (dirname (__FILE__)). $ namespace); $ filepath. = $ nom_fichier; // Si le fichier existe dans le chemin spécifié, incluez-le. if (file_exists ($ filepath)) include_once ($ filepath);  else wp_die (esc_html ("Le fichier qui tente d'être chargé à $ filepath n'existe pas.")); 

À ce stade, rappelez-vous que le principe de responsabilité unique énonce ce qui suit:

Une classe ne devrait avoir qu'une seule raison de changer.

À l'heure actuelle, nous n'avons même pas de classe, encore moins plusieurs méthodes individuelles qui n'ont qu'une seule raison de changer.

Et même s'il peut être judicieux de commencer par diviser cette méthode d'autoloader en méthodes individuelles plus petites, commençons par un niveau supérieur et commençons à penser à un autochargeur en termes d'interface. Ensuite, nous allons approfondir la création d'une classe (ou de classes).

Analyse orientée objet: responsabilités

Rappelez-vous du tutoriel précédent qu'une interface est définie par le manuel PHP comme suit:

Les interfaces d'objet vous permettent de créer un code qui spécifie les méthodes qu'une classe doit implémenter, sans avoir à définir comment ces méthodes sont gérées.

Etant donné le code et les définitions ci-dessus, réfléchissons à ce qu'un autochargeur doit faire dans une perspective plus modulaire. Spécifiquement, divisons cela en points qui représentent ce qui pourrait être suffisant pour changer. Non, nous n'utilisons peut-être pas tous ces points, mais c'est la raison pour laquelle cela s'appelle analyse. Nous travaillerons sur la conception plus tard.

Le code fait ce qui suit:

  1. Valide nous travaillons explicitement avec notre espace de noms.
  2. Divise le nom de classe entrant en parties pour déterminer s'il s'agit d'une classe ou d'une interface (donc $ nom_classe est un nom de variable pauvre).
  3. Vérifie si nous travaillons avec un fichier d'interface.
  4. Vérifie si nous travaillons avec un fichier de classe.
  5. Vérifie si nous travaillons avec une interface.
  6. En fonction du résultat des conditions ci-dessus, génère un nom de fichier..
  7. Construit un chemin de fichier basé sur le nom de fichier généré.
  8. Si le fichier existe sous le nom généré, incluez-le.
  9. Sinon, le code génère une erreur.

Ainsi, le code ci-dessus ne neuf choses-c'est-à-dire qu'il a au moins neuf raisons de changer, avant d'avoir terminé son travail. 

Cela devrait aller de soi, mais cette fonction particulière est un exemple parfait de refactorisation permettant de démontrer une analyse, une conception, des interfaces et une implémentation orientées objet..

Et cela soulève une question: par où commençons-nous même?

Analyse orientée objet

À ce stade, il est juste de dire que nous pouvons commencer à faire une analyse orientée objet, c'est-à-dire examiner quelles classes potentielles nous pouvons avoir et comment elles interagissent, compte tenu de tout ce que nous avons énuméré ci-dessus. N'oubliez pas que nous souhaitons également que le principe de responsabilité unique nous guide dans notre prise de décision..

Pour le moment, nous ne sommes pas très préoccupés par la manière dont les classes vont communiquer les unes avec les autres. Au lieu de cela, nous nous concentrons davantage sur la création de classes ayant une seule raison de changer..

Cela dit, je vais vous fournir un échantillon de classes qui pourraient fonctionner. Avant d'aller plus loin, regardez ce que nous avons fait et essayez de créer votre propre liste. Ensuite, nous pouvons comparer les notes.

Un mot sur les compétences

Notez que vous avez peut-être une meilleure idée que ce qui est répertorié ci-dessous ou vous pouvez retirer quelque chose de ce que nous avons partagé. Quoi qu'il en soit, il s'agit d'un exercice d'apprentissage. Nous essayons d'améliorer notre code, notre organisation et finalement de devenir de meilleurs programmeurs.

Nos classes potentielles

Compte tenu de ce que j'ai énuméré ci-dessus, j'ai mis au point les classes suivantes:

  1. Autochargeur. C'est la classe principale responsable d'inclure finalement notre classe, notre espace de noms ou notre interface. Nous appellerons cette classe. Les autres sont des classes qui s’occuperont du travail nécessaire à cette classe pour inclure le fichier.. 
  2. NamespaceValidator. Ce fichier examinera la classe entrante, l'interface ou ce que vous avez et déterminera s'il est valide. Cela nous donnera le facteur décisif si nous pouvons procéder avec le reste de notre code notre pas. 
  3. FileInvestigator. Cette classe examine le type de fichier transmis à l'autochargeur. Il déterminera s'il s'agit d'une classe, d'une interface ou d'un espace de noms et retournera le nom de chemin complet au fichier afin qu'il puisse être inclus..
  4. FileRegistry. Ceci utilisera le chemin de fichier pleinement qualifié finalement renvoyé par les autres classes et l'inclura dans le plugin..

Et c'est tout. Désormais, les classes tierces de notre plug-in doivent uniquement connaître la classe de l'autoloader, mais l'autoloader doit connaître la connaissance d'une autre classe et les autres classes doivent connaître d'autres classes..

Là sont façons de gérer cela (en utilisant des conteneurs d'injection de dépendance, mais cela dépasse le cadre de ce projet). Mais ce que nous viserons dans notre code est de minimiser le nombre de classes qui se connaissent.

Conception orientée objet

À ce stade, différents développeurs, entreprises, agences et équipes adopteront une approche différente pour concevoir le système sur lequel ils travaillent..

L'une des méthodes les plus courantes consiste à utiliser un diagramme appelé UML. Bien que cela soit utile, ce n’est pas intéressant d’être dans le cadre de ce tutoriel, car il faudra tout un autre tutoriel pour expliquer tous les éléments..

Donc, pour les besoins de notre tutoriel, et comme nous travaillons avec une si petite quantité de code, nous allons essayer d'expliquer comment chacune des classes ci-dessus peut fonctionner avant de les implémenter. De cette façon, nous aurons une idée de la façon dont nous pouvons organiser notre code.

Notez que nous n'allons pas encore nommer aucun code de ce code, et aucun de ce code ne doit être implémenté ou testé par rapport à WordPress. Nous entrerons dans cela dans le prochain tutoriel.

Commençons par le Autochargeur et travailler à partir de là.

Autochargeur

N'oubliez pas que cette classe est chargée d'inclure le fichier nécessaire. C'est le fichier qui sera enregistré avec le spl_autoload_register une fonction. 

namespace_validator = new NamespaceValidator (); $ this-> file_registry = new FileRegistry ();  fonction publique load ($ filename) if ($ this-> namespace_validator-> is_valid ($ filename)) $ this-> file_registry-> load ($ filename);  

Notez que cette classe dépend de la NamespaceValidator et le FileRegistry classe. Nous verrons chacune de ces choses plus en détail dans un instant.

NamespaceValidator

Ce fichier examinera le nom du fichier entrant et déterminera s'il est valide. Ceci est fait en regardant l'espace de noms dans le nom du fichier.

Si le fichier Est-ce que en fait appartenir à notre espace de noms, alors nous pouvons supposer qu'il est prudent de charger notre fichier.

FileInvestigator

Ce cours fait pas mal de travail, bien qu’une partie de ce travail se fasse via des méthodes d’aide très simples et très petites. Au cours de l'exécution, il examine le type de fichier transmis.. 

Il récupère ensuite le nom de fichier qualifié complet pour le type de fichier.

get_file_name ($ file_parts, $ current, $ i); if (count ($ file_parts) - 1! == $ i) $ filepath = trailingslashit ($ filepath);  return $ filepath;  fonction privée get_file_name ($ file_parts, $ current, $ i) $ filename = "; if (nombre ($ fichiers_parts) - 1 === $ i) si ($ this-> is_interface ($ fichiers_fichiers)) $ filename = $ this-> get_interface_name ($ file_parts); else $ filename = $ this-> get_class_name ($ current); else $ filename = $ this-> get_nomspace_name ($ current); return $ filename;  function privée is_interface ($ file_parts) return strpos (strtolower ($ file_parts [count ($ file_parts) - 1]), 'interface'); fonction privée get_interface_name ($ file_server) $ interface_name = explode ('_', $ file_parts [count ($ file_parts) - 1]); $ interface_name = $ interface_name [0]; return "interface- $ interface_name.php"; fonction privée get_class_name ($ current) return "class- $ current.php" ; fonction privée get_namespace_name ($ current) return '/'. $ current;

S'il y a un fichier qui peut être refactoré un peu plus, alors c'est ça. Après tout, il tente de déterminer si nous travaillons avec une classe, une interface ou une classe. Une simple usine pourrait mieux convenir à cela.

Lorsque le moment sera venu d’implémenter notre code, nous pourrons peut-être le reformuler davantage. Jusque-là, il s'agit d'un avant-projet qui peut fonctionner assez bien.

FileRegistry

Cela utilisera le chemin de fichier qualifié complet et inclura le fichier; sinon, il utilisera l'API WordPress pour afficher un message d'erreur.

classe FileRegistry private $ investigator; fonction publique __construct () $ this-> investigator = new FileInvestigator ();  fonction publique load ($ filepath) $ filepath = $ this-> investigator-> get_filetype ($ filepath); $ filepath = rtrim (plugin_dir_path (nomrépertoire (__FILE__)), '/'). $ filepath; if (file_exists ($ filepath)) include_once ($ filepath);  else wp_die (esc_html ('Le fichier spécifié n'existe pas.'));  

Une autre alternative à l’utilisation de l’API WordPress serait de lancer un message d’exception personnalisé. De cette manière, nous pourrions séparer ou découpler complètement notre code de WordPress..

Encore une fois, ce code est un report de l’autochargeur initial. Pendant la mise en œuvre, nous pouvons changer cela, ainsi.

Conclusion

Très bien, nous avons donc examiné le code existant pour notre autochargeur, puis nous avons éliminé un code potentiel que nous pouvons utiliser en nous basant sur une analyse et une conception orientées objet..

La solution à laquelle nous travaillons est-elle plus maintenable que celle que nous avons? Absolument. Est-ce que cela va fonctionner dans le contexte de WordPress et de notre plugin existant? Nous ne le saurons pas avant d'avoir commencé à le connecter à notre plugin.

Comme mentionné précédemment, il y a encore certains domaines dans lesquels nous pourrions éventuellement reformer ce code. Si nous rencontrons ce type de problèmes lors de l'implémentation de notre code dans la version finale de notre plugin, nous verrons exactement comment faire..

Quoi qu'il en soit, le code que nous avons maintenant devrait être plus lisible (bien que nous ayons toujours DocBlocks et quelques commentaires en ligne à introduire) et plus maintenable et encore plus testable..

Cela dit, j'espère que cela vous a donné une idée de la méthode à suivre pour adopter une méthode longue et la diviser en classes plus axées sur les objectifs. Bien sûr, avoir plusieurs classes peut sembler bizarre au début, mais cela ne veut pas dire que c'est une mauvaise chose. Avoir plus de fichiers (et donc de classes) avec moins de code qu'un fichier avec beaucoup de code, c'est mieux.

Adoptez le caractère contre-intuitif de la programmation orientée objet à cet égard. Dans le prochain tutoriel, nous allons revenir à notre plugin et travailler à la mise en œuvre d'une variante du code ci-dessus. Nous allons probablement en déboguer une partie. Après tout, nous réussissons rarement du premier coup

Jusque-là, si vous souhaitez en savoir plus sur la programmation orientée objet dans le contexte de WordPress, vous pouvez trouver tous mes tutoriels précédents sur ma page de profil. N'hésitez pas à me suivre sur mon blog ou à me suivre sur Twitter où je parle souvent des deux.

Ressources

  • Chargement automatique orienté objet dans WordPress, 1ère partie
  • Espaces de noms
  • Chargement automatique
  • Des interfaces
  • L'API du plugin WordPress
  • Principe de responsabilité unique