PHP objects are in one hell of a state too

In my previous article, I presented the design pattern “State”. It’s time to introduce a method to implement it in your PHP projects.

I wrote the library “States” which allows to easily implement this behavior to your objects, without having to use a third-party PHP extension.

We can install it easily with the following command:

composer require teknoo/states

Presentation

In the States library, “Context” classes are called “Proxy” and require the implementation of the interface “ProxyInterface”. A trait is provided to avoid writing it yourself.

Since version 3, the library requires PHP7.1 or higher, Proxy classes are autonomous. In previous versions, they require a “factory” to be instantiated.

The states are represented by classes implementing the interface “StateInterface”. A trait is also available. States classes must be listed in the Proxy class, in the static method “statesListDeclaration”.

Methods of these states will be methods called by our object “Proxy”. The keywords “$this->”, “self::” and “static::” will represent the Proxy object (or instance) or class and not the State class / object.

The visibility of Proxy’s attributes, of Proxy’s methods and all methods in states are preserved. A protected element will be accessible only to the methods of the class and to its children, private elements only to the methods of the class.

Children classes of the Proxy class inherit of states from their parents classes. It is possible to extend or redefine them.

Attention
Because of an internal PHP restriction, state methods must return a closure implementing the body of the method. It’s this closure will be called alter.
Moreover, no attribute can be declared in these states, they will be ignored.

Implementation

By following our pseudo code of the previous article, we can write this implementation:


Automating

This library provides also a mechanism to select “automatically” the appropriate state(s) according to the attributes of the object. The selection is made using a list of assertions to be defined via the static method listAssertions().

The selection is not executed automatically, however, only when calling the method updateStates(). It can be called at any time, in the constructor, before or after each call, in a method of the Proxy class or its states, or from an external method or function.

We can adapt our class Person to speak the language of the native country when its interlocutor does not specify the required language.


With this last evolution, our object will automatically speak the language of user’s country. It is possible to go further, the library implement other assertions, based on digital operations, or on closures.

This evolution also implements a variant. The interlocutor tells it, via the method spoke(), the required language, it is no longer passed as a parameter. The method hello() and birthday() methods are directly implemented in states and are accessible if the state is enabled.