H
eureusement, vous avez à votre ble un simple conteneur IoC dont le fonc-
disposition un conteneur IoC (en tionnement repose en grande partie sur
anglais Inversion of Control) que le principe d'Hollywood susmentionné. Le
nous avons présenté plusieurs fois dans code du conteneur et un exemple d'implé-
nos magazines PHP Solutions. Si vous mentation se trouveront sur le site Internet
connaissez certains articles précédents, http://flexi.sf.net/, comme c'était le cas des
vous savez ce que IoC sait faire à peu articles précédents.
près : le conteneur vous proposera un
graphe des objets préparés, par exemple, Qu'est-ce qu’un
il permettra de configurer facilement les conteneur IoC ?
décorateurs. Un conteneur IoC est une fabrique d'ob-
jets configurable, capable non seulement
Ne nous appelez pas, de créer les objets mais aussi de les
à placer dans les paramètres appro- Imaginez que la classe A a besoin choisir ? Ces problèmes n'apparaissent
priés du constructeur ou du setter. Le de n'importe quelle classe qui implé- pas dans de simples projets où le fi-
format du fichier n'est pas important ; il mente l'interface BI pour fonctionner. Et chier de configuration contient plusieurs
devrait seulement être lisible car il faut imaginez que vous disposiez de deux objets mais dans les projets contenant
l'écrire manuellement. Pour cette rai- classes qui implémentent cette interface plusieurs dizaines d'objets ; vous les ren-
son, l'analyse du fichier de configuration dans le fichier de configuration ; laquelle contrerez sûrement. Le conteneur que
dans votre application sera transférée
à des classes séparées pour modifier fa- Listing 4. Implémentation des classes qui mappent le fichier de configuration dans
cilement le format et la source des don- le modèle orienté objet : classe DefaultParamMap
nées de configuration. Il est possible de
<?php
créer un fichier de configuration en vous
basant sur XML et Xschema et d'utiliser abstract class DefaultParamMap {
un outil graphique pour créer des fichiers
de configuration. Cet outil vérifierait en private $name;
plus si le fichier XML est correct. Vous private $value;
private $type;
réaliserez votre fichier de configuration
en vous basant sur les tableaux asso- public function __construct($name, $value, $type) {
ciatifs. $this->setName($name);
La deuxième méthode de définition de $this->setValue($value);
l'arbre est une extension de la première $this->setType($type);
}
méthode. Elle demande toutefois d'utiliser
un typage fort dans le code. Imaginez public function getName() {
que l'objet A a besoin de n'importe quelle return $this->name;
classe pour fonctionner correctement ; }
cette classe implémente l'interface BI ou
protected function setName( $name ) {
tout simplement les classes B. Depuis un
$this->name = $name;
certain temps, il est possible de forcer en }
PHP les types d'objets. Pour cette raison, il
est possible de coder le constructeur ou le public function getValue() {
setter de la classe 1 de manière suivante : return $this->value;
}
ou, si vous ne voulez pas utiliser l'interface protected function setType( $type ) {
mais uniquement la classe B : $this->type = $type;
}
class A { }
public function ?>
__construct(B $b){}
public function Listing 5. Implémentation des classes qui mappent le fichier de configuration dans
setB(B $b){}
le modèle orienté objet : classe ConstructorParamMap
} <?php
Configuration sociatif, chaque clé de ce tableau identifie mettre à la place de cet attribut,
du conteneur un objet. Les objets seront chargés depuis constitue une valeur. En ce qui
Afin de configurer le conteneur IoC, uti- le conteneur d'après cet identifiant. Remar- concerne les constantes caractère
lisez un simple modèle orienté objets et quez qu'il est possible de définir plusieurs ou numériques, vous y placez leur
les tableaux associatifs. La configuration configurations pour une seule classe dans valeur et en ce qui concerne les ré-
gérée par le programmeur se trouvera un fichier ; il suffit qu'elles soient identifiées férences aux objets, vous saisissez
dans un tableau spécial, traduit ensuite par d'autres clés du tableau. En dessous le caractère « & » et l'identifiant de
en un ensemble d'objets par une classe de l'identifiant de l'objet se trouve un autre l'objet, défini dans le conteneur IoC,
d'analyse spéciale. Votre conteneur opé- tableau associatif ; il dispose d'un ensem- • constructorParams – tableau con-
rera sur ces objets. Grâce à cette démar- ble défini des clés : tenant les paramètres, prévus au
che, il sera facile de modifier les formats constructeur de l'objet ; cette fois-ci,
et les sources de données de configu- • className – nom de la classe, il ne s'agit pas de tableau associatif.
ration. Vous pourrez aussi configurer le • file – emplacement du fichier conte- Seul l'ordre des valeurs placées est
conteneur sans les fichiers de configura- nant la définition de la classe, important. Elles seront placées dans
tion dans les situations difficiles. • singleton – indicateur qui dit si l'objet le même ordre dans le constructeur
Le Listing 1 présente un extrait du doit être créé une seule fois et placé lors de la création de l'objet. Les
script index.php. Vous y trouverez deux ensuite dans la mémoire cache ou si règles de la saisie des paramètres
sections : l'une est très longue pour une instance de l'objet doit être créé à sont les mêmes que ci-dessus.
configurer les objets et la seconde est chaque fois,
plus courte pour lancer le front control- • properties – tableau associatif où La Figure 2 présente un diagramme
ler. Maintenant, regardez le Listing 2. le nom de l'attribut de l'objet cons- UML et les Listings 4 – 8 présentent
Il présente le même script index.php ; titue la clé. La variable, qu'il faut les implémentations des classes qui
cette fois-ci, le conteneur IoC est chargé
de configurer les objets et de les créer. Listing 8. Implémentation des classes qui mappent le fichier de configuration dans
Au premier abord, vous remarquerez le modèle orienté objet : classe ApplicationMap
que le script est plus simple. Plus l'arbre
<?php
d'objets à créer est grand, plus le code
est lisible. require_once 'ioc/ClassMap.class.php';
Le Listing 3 présente la configu- class ApplicationMap {
ration de votre conteneur IoC. Cette
configuration vous permet de restituer private $classes = array();
Si vous utilisez la version PHP 5.1.3 ou de configuration dans la section tributs d'objets. Elle est conforme à la
supérieure, vous pouvez créer les objets properties. Le conteneur crée lui- convention utilisée dans d'autres appli-
avec les paramètres pour le constructeur même l'information pour savoir quel cations. Remarquez aussi deux métho-
à l'aide de Reflection Api et la méthode setter utiliser ; cette information n'est des : getConstructorParamsRecursively
newInstanceArgs. pas enregistrée dans la configuration. et getPropertyValueRecursively. Elles
Une fois l'objet créé, son ins- Le nom correct du setter se compose se ressemblent. D'après le type de pa-
tance est transmise à la méthode d'un préfixe set et du nom de property ; ramètre qui peut prendre deux valeurs
setProperties où on ajoute les varia- la première lettre est majuscule. Vous value ou référence, le conteneur char-
bles à l'objet à l'aide des setters ; ces devriez connaître cette convention pour ge une constante depuis la configura-
variables sont définies dans le fichier nommer les méthodes d'accès aux at- tion ou lance de nouveau sa méthode
create, afin de créer un objet. Grâce
à ce morceau de code, le conteneur
Listing 10 b. Forme élémentaire de l'implémentation complète du conteneur
– suite peut retourner des arbres entiers d'ob-
jets. Pour savoir si le paramètre est du
protected function getConstructorParamsRecursively(ConstructorParamMap type value ou référence, regardez si le
$constructorParamMap) { caractère & se trouve à côté de la défi-
switch ( $constructorParamMap->getType() ) {
nition de la valeur du paramètre dans
case 'value' : $param = $constructorParamMap->getValue(); break;
case 'reference' : $param = le fichier de configuration.
$this->create( $constructorParamMap->getValue() ); break;
default : throw new Exception( Conclusion
"Le type du paramètre est incorrect {$constructorParamMap- Le conteneur IoC, que nous avons
>getType()}" );
réalisé ensemble, est utilisé depuis un
}
certain temps dans le travail quotidien
return $param; dans ma société. L'expérience a mon-
} tré que son implémentation a facilité
la réalisation des applications. Nous
protected function setProperties(ClassMap $classMap, $object) {
avons gagné le plus dans les tests
$properties = $classMap->getProperties();
et la clarté du code. De plus, après
foreach($properties as $propertyParamMap) { l'adaptation à la spécificité du conte-
$propertySetterName = $propertyParamMap->getSetterMethodName(); neur IoC (nous fournissons les objets
$object->{$propertySetterName} via le constructeur et les setters), une
( $this->getPropertyValueRecursively($propertyParamMap) );
grande partie des classes est devenue
}
} tellement souple que nous les utilisons
dans d'autres projets sans les mo-
protected function getPropertyValueRecursively( PropertyParamMap difier. Nous avons également réussi
$propertyParamMap ) { à supprimer dans le code les aspects
switch ( $propertyParamMap->getType() ) {
liés à l'autorisation, à la connexion et
case 'value' : $param = $propertyParamMap->getValue(); break;
case 'reference' : $param = $ à la validation. Pour savoir comment
this->create( $propertyParamMap->getValue() ); break; nous l'avons réussi, rendez-vous dans
default : throw new Exception( le prochain article. n
"Le type de l'attribut est incorrect {$propertyParamMap->getType()}"
);
}