Often the existence of dependency constraints among the available classes makes it difficult to develop source codes that are legible and characterized by easily reusable components. During this brief discussion, the operation of the Design pattern Dependency Injection will be described as a valid solution to minimize the side effects due to the existence of dependencies between classes.
The concept of dependence between the classes
The management of dependencies between classes is a fairly common problem in the implementation of complex applications written in PHP and whose code is based on the paradigm of object-oriented programming; substantially a “dependence” can be defined in programming as the constraint existing between the various components that constitute an application, this link establishes in practice the level of relationship for which the functioning of a part “depends” on the nature and presence of the other set off.
What has been said is translatable from the point of view of the Object Oriented Programming referring to the mechanism of the classes. It is assumed to have two classes, called respectively “Automobile” and “Gasoline”, in case the class “Automobile” should use the “Gasoline” class it will be said that the first class depends on the second; this also means that “Automobile” (employee) will not work without “petrol” (dependence) and that the first cannot be used without involving the second.
The proposed example brings out the problem implicit in the presence of dependencies , they in fact negatively affect the degree of flexibility of a project because they limit the opportunities for re-employment of classes, the developer must always keep in mind the implications due to the adoption of a class if for its operation it needs a further model for the creation of objects.
Dependency Injection features
A system for solving dependency-related problems refers to the use of a pattern, that is a design scheme, which takes the name of Dependency Injection; in practice, the latter will allow injections of objects in the context of a class without having to generate them inside it. To clarify the mechanics of the injection of addictions it is possible to start from a practical case, ie from the origin of the problem; then start from the definition of the following class:
class Employee { private $ _rincolo; public function __construct ($ foo, $ pluto) { $ this -> _ constraint = new Dependency ($ foo, $ pluto); } } $ object = new Employee ('pippo', 'pluto');
From the syntactic point of view the presented code does not include particular problems or complexities, but if it is realized at a functional level it is possible to observe the existence of a dependency constraint on the manufacturer’s account, the latter generates a link between the “Dependent” class and the “Dependency” class; it follows that the occurrence of an event, such as the inclusion of a parameter passed to the dependency, will affect any instance of its employee.
In the case of such an eventuality, the speech related to Dependency Injection could be useful, because this will give the developer the possibility of inserting the dependency without having to generate it in the class constructor; on the basis of what has been anticipated, the previously proposed code can be modified as follows:
class Employee { private $ _rincolo; public function __construct ($ constraint) { $ this -> _ constraint = $ constraint; } } $ constraint = new Dependency ('pippo', 'pluto'); $ object = new Employee ($ constraint);
What is contained in the example shown summarizes the most common way to use Dependency Injection , ie the one that involves the transfer of dependencies to the class constructor, but it is possible to ensure that the dependencies are injected also through methods and properties; to notice then as in the case of the proposed code the insertion of new parameters through the instance of the class object of the dependence will not have influence on the instances related to the employee:
$ constraint = new Dependency ('pippo', 'pluto', 'paperino'); $ object = new Employee ($ constraint);
Another obvious advantage in the use of Dependency Injection lies in the fact that, thanks to it, the dependency can be configured independently of the constraint that binds it to the dependent component, so that the former can also be replaced with another without for this reason intervene in any way on the second.
Methods of application of the Dependency Injection
The developer will have different ways to manage the dependencies through their injection, but it is still possible to make a distinction in three types each associated with different implications. Field Injection, otherwise called “Property Injection”, consists in practice in direct injection of dependencies within class properties with a level of public visibility; an example of its use could be the following:
$ constraint = new Dependency (); $ object = new Employee (); $ object -> _ constraint = $ constraint;
Although it is a fast-use technique, it has the disadvantage of not supporting the Type Hinting useful for forcing the use of a specific type of object as a parameter; since in its absence the PHP parser will not produce the expected error notification in case of non-compliance with the suggested type, it will not be possible to be certain that the type associated with an addiction is the correct one.
The Setter Injection works similarly to the Field Injection but, specifically, bases its operation on manufacturers without arguments and passing dependencies through “setter”, ie methods that write attributes, and can be made recognizable by the key “init “Placed in front of the root of their name:
$ constraint = new Dependency (); $ object = new employee (); $ Object-> initVincolo ($ constraint);
The Setter Injection allows to partially insert the dependencies and makes them optional as related to the possible call of the setter method, moreover, it facilitates the alteration of the objects allowing to inject again the dependencies through multiple calls to the setter. This mode is not particularly functional when a large number of dependencies must be managed, in fact they will require a similar amount of setter methods.
The Constructor Injection, already used in the examples proposed in the previous chapter, exploits a logic according to which all injections of dependencies must be carried out by the manufacturer and consequently previously to the requests. This means that, since an object can not be instantiated without dependence, it must necessarily be present at the moment of the instance; this will not happen in the case of the Setter Injection where the call to the setter methods is optional and the injection of the dependencies can only be verified through controls.
The use of expressions based on Constructor Injection such as the following
$ constraint = new Dependency (); $ object = new Employee ($ constraint);
will make sure the immutability of the dependency for the entire period of execution in which the created object will exist, this because of the only call that will involve the constructor, moreover, it will be easier to manage a high number of dependencies thanks to a single relative constructor with more parameters.
While Constructor Injection allows you to initialize objects in an orderly manner and does not need a setter method for each dependency, it is necessary to underline that it does not allow partial injecting of addictions due to the fact that for the creation an object will be required to pass all the arguments to the constructor; then the limit due to the impossibility of modifying an object should be remembered.
Recalling the lack of support of the Type Hinting by Field Injection , it is not easy to establish a priori which mode is preferable between Setter Injection and Constructor Injection, much will depend on the need of the developer to operate or not with optional dependencies (one point in favor of the Setter Injection) or the importance that the sequence of initialization of the objects will have for the project implemented (a point in favor of the Constructor Injection).
Conclusions
This discussion dealt with the speech about managing dependencies in PHP using the Dependency Injection pattern; the latter has described the characteristics, the syntax and the different methods of use, proposing to the reader the opportunities and limits of the various techniques available for the reduction of the negative effects of dependencies on readability and code and flexibility.
Even the Dependency Injection is easily applicable in all cases where dependencies must be managed, this because its use in a project requires careful “upstream” planning, but in the long run it can prove to be an excellent ally for operations maintenance and update of the sources.