L'inversion de contrôle (Inversion of Control, IoC) est un motif de conception (design pattern) devenu populaire, ces dernières années, avec l'adoption des conteneurs légers comme SpringFramework. Entendant leurs mérites tant vantés par les développeurs Java, des adeptes de PHP se sont fait un devoir d'implémenter un tel conteneur dans leur langage de prédilection. On trouve ainsi : Drip, Garden, Solar, Phemto, Seasar, ClawPHP et même WACT. C'est à mon avis alourdir considérablement le développement pour faire quelque chose que PHP sait faire naturellement. Je vous propose donc de découvrir ce qu'est l'inversion de controle et comment la mettre en place en PHP sans même l'implémenter concrètement.
L'inversion de contrôle est ce qui différencie un framework d'une librairie. Une librairie est essentiellement un essemble de fonctions (organisées en objet de nos jours) appelées par le programmeur. Chaque appel réalise une tâche donnée et rend la main au programme appelant. Au contraire, un framework incorpore une conception abstraite ayant un comportement propre. Pour l'utiliser, vous devez insérer votre code à certains endroits du framework, par héritage des classes du framework ou par un mécanisme de plugin. C'est ensuite le framework qui appelle votre code. D'où l'autre nom de l'inversion de contrôle, le principe de Hollywood : « Ne nous appelez pas, c'est nous qui vous appellerons ».
Prenons l'exemple trivial, en Java, issu de l'article The Dependency Inversion Principle (PDF de 30 ko) de Robert C. Martin. Un bouton, actionné par une méthode switchState contrôle une lampe pour l'allumer (turnOn) ou l'éteindre (turnOff). La version naïve proposée est celle du bouton commandant directement la lampe :

Cette lampe peut être allumée (turnOn) ou éteinte (turnOff) par le bouton dont elle est un attribut :
Cette dépendance du bouton envers la lampe implique qu'il peut être nécessaire de modifier la classe Button si la classe Lamp change. D'autre part ce bouton ne peut être réutilisé pour contrôler un autre appareil.
Pour inverser ce contrôle du bouton sur la lampe, on met en place des abstractions. L'abstraction de la lampe est une interface de client du bouton (ButtonClient) :
On peut aussi abstraire le bouton en une interface Button pour rendre encore plus modulaire le code, bien que cela ne soit pas impliqué par le principe de l'inversion de contrôle dans cet exemple naïf.
Ainsi la lampe implémente l'interface ButtonClient :
Et le bouton concrêt (ButtonImpl) implémente l'interface Button :
La figure suivante présente les dépendances existantes entre ces différents éléments :

Le code ainsi produit est fortement découplé, léger, facile à faire évoluer, et testable unitairement. Mais alors pourquoi ne pas l'implémenter en PHP ?
PHP est un langage (très) faiblement typé ! La résolution des noms des méthodes se fait lors de l'appel, sans vérification d'un quelconque type de l'objet sur lequel est appelé la méthode. En PHP, les abstractions n'ont donc pas besoin d'être exprimées dans le langage : il n'est pas nécessaire de formaliser les interfaces. Il est simplmeent nécessaire de les décrire dans la documentation, pour que l'on sache quelles méthodes implémenter sur quels objets afin de les insérer dans le framework. L'exemple précédent se résume donc en PHP aux deux seules classes concrêtes que sont la lampe :
Et le bouton :
Il n'y a donc plus aucun couplage entre les deux classes instanciées par le programme principal :
Et le diagramme de classes est on ne peut plus simple :

Remarque : l'utilisation d'objets PHP est, ici, a dessein pédagogique, mais n'est pas une obligation contrairement à une croyance très répandue.
L'implémentation de l'inversion de contrôle en PHP n'a donc pas besoin d'artifices, comme les interfaces. Mais il faut être très rigoureux. Bien souvent, le recours à la POO avec typage est un moyen de contraindre le programmeur à être rigoureux. Mais il est très facile de passer outre cette contrainte. L'important n'est pas d'implémenter IoC selon les canons de la POO, mais de produire du code flexible, robuste et réutilisable. C'est donc avant tout, le principe de la séparation des préoccupations qui est essentiel.
Bien sûr, la thèse défendue ici est un peu extrémiste. Les interfaces explicites sont utiles, mais on pourrait envisager de les fournir pour guider le programmeur dans l'écriture de code conforme à ce qu'attend le framework sans obligation de les implémenter. Par contre réaliser un conteneur IoC en PHP est une ineptie. Cela revient, en effet, à construire toute une machinerie complexe, pour faire quelque chose qu'il est encore plus simple de faire sans.