Du PHP dans tous ses états

Dans mon précédent article, je vous ai présenté le design pattern “Etat”. Il est temps de vous présenter une méthode pour l’implémenter dans vos projets PHP.

J’ai écrit la bibliothèque “States” qui permet d’implémenter facilement ce comportement à vos objets, sans à avoir recours à une extension PHP tierce.

Nous pouvons l’installer facilement avec composer avec la commande suivante :

composer require teknoo/states

Présentation

Dans la bibliothèque States, les classes “Context” sont appelés “Proxy” et nécessite l’implémentation de l’interface “ProxyInterface”. Un trait est fourni pour vous éviter de l’écrire vous même.

Depuis la version 3, la bibliothèque nécessite PHP7.1 ou plus, les classes Proxy sont autonomes. Dans les versions précédentes, elles nécessitent une “factory” pour être instanciées.

Les états sont représentés par des classes implémentant l’interface “StateInterface”. Un trait est également disponible. Ces dernières doivent être listées dans le proxy, dans la méthode statique “statesListDeclaration”.

Les méthodes de ces états seront les méthodes appelées par notre objet “Proxy”. Les mots clés “$this->”, “self::” et “static::” représenteront l’objet (l’instance) Proxy ou la classe et non la classe State.

La visibilité des attributs de la classe Proxy, ainsi que des méthodes de cette même classe et de ses états sont conservés. Ainsi un élément protected ne sera accessible qu’aux méthodes de la classe et à ses enfants, les éléments private uniquement aux méthodes de ladite classe.

Les classes enfants à la classe Proxy hérite des états de leurs classes parentes. Il est possible de les étendre ou de les redéfinir.

Attention
Suite à une restriction interne à PHP, les méthodes des états doivent retourner une closure implémentant le corps de la méthode. C’est cette dernière qui sera appelée.
De plus, aucun attribut ne peut être déclaré dans ces états, ils seront ignorés.

Implementation

En suivant notre pseudo code de l’article précédent, son implémentation nous donne :


Automatisation

La bibliothèque propose un mécanisme permettant de sélectionner “automatiquement” le ou les états appropriés en fonction des attributs de l’objet. La sélection s’effectue à l’aide d’une liste d’assertions à définir via la méthode listAssertions().

La sélection n’est cependant pas exécuté automatiquement, mais uniquement lors de l’appel à la méthode updateStates(). Cette dernière peut être appelé à tout moment, dans le constructeur, avant ou après chaque appel, dans une méthode de la classe Proxy ou de ses états, voir depuis une méthode ou fonction extérieure.

Nous pouvons adapter notre classe Person pour parler la langue de son pays natal lorsque son interlocuteur ne lui spécifie pas le langage demandé.


Avec cette ultime évolution, notre objet va automatiquement parler la langue de son pays. Il est possible d’aller plus loin, la bibliothèque implémente d’autres assertions, basées sur les opérations numériques, ou sur des closures.

Cette évolution implémente également une variante. L’interlocuteur lui indique via la méthode spoke() la langue désirée, elle n’est plus passée en paramètre. Les méthodes hello() et birthday() sont directement implémentées dans les états et donc accessibles (si l’état est actif).