<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Not My Idea &#187; IoC</title>
	<atom:link href="http://www.notmyidea.org/article/tag/ioc/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.notmyidea.org</link>
	<description>Carnets Web d&#039;Alexis Métaireau</description>
	<lastBuildDate>Tue, 20 Jul 2010 10:07:17 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Réaliser un injecteur de dépendances, en utilisant de bonnes pratiques logicielles</title>
		<link>http://www.notmyidea.org/article/realiser-un-injecteur-de-dependances-en-utilisant-de-bonnes-pratiques-logicielles/</link>
		<comments>http://www.notmyidea.org/article/realiser-un-injecteur-de-dependances-en-utilisant-de-bonnes-pratiques-logicielles/#comments</comments>
		<pubDate>Tue, 20 Jul 2010 10:07:17 +0000</pubDate>
		<dc:creator>Alexis Metaireau</dc:creator>
				<category><![CDATA[php-fr]]></category>
		<category><![CDATA[Dependency Injection]]></category>
		<category><![CDATA[IoC]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://www.notmyidea.org/?p=413</guid>
		<description><![CDATA[Je publie ici un article que j&#8217;ai rédigé il y à un moment et qui à été publié dans PHP solutions en février dernier, à propos de l&#8217;injecteur de dépendances sur lequel j&#8217;ai travaillé pour mon framework spiral. (Dur de retourner à du PHP après avoir découvert les possibilités offertes par python !)
L&#8217;article est également [...]]]></description>
			<content:encoded><![CDATA[<p>Je publie ici un article que j&#8217;ai rédigé il y à un moment et qui à été publié dans PHP solutions en février dernier, à propos de l&#8217;injecteur de dépendances sur lequel j&#8217;ai travaillé pour mon framework <a href="http://www.spiral-project.org">spiral</a>. (Dur de retourner à du PHP après avoir découvert les possibilités offertes par <a href="http://python.org">python</a> !)</p>
<p>L&#8217;article est également <a href='http://www.notmyidea.org/wp-content/uploads/2010/07/injection_1b.pdf'>disponible en PDF</a> si vous souhaitez.</p>
<h2 id="toc-larticle">L&#8217;article !</h2>
<p>Un injecteur de dépendances ? Peut être cela ne vous parle il pas vraiment. Tant mieux, l&#8217;objectif de cet article est d&#8217;éclaircir ces termes, et de présenter une implémentation que j&#8217;ai eu l&#8217;occasion de mettre en place, en essayant de m&#8217;appuyer sur de bonnes pratiques logicielles.</p>
<p>Cet article est basé sur mon expérience personnelle, ainsi que sur des recherches effectuées lors de la réalisation d&#8217;un composant logiciel. L&#8217;objectif n&#8217;est aucunement d&#8217;imposer ma vision des choses, mais bel et bien de partager les interrogations, réflexion et découvertes que nous avons eu alors.</p>
<p>Nous parlerons ici de l&#8217;injecteur de dépendances de Spiral, un framework maison réalisé avec quelques amis, et dont l&#8217;objectif principal est de découvrir les rouages des frameworks, ainsi que de nous initier aux bonnes pratiques logicielles.</p>
<p>Alors que nous travaillions sur ce projet, notre principal but était de réellement comprendre, dans le détail, comment un injecteur de dépendances pouvait fonctionner. <em>Ré-inventer la roue</em>, pour mieux comprendre comment une roue fonctionne, en quelque sorte.</p>
<p>Aussi, l&#8217;objectif de ce document n&#8217;est pas de fournir une documentation sur l&#8217;utilisation du composant, mais bien d&#8217;expliquer <em>comment</em> nous l&#8217;avons réalisé.</p>
<p>L&#8217;injecteur de dépendances est disponible dans une version intégrée à Spiral ou dans une version <em>standalone</em>. Vous pouvez trouver le code sur le <a href="http://bitbucket.org/ametaireau/spiral/">dépôt mercurial</a> du projet.</p>
<p>A l&#8217;heure ou j&#8217;écris ces lignes, l&#8217;injecteur de dépendances de spiral n&#8217;est pas encore terminé (sept 09), mais est dans un état avancé, et devrait être disponible en novembre 2009.</p>
<p>L&#8217;ensemble des exemples de ce document sont en PHP, mais les concepts discutés ici peuvent être (et sont!) implémentés dans d&#8217;autres langages.</p>
<p>Donc, parlons un peu d&#8217;injection de dépendances !</p>
<h2 id="toc-comment-gerons-nous-nos-objets">Comment gérons-nous nos objets ?</h2>
<p>Avant toute chose, il est indispensable de bien comprendre ce qu&#8217;est l&#8217;inversion de contrôle.</p>
<p><img class="alignright" src="http://www.notmyidea.org/wp-content/uploads/2010/07//icecream.png" alt="une glace ?" /></p>
<p>Lorsque nous réalisons des logiciels en utilisant le <em>paradigme</em> orienté objet, nous travaillons avec des classes, et la majeure partie du temps, nous faisons interagir ces classes entre elles. En pratique, certaines classes sont dépendantes d&#8217;autres classes.</p>
<p>Pour mettre un exemple derrière ces concepts, tout au long de ce document, nous allons nous mettre dans la peau d&#8217;<em>Alice</em>, une jeune fille qui adore manger des glaces, spécialement celles à la fraise !</p>
<p>Certains disent même qu&#8217;Alice est dépendante de la glace à la fraise.</p>
<div class="codecolorer-container php notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">class</span> Alice <span style="color: #009900;">&#123;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> mangerGlace<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$glace</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> GlaceALaFraise<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$glace</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">manger</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>Il est clair, au regard de cette implémentation, qu&#8217;à chaque fois qu&#8217;Alice mange une glace, il s&#8217;agit d&#8217;une glace à la fraise. Génial,  mais un jour, la mère d&#8217;Alice souhaite lui faire découvrir d&#8217;autres parfums&#8230;</p>
<p>En réalité, avec cette implémentation, il est impossible de changer la glace qu&#8217;Alice va manger.</p>
<h2 id="toc-inversion-de-controle-ioc">Inversion de Contrôle (IoC)</h2>
<h3 id="toc-principe">Principe</h3>
<p><img class="alignright" src="http://www.notmyidea.org/wp-content/uploads/2010/07//holywood-principle.png" alt="Don't call me, I'll call you!" /></p>
<p>Il apparait donc nécessaire de supprimer les dépendances entre nos deux classes, pour permettre à Alice de gouter de nouveaux parfums.</p>
<p>Comment ? C&#8217;est assez simple, regardez donc le code:</p>
<div class="codecolorer-container php notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">class</span> Alice <span style="color: #009900;">&#123;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> mangerGlace<span style="color: #009900;">&#40;</span>Glace <span style="color: #000088;">$glace</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$glace</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">manger</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>Quand Alice mange une glace (via la méthode<code>mangerGlace</code>), nous devons lui passer la glace, ce n&#8217;est plus elle qui choisit, <em>nous</em> le faisons à sa place.</p>
<p>Ce principe est connu comme étant <strong>le principe d&#8217;Hollywood</strong>: <em>&laquo;&nbsp;Ne nous appelez pas, nous vous appellerons&raquo;&nbsp;</em>. En d&#8217;autres termes, n&#8217;utilisez pas l&#8217;opérateur<code>new</code>dans vos classes, mais préférez passer (ou qu&#8217;on vous passe) les objets par référence.</p>
<p>Alice peut faire d&#8217;autres choses avec sa glace, la laisser tomber par terre par exemple (oups!), grâce à la méthode<code>lacherGlace()</code>. Nous pouvons alors choisir de passer la glace à cette méthode également, ou choisir de la donner directement à Alice, la laissant s&#8217;occuper du reste, et évitant de lui passer une glace pour chaque action qui en nécessite une.</p>
<div class="codecolorer-container php notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">class</span> Alice <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; protected <span style="color: #000088;">$_glace</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> setGlace<span style="color: #009900;">&#40;</span>Glace <span style="color: #000088;">$glace</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_glace <span style="color: #339933;">=</span> <span style="color: #000088;">$glace</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> mangerGlace<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_glace<span style="color: #339933;">-&gt;</span><span style="color: #004000;">manger</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> lacherGlace<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_glace<span style="color: #339933;">-&gt;</span><span style="color: #004000;">l</span>âcher<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>Il est bien plus facile maintenant de choisir la glace à donner a Alice, et ainsi de contrôler les dépendances d&#8217;Alice vis à vis de la glace.</p>
<p>Ici, il subsiste des dépendances dans le code. Il s’agit de dépendances vis à vis de contrats (interfaces) et non d’implémentations données (classes), puisque j’ai choisi d’utiliser le paradigme de <a href="http://fr.wikipedia.org/wiki/Programmation_par_contrat">programmation par contrats</a>.</p>
<p>Et c&#8217;est tout pour le principe d&#8217;inversion de contrôle (pas les glaces à la fraise, contrôler les dépendances)! Il s&#8217;agit <em>simplement</em> du fait d&#8217;inverser le flux de contrôle de vos application, en déléguant à un plus haut niveau la création des objets.</p>
<h3 id="toc-injection-de-dependances">Injection de dépendances</h3>
<p>Maintenant que le concept d&#8217;inversion de contrôle est clair, expliquons ce qu&#8217;est l&#8217;injection de dépendances. Les deux concepts sont assez proches, et souvent utilisés de pair, mais il est important de bien saisir la frontière entre les deux.</p>
<p>Dans la méthode<code>mangerGlace</code>, nous considérons que la glace en question est déjà donnée à Alice. C&#8217;est un comportement vraiment utile: Nous n&#8217;avons plus à nous occuper de la manière dont la glace est arrivée là, nous l&#8217;avons déjà (dans une propriété privée par exemple).</p>
<p>Dans la section précédente, Alice était <em>dépendante</em> de sa glace. En inversant le flux de contrôle, le comportement d&#8217;Alice vis à vis des glaces est plus facilement contrôlable, et testable (utiliser des <em>mocks</em>, ou <em>bouchons de tests</em> est aussi facile que de régler une propriété, nous parlerons de tests plus tard).</p>
<p>Notre travail (celui de la mère d&#8217;Alice), est de créer les objets et de les passer à Alice. Les <em>injecter</em> est le bon mot. En utilisant des mutateurs, ou en utilisant le constructeur, injectant les objets nécessaires.</p>
<p>Allons-y:</p>
<div class="codecolorer-container php notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000088;">$alice</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Alice<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$glaceAuPat</span>é <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> GlaceAuPaté<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$alice</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setGlace</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$glaceAuPat</span>é<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<p>L&#8217;inversion de contrôle est donc le fait d&#8217;exposer des méthodes publiques (ou des constructeurs) pour régler certaines propriétés, et l&#8217;injection de dépendances est le fait de, justement, injecter ces dépendances, utiliser ces méthodes et constructeurs.</p>
<h3 id="toc-un-conteneur">Un Conteneur ?</h3>
<p>L&#8217;exemple utilisé jusqu&#8217;ici est volontairement simple, et il à été choisi afin d&#8217;expliquer les concepts le plus clairement possible: Nous avons uniquement deux classes, et une dépendance.</p>
<p>En pratique, vous serez surement d&#8217;accord pour dire qu&#8217;un projet est rarement aussi simple. Aussi, dans les projets importants, la gestion du cycle de vie des objets et de l&#8217;injection de leurs propriété peut rapidement devenir un vrai casse tête.</p>
<p>L&#8217;idéal est alors d&#8217;automatiser le processus de création, d&#8217;injection et de gestion de ces cycles de vie. Le conteneur fait exactement ça.</p>
<p>Pourquoi &laquo;&nbsp;conteneur&raquo;&nbsp; ? Parce que la création automatique et l&#8217;injection est effectuée grâce à un objet, qui se charge de contenir toutes les informations sur les dépendances. Une fois les objets crées, le conteneur garde une référence vers ces derniers au cas ou nous en aurions encore besoin (voir la  définition de portée d&#8217;un service &#8211; les &laquo;&nbsp;scopes&raquo;&nbsp;- plus loin)</p>
<p>Le conteneur va donc se charger d&#8217;injecter les objets pour nous, en quelque sorte, il fait le travail de la Mère d&#8217;Alice à sa place.</p>
<p>Nous souhaitons donc que lorsque nous appellerons Alice, via le conteneur, elle nous soit retourné avec une glace prête à être mangée !</p>
<div class="codecolorer-container php notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000088;">$alice</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$container</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getService</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Alice'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$alice</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">mangerGlace</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<p>Ici, le conteneur à injecté la bonne glace à Alice (peu importe laquelle d&#8217;ailleurs, nous souhaitons juste avoir une glace)</p>
<p>Si la glace elle même avait été dépendante d&#8217;autres objets (disons, des noix de coco par exemple), c&#8217;est le rôle du conteneur que de résoudre l&#8217;ensemble des dépendances, dans le bon ordre, simplifiant au maximum la tâche de gestion des dépendances entre les objets et les classes, laissant la tâche simple pour le développeur.</p>
<h2 id="toc-concepts-logiciels">Concepts logiciels</h2>
<p>Maintenant que les concepts d&#8217;inversion de contrôle et d&#8217;injection de dépendances sont clairs (enfin, j&#8217;espère!), nous pouvons commencer à parler de <em>comment</em> nous avons réalisé cette bibliothèque.</p>
<p>Les concepts discutés ici sont des concepts assez simples, dont le principal objectif est de fournir une structure solide aux composants. Chaque composant à ainsi un rôle et un emplacement précis au sein de notre architecture.</p>
<h3 id="toc-le-schema">Le Schéma</h3>
<p><img class="alignright" src="http://www.notmyidea.org/wp-content/uploads/2010/07//schema.png" alt="Le Schéma, avec les services, méthodes, et arguments" /></p>
<p>Dans le schéma, et dans l&#8217;injecteur de dépendances en général, un &laquo;&nbsp;service&raquo;&nbsp; est un objet qui est géré par le conteneur.</p>
<p>Le schéma représente les liens entre les différents services. Il décrit les dépendances de nos objets.</p>
<p>Si vous connaissez le patron de conception de <em>fabrique abstraite</em>, vous pouvez vous représenter le schéma comme une configuration alors que le conteneur serait la fabrique elle même (ou quelque chose d&#8217;approchant).</p>
<p>Le schéma contient toutes les informations sur les méthodes qui doivent êtres appelées pour injecter les objets, le type des arguments qui doivent être passés, et tout autre type d&#8217;information potentiellement utile au moment de l&#8217;injection.</p>
<p>Pour en revenir à notre exemple, le schéma contiendrait des informations sur le type de glace qui doit être passée à Alice (Une glace à la fraise bien sur!), et sur la manière de donner cette glace à Alice (via la méthode<code>setGlace()</code>)</p>
<p>Jusqu&#8217;à maintenant, nous avons parlé de dépendances simples, mais le schéma peut aussi gérer d&#8217;autres types de services, méthodes et arguments. Tout est décrit dans les sections suivantes:<code>Services</code>,<code>Methods</code>et<code>Attibutes</code>.</p>
<h4 id="toc-services">Services</h4>
<p>Un service représente un objet. Dans notre exemple, la Glace et Alice sont des services.</p>
<p>Un service se compose d&#8217;:</p>
<ul>
<li>un nom</li>
<li>un ensemble de méthodes</li>
<li>une manière de se construire</li>
<li>une portée (scope)</li>
</ul>
<p>La portée d&#8217;un service définit comment la durée de vie des services doit être gérée par le conteneur: Est-ce que le service doit rester dans le conteneur pendant toute la durée du script (singleton), ou doit il être systématiquement supprimé après avoir été construit (prototype)? </p>
<p>L&#8217;instance de l&#8217;objet courant peut être la même pour l&#8217;ensemble des services si la portée du service est définie comme étant un <em>singleton</em>, ou être à chaque fois différente si la portée est définie comme <em>prototype</em>.</p>
<p>D&#8217;autres types de portées peuvent êtres imaginées comme une portée de &laquo;&nbsp;session&raquo;&nbsp;, qui retournerait la même instance durant une session unique, ou une sorte de portée &laquo;&nbsp;immortelle&raquo;&nbsp;, qui retournerait toujours le même objet, en faisant persister cet objet à travers différentes sessions.</p>
<p>L&#8217;injecteur de dépendances est fourni avec les types de service suivants:</p>
<p><strong>Défaut</strong> :   Un service &laquo;&nbsp;simple&raquo;&nbsp;, composé de méthodes, et qui peut être construit comment un simple objet.</p>
<p><strong>Alias</strong> :   Un alias vers un autre service. Seul le nom est différent. Ce type de service permet de gérer facilement les dépendances dans le temps. &laquo;&nbsp;Pour le moment, il s&#8217;agit d&#8217;un alias, mais peut être qu&#8217;un jour nous aurons besoin d&#8217;un autre type de service&raquo;&nbsp;.</p>
<p><strong>Héritage de services</strong> :   Plutôt que de se répéter maintes et maintes fois lors de la description de services qui se ressemblent, il est possible d&#8217;utiliser l&#8217;héritage. Cela ressemble grandement à l&#8217;héritage de classes: les méthodes que vous redéfinissez ou ajoutez dans les services enfants écraseront ceux des parents.</p>
<h4 id="toc-methodes">Méthodes</h4>
<p>Chaque service contient des méthodes.</p>
<p>Une méthode permet d&#8217;injecter certains paramètres dans nos services, ou de définir certaines ressources qui doivent être appelées au moment de la construction des services. Dans le cas d&#8217;Alice,<code>setGlace()</code>est une méthode.</p>
<p>Une méthode est composée d&#8217;:</p>
<ul>
<li>un nom,</li>
<li>optionellement, un nom de classe</li>
<li>une liste d&#8217;arguments</li>
<li>une information disant si la méthode est statique ou non</li>
</ul>
<p>Voici les différents types de méthodes actuellement implémentées:</p>
<p><strong>Défaut</strong> :   Une simple méthode, avec des arguments. Peut être une méthode statique</p>
<p><strong>Attributs</strong> :   Utilisé pour régler directement les propriétés en utilisant les attributs publics de l&#8217;objet ($service->attribut = $valeur`).    Ce type de méthode peut contenir uniquement un argument. Il peut paraître étrange de gérer les attributs comme des méthodes. En réalité, il est important de comprendre la différence entre une méthode et un argument. Alors qu&#8217;un argument représente une valeur, une méthode représente une manière d&#8217;utiliser ces arguments. Dès lors, il parait plus logique de gérer les attributs comme des méthodes que comme des arguments.</p>
<p><strong>Rappels (callbacks)</strong> :   Avant ou après la création de vos services, il est possible d&#8217;appeler des méthodes spécifiques, appelées méthodes de rappel.</p>
<h4 id="toc-arguments">Arguments</h4>
<p>Les méthodes contiennent donc des arguments, et il existe plusieurs types d&#8217;arguments également.<br />
Les arguments sont le bout de la chaine services / méthodes / arguments.</p>
<p><strong>Défaut</strong> :   Types PHP natifs (int, string, float etc)</p>
<p><strong>Conteneur</strong> :   Il est possible d&#8217;injecter directement le conteneur. Ce type d&#8217;argument n&#8217;est utilisé que par les services qui nécessitent d&#8217;utiliser le conteneur. Ils sont appelées services &laquo;&nbsp;ContainerAware&raquo;&nbsp;.</p>
<p><strong>Service courant</strong> :   Il est possible d&#8217;injecter le service en cours, et de l&#8217;utiliser comme argument. En pratique, ceci est uniquement utile pour les méthodes de rappel (callback)</p>
<p><strong>Argument vide</strong> :    Il s&#8217;agit d&#8217;un type d&#8217;argument qui na pas de valeur. L&#8217;argument &laquo;&nbsp;conteneur&raquo;&nbsp; et &laquo;&nbsp;service courant&raquo;&nbsp; étendent ce type. Attention, l&#8217;argument vide est différent de null.</p>
<p><strong>Référence à un service</strong> :   C&#8217;est un des types d&#8217;argument le plus utilisé, il représente un autre service.</p>
<p><strong>Argument résolu grâce aux services</strong> :   Parfois, il est utile d&#8217;utiliser un service pour récupérer un argument, je pense à la configuration entres autres. Ce type d&#8217;argument utilise donc une méthode spécifique d&#8217;un autre service pour être résolu.</p>
<h3 id="toc-strategies-de-construction">Stratégies de construction</h3>
<p><img class="alignright" src="http://www.notmyidea.org/wp-content/uploads/2010/07//construction.png" alt="Stratégies de construction" /></p>
<p>Maintenant que nous avons un schéma qui représente les relations entre nos services, nous allons nous occuper de la construction de ces services.</p>
<p>Nous avons choisi de séparer complètement les logiques de construction et de définition, pour permettre de favoriser un maximum d&#8217;usages possibles pour l&#8217;un et l&#8217;autre des composants.</p>
<p>Chaque type, dans le schéma, peut être lié à un type de stratégie pour se construire. Il y à donc plusieurs stratégies de construction pour les services, les méthodes et les arguments.</p>
<p>L&#8217;intérêt d&#8217;utiliser des stratégies de construction est de permettre à chacun de nos types, dans le schéma, de se construire <em>eux même</em>, en utilisant leur méthode<code>build()</code>, qui va elle déléguer la tache de construction aux stratégies.</p>
<p>En interne, il est possible d&#8217;utiliser des stratégies de construction différentes, et d&#8217;en changer à tout moment. Ce comportement suit, en fait, <a href="http://fr.wikipedia.org/wiki/Strat%C3%A9gie_(patron_de_conception)">le patron de conception stratégie</a>.</p>
<h3 id="toc-builders-monteurs"><em>Builders</em> / Monteurs</h3>
<p>Puisque nous parlons de patrons de conception (design patterns), parlons du motif &laquo;&nbsp;Monteur&raquo;&nbsp;.</p>
<p>Vous serez sans doute d&#8217;accord avec moi pour dire qu&#8217;écrire un schéma entièrement à la main, en utilisant les classes dont nous avons parlé un peu plus haut peut s&#8217;avérer rapidement assez pénible. En tout cas, pour l&#8217;avoir expérimenté lors de l&#8217;écriture des tests, je peux dire qu&#8217;il ne s&#8217;agit pas d&#8217;un gain de temps, loin de là.</p>
<p>Une solution pratique consiste à utiliser le motif <em>Monteur</em>. L&#8217;idée est d&#8217;écrire le schéma sous une forme sympathique et facile à écrire pour nous, développeurs, et d&#8217;utiliser une classe intermédiaire pour transformer notre représentation du schéma dans la représentation compréhensible par notre composant.</p>
<p>Cette classe intermédiaire <em>monte</em> donc notre schéma, en déchiffrant une autre structure.</p>
<p><img class="alignright" src="http://www.notmyidea.org/wp-content/uploads/2010/07//builders.png" alt="Builders" /></p>
<p>Le premier type de <em>monteur</em> qui me vient à l&#8217;esprit (le plus pratique, en fait), est le <em>monteur</em> XML. Il est capable de lire un schéma, décrit au format XML, et de construire le schéma en utilisant les objets de notre bibliothèque. L&#8217;écriture du schéma XML à plusieurs avantages: il est facile à écrire, permet d&#8217;utiliser des outils extérieurs pour l&#8217;éditer facilement, et bénéficie, grâce a <a href="http://fr.wikipedia.org/wiki/XML_Schema">XML Schema</a>, d&#8217;une auto-complétion et d&#8217;une vérification à la volée, lors de l&#8217;écriture.</p>
<p>Les injecteurs de dépendances <a href="http://code.google.com/p/google-guice/">Google Juice</a> et <a href="www.springsource.org">Spring</a> permettent l&#8217;utilisation des annotations directement dans le code, pour définir les règles d&#8217;injection (le schéma pour nous).</p>
<p>Bien qu&#8217;il ne s&#8217;agisse pas d&#8217;un comportement recommandé (les annotations ne sont exploitables que par un type d&#8217;injecteur, même si <a href="http://jcp.org/en/jsr/summary?id=dependency+injection">une spécification est actuellement en cours</a>), il est possible d&#8217;utiliser la réflexion sur un projet, et de la combiner a l&#8217;utilisation d&#8217;annotations pour déduire facilement la structure de notre schéma, pour le remplir ensuite à notre guise.</p>
<p>Ce composant est également un <em>monteur</em>.</p>
<p>Les monteurs suivants sont fournis de base:</p>
<ul>
<li>Le monteur XML</li>
<li>Le monteur PHP, qui utilise une interface fluide, pour permettre des configurations de ce type:<code>$monteur->addService()->withMethod()</code></li>
<li>Le monteur Réflexion (utilise la réflexion sur nos classes pour construire un schéma)</li>
</ul>
<h3 id="toc-dumpers"><em>Dumpers</em></h3>
<p>Un <em>dumper</em> est un objet qui copie des données d&#8217;un type de format vers un autre. Effectivement, il peut s&#8217;avérer utile d&#8217;avoir une manière simple de se représenter un schéma déjà défini.</p>
<p><img class="alignright" src="http://www.notmyidea.org/wp-content/uploads/2010/07//dumpers.png" alt="Dumpers" /></p>
<p>Les dumpers permettent par exemple de représenter un schéma sous une forme graphique, ou bien sous une forme plus compréhensible pour nous, avec un simple texte par exemple.</p>
<p>Il est donc vraiment facile de montrer les dépendances de vos projets, en utilisant simplement le dumper Dot (qui est le format utilisé par <a href="www.graphviz.com">graphviz</a>) par exemple.</p>
<p>Voici la liste des dumpers :</p>
<ul>
<li>Le dumper texte</li>
<li>Le dumper Dot (graphviz)</li>
<li>Le dumper XML</li>
<li>Le dumper PHP</li>
</ul>
<p>Ces deux composants laissent entrevoir des pistes intéressantes: il est possible d&#8217;écrire ses classes, puis de générer un schéma partiel grâce au monteur &laquo;&nbsp;réflexion&raquo;&nbsp;, de le <em>dumper</em> en XML, de le compléter à la main (avec de l&#8217;auto-complétion), et de le monter à nouveau, grâce au monteur XML.</p>
<h2 id="toc-implementation">Implémentation</h2>
<p>Voici quelques règles que nous avons suivi lors du développement en lui même:</p>
<h3 id="toc-espaces-de-noms-php-5-3">Espaces de noms / PHP 5.3</h3>
<p>Alors que nous nous penchions sur ce projet, PHP 5.3 n&#8217;était pas encore sorti, mais puisque cette version apportait des fonctionnalités vraiment intéressantes (late static binding, espaces de noms et closures), nous avons choisi d&#8217;utiliser alors la version en cours de développement de PHP 5.3.</p>
<p>Maintenant, PHP 5.3 est disponible en version stable, et permet de faire fonctionner notre projet.</p>
<p>Notre bibliothèque se sépare selon les espaces de noms suivants:</p>
<ul>
<li>L&#8217;espace de nom<code>Construction</code>, qui contient toutes les classes liées au concept de construction (les stratégies de construction)</li>
<li>L&#8217;espace de nom<code>Definition</code>, qui contient le schéma.</li>
<li>L&#8217;espace de nom<code>Transformation</code>qui contient les Dumpers et les <em>Monteurs</em></li>
</ul>
<h3 id="toc-developpement-pilote-par-les-tests-tdd">Développement piloté par les tests (TDD)</h3>
<p>Ce projet fut également l&#8217;occasion d&#8217;écrire nos premiers tests, pour finir par utiliser une approche pilotée par les tests.</p>
<p>Le développement piloté par les tests préconise de réaliser ses tests <strong>avant</strong> d&#8217;écrire ses classes. Au début, ça chatouille un peu, mais on comprend rapidement l&#8217;intérêt de cette méthodologie, qui est une vraie bonne pratique.</p>
<p>Écrire ses tests avant d&#8217;avoir codé la classe nous oblige à la fois à privilégier une utilisation logique de nos composants, et à fixer les interfaces. Le code produit est réellement comme on souhaite l&#8217;utiliser, et non pas comme il est plus facile de l&#8217;implémenter.</p>
<p>Écrire des tests, c&#8217;est aussi penser à l&#8217;ensemble des scénarios d&#8217;utilisation de ces classes, même les plus farfelus. Cela nous oblige à réfléchir à tous ces cas d&#8217;utilisation, et ça fait le plus grand bien !</p>
<p>Pour revenir aux tests, ils permettent de tester que notre application se comporte bien comme elle le devrait, mais cela permet aussi de détecter rapidement des régressions que de nouvelles fonctionnalités peuvent apporter.</p>
<p>Rapidement, on écrit des tests pour tout: bugs, idées, etc. Ça favorise vraiment le développement d&#8217;une application.</p>
<p>Un peu plus haut, je parlais de Mock objets (ou objets bouchon, en français). Je vous laisse consulter l&#8217;<a href="http://en.wikipedia.org/wiki/Mock_object">article wikipédia sur les mocks</a> pour vous faire une idée plus précise, mais il s&#8217;agit, rapidement, d&#8217;objets qui permettent de simuler le comportement d&#8217;autres objets, ces derniers pouvant communiquer avec la suite de tests.</p>
<h3 id="toc-interfaces">Interfaces</h3>
<p>Dans l&#8217;ensemble de nos classes, nous essayons d&#8217;utiliser des interfaces plutôt que des implémentations particulières.<br />
Pourquoi ? Parce que travailler avec des interfaces nous permet de changer à tout moment d&#8217;implémentation !</p>
<p>Dans le cas d&#8217;Alice, elle n&#8217;est pas dépendante d&#8217;un type particulier de glace (celle à la fraise), mais simplement aux glaces, à l&#8217;<em>interface</em><code>Glace</code>, pour être exact.</p>
<p>Chacune des interfaces ci dessous représente un comportement décrit plus haut:</p>
<ul>
<li>Schema</li>
<li>Service</li>
<li>Method</li>
<li>Argument</li>
<li>Container</li>
<li>Dumper</li>
<li>Builder</li>
</ul>
<h3 id="toc-lecriture-des-classes">L&#8217;écriture des classes</h3>
<p>Pour écrire nos classes, et parce que nous souhaitons fournir un système facilement extensible, nous fournissons quasi systématiquement une interface, et une classe abstraite, pour que chaque concept puisse être étendu facilement.</p>
<p>D&#8217;ailleurs, l&#8217;écriture des classes en elle même est assez simple, une fois que tous les concepts ont étés décrit et sont clairs.</p>
<p>Vous pouvez regarder le code sur <a href="http://bitbucket.org/ametaireau/spiral/src/">le dépôt mercurial de spiral</a></p>
<p>Je ne vois pas grand chose à ajouter à propos de l&#8217;implémentation, si ce n&#8217;est, peut être, qu&#8217;il est indispensable de commenter votre code: cela permet aux potentiels futur contributeurs de s&#8217;y retrouver facilement, et de comprendre le détail des opérations !</p>
<h2 id="toc-conclusion">Conclusion</h2>
<p>J&#8217;espère que cet article vous aura intéressé, en tout cas j&#8217;ai pris beaucoup de plaisir à l&#8217;écrire, et vous aurez au moins appris comment nous avons choisi d&#8217;implémenter un injecteur de dépendances en utilisant quelques bonnes pratiques logicielles !</p>
]]></content:encoded>
			<wfw:commentRss>http://www.notmyidea.org/article/realiser-un-injecteur-de-dependances-en-utilisant-de-bonnes-pratiques-logicielles/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Dependency Injection &#8211; Using SpiralDi Container</title>
		<link>http://www.notmyidea.org/article/en-introduction-to-spiral-dependency-injection-container-in-php/</link>
		<comments>http://www.notmyidea.org/article/en-introduction-to-spiral-dependency-injection-container-in-php/#comments</comments>
		<pubDate>Tue, 23 Jun 2009 09:10:26 +0000</pubDate>
		<dc:creator>Alexis Metaireau</dc:creator>
				<category><![CDATA[Architecture logicielle]]></category>
		<category><![CDATA[php-en]]></category>
		<category><![CDATA[Dependency Injection]]></category>
		<category><![CDATA[IoC]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[spiral]]></category>

		<guid isPermaLink="false">http://www.notmyidea.org/?p=226</guid>
		<description><![CDATA[Please note that this article is also available in French. A big thanks to Frédéric Sureau for his translation work on the English version.
Since my previous article (FR), I have kept on working on the dependencies injector of Spiral, wich I just published in a standalone version.
Here is an overview of SpiralDi functionnalities, and some [...]]]></description>
			<content:encoded><![CDATA[<p class="info">Please note that this article is also <a href="http://www.notmyidea.org/article/fr-introduction-to-spiral-dependency-injection-container-in-php">available in French</a>. A big thanks to Frédéric Sureau for his translation work on the English version.</p>
<p>Since my <a href="http://www.notmyidea.org/article/dependency-injection-singleton-design-pattern-ioc-dendencies-dependences/">previous article (FR)</a>, I have kept on working on the dependencies injector of <a href="http://bitbucket.org/ametaireau/spiral/wiki/Home">Spiral</a>, wich I just published in a <a href="http://bitbucket.org/ametaireau/spiraldi/"><em>standalone</em> version</a>.</p>
<p>Here is an overview of SpiralDi functionnalities, and some examples on the use.<br />
<span id="more-226"></span></p>
<h2>Table des matières</h2>
<div class="toc">
<ol>
<li><a href="http://www.notmyidea.org/article/en-introduction-to-spiral-dependency-injection-container-in-php/#toc-overview">Overview</a></li>
<li><a href="http://www.notmyidea.org/article/en-introduction-to-spiral-dependency-injection-container-in-php/#toc-principles">Principles</a>
<ol>
<li><a href="http://www.notmyidea.org/article/en-introduction-to-spiral-dependency-injection-container-in-php/#toc-services-scope">Services scope</a></li>
</ol>
</li>
<li><a href="http://www.notmyidea.org/article/en-introduction-to-spiral-dependency-injection-container-in-php/#toc-advanced-use">Advanced use</a>
<ol>
<li><a href="http://www.notmyidea.org/article/en-introduction-to-spiral-dependency-injection-container-in-php/#toc-using-references-and-methodfactory">Using references and <em>MethodFactory</em></a></li>
<li><a href="http://www.notmyidea.org/article/en-introduction-to-spiral-dependency-injection-container-in-php/#toc-inheriting-and-overloading-services">Inheriting and overloading services</a></li>
<li><a href="http://www.notmyidea.org/article/en-introduction-to-spiral-dependency-injection-container-in-php/#toc-container-aware">Container Aware</a></li>
</ol>
</li>
<li><a href="http://www.notmyidea.org/article/en-introduction-to-spiral-dependency-injection-container-in-php/#toc-factories">Factories</a></li>
<li><a href="http://www.notmyidea.org/article/en-introduction-to-spiral-dependency-injection-container-in-php/#toc-download-it">Download it ! </a>
<ol>
<li><a href="http://www.notmyidea.org/article/en-introduction-to-spiral-dependency-injection-container-in-php/#toc-via-the-mercurial-repository">Via the mercurial repository</a></li>
<li><a href="http://www.notmyidea.org/article/en-introduction-to-spiral-dependency-injection-container-in-php/#toc-via-the-archives">Via the archives</a></li>
</ol>
</li>
<li><a href="http://www.notmyidea.org/article/en-introduction-to-spiral-dependency-injection-container-in-php/#toc-interesting-readings">Interesting readings</a></li>
<li><a href="http://www.notmyidea.org/article/en-introduction-to-spiral-dependency-injection-container-in-php/#toc-going-further">Going further ?</a></li>
</ol>
</div>
<h2 id="toc-overview">Overview</h2>
<p>SpiralDi comes with a lot of new features, some of them inspired by the excellent Java framework : Spring. It is now possible to :</p>
<ul>
<li>Use <em>factories</em> to set the parameters values (useful for configuration)</li>
<li>Use an inheritance system to make configuration file more clear</li>
<li>Use <em>factories</em> for the construction of the services</li>
<li>Directly inject the container in <em>ContainerAware</em> services</li>
</ul>
<p>But, maybe, it doesn&#8217;t mean anything for you ? I will explain the details further later.</p>
<h2 id="toc-principles">Principles</h2>
<p>If you don&#8217;t know much about the inversion of control, I advise you to read my <a href="http://www.notmyidea.org/article/dependency-injection-singleton-design-pattern-ioc-dendencies-dependences/">introduction on the dependencies injection (FR)</a>.</p>
<p>The use of a lightweight container is done in two steps :</p>
<ul>
<li>The description of the <em>schema</em> of all the services that will be used later</li>
<li>The call (so, the construction) of these services via the <em>container</em></li>
</ul>
<p>The SpiralDi library let you describe the <em>Schema</em> in different ways. The sexiest is probably the XML description file, but it is also possible to define this <em>Schema</em> using the PHP language if you think it&#8217;s more convenient. The following examples are in XML. Here is a quite simple definition file, that describe two services :</p>
<div class="codecolorer-container xml notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt; ?xml <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;1.0&quot;</span> <span style="color: #000066;">encoding</span>=<span style="color: #ff0000;">&quot;UTF-8&quot;</span><span style="color: #000000; font-weight: bold;">?&gt;</span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;container<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;service</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;db&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;Database&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;constructor<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;argument</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;localhost&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;argument</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;root&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;argument</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;password&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/constructor<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/service<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;service</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;user&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;User&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;method</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;setDb&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;argument</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;service&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;db&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/method<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/service<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/container<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></div>
<p>Once this file is written, you have to transform it in a SpiralDi understandable format : the Schema.</p>
<div class="codecolorer-container php notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000088;">$builder</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> SpiralDi_SchemaBuilder_Xml<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$builder</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setFileName</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;schema.xml&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$schema</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$builder</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">buildSchema</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<p>You can now exploit the built Schema. The Schema is first used to resolve objects. We will see later that it has much more aims. Now, pass this <em>Schema</em> to the <em>Container</em> :</p>
<div class="codecolorer-container php notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666; font-style: italic;">// construction of the container</span><br />
<span style="color: #000088;">$container</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> SpiralDi_Container_Default<span style="color: #009900;">&#40;</span><span style="color: #000088;">$schema</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #666666; font-style: italic;">// getting the desired service</span><br />
<span style="color: #000088;">$myUser</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$container</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">user</span><span style="color: #339933;">;</span></div></div>
<p>This looks sexy, isn&#8217;t it ? The container has done everything ! Resolution of the object&#8217;s dependencies and injection of these dependencies when needed.</p>
<h3 id="toc-services-scope">Services scope</h3>
<p>All services constructed by SpiralDi have a controlled life time.<br />
In the default behavior, the container will return the same instance of the object, each time the service is needed. This is the <em>singleton</em> scope.<br />
All services are by default configured to have the <em>singleton</em> scope.</p>
<p>You can also use the <em>prototype</em> scope to make the container create a new instance each time the service is needed.</p>
<p>To change the scope of the service, you can use the property</p>
<div class="codecolorer-container text notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">scope=&quot;prototype&quot;</div></div>
<p>in the XML file.</p>
<h2 id="toc-advanced-use">Advanced use</h2>
<p>Now, you know how to describe &laquo;&nbsp;basic&raquo;&nbsp; services and their dependencies. Let&#8217;s see now, more complex features.</p>
<h3 id="toc-using-references-and-methodfactory">Using references and <em>MethodFactory</em></h3>
<p>Sometimes, you will need to inject parameters in a dynamic manner. Imagine that you don&#8217;t know the value of a parameter that you want to inject because it is stored in a configuration object for example.</p>
<p>So, we want the container to construct our services using information from a <em>Config</em> object. The container is able to generate automatically the following code for us :</p>
<div class="codecolorer-container php notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000088;">$config</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Config<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$service</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Db<span style="color: #009900;">&#40;</span><span style="color: #000088;">$config</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">host</span><span style="color: #339933;">,</span> <span style="color: #000088;">$config</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">user</span><span style="color: #339933;">,</span> <span style="color: #000088;">$config</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">password</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<p>For this, we have to use the system of references :</p>
<div class="codecolorer-container xml notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;service</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;db&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;Database&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;constructor<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;argument</span> <span style="color: #000066;">ref</span>=<span style="color: #ff0000;">&quot;config&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;host&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;argument</span> <span style="color: #000066;">ref</span>=<span style="color: #ff0000;">&quot;config&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;user&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;argument</span> <span style="color: #000066;">ref</span>=<span style="color: #ff0000;">&quot;config&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;password&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/constructor<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/service<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></div>
<p>It is also possible to specify the method that will be used to get arguments. For example</p>
<div class="codecolorer-container text notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">getParam()</div></div>
<p>will produce something like this :</p>
<div class="codecolorer-container php notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000088;">$config</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Config<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$service</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Db<span style="color: #009900;">&#40;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$config</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getParam</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;host&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; <span style="color: #000088;">$config</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getParam</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;user&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; <span style="color: #000088;">$config</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getParam</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;password&quot;</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<p>The corresponding XML code will be :</p>
<div class="codecolorer-container xml notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;argument</span> <span style="color: #000066;">ref</span>=<span style="color: #ff0000;">&quot;config&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;host&quot;</span> <span style="color: #000066;">factoryMethod</span>=<span style="color: #ff0000;">&quot;getParam&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span></div></div>
<h3 id="toc-inheriting-and-overloading-services">Inheriting and overloading services</h3>
<p>Quite often, some services are similar. It is possible to use the inheritance system to make the services description lighter.<br />
This is not an actual inheritance between classes, but only the inheritance principle. Thus, you can extend a service description, which make the description file more readable and easier to understand.</p>
<div class="codecolorer-container xml notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;service</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;extendedService&quot;</span> <span style="color: #000066;">extends</span>=<span style="color: #ff0000;">&quot;config&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;method</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;method2&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;argument</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;value&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/method<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/service<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></div>
<h3 id="toc-container-aware">Container Aware</h3>
<p>In some cases, services have to know the existence of the container, and need to access to it. It is easy to inject the container in a service by using the &laquo;&nbsp;container&raquo;&nbsp; type or the facility &laquo;&nbsp;containerAware&raquo;&nbsp; :</p>
<div class="codecolorer-container xml notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;service</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;containerAwareService&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;Service&quot;</span> <span style="color: #000066;">containerAware</span>=<span style="color: #ff0000;">&quot;true&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
<span style="color: #808080; font-style: italic;">&lt;!-- is exactly the same as --&gt;</span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;service</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;containerAwareService&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;Service&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;method</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;setDiContainer&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;argument</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;container&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/method<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/service<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></div>
<p>From the class&#8217; point of view, you only have to implement the <em>SpiralDi_ContainerAware</em> interface. In this way, during the construction of the service, the <em>setDiContainer</em> method of your class will be automatically called.</p>
<p>As well, in this case, there is no need to explicitly name your service as &laquo;&nbsp;ContainerAware&raquo;&nbsp; in the description file, the container will automatically detect it</p>
<h2 id="toc-factories">Factories</h2>
<p>SpiralDi also provides a convenient way to use Factories from the DI. This helps generating behaviors like :</p>
<div class="codecolorer-container php notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000088;">$service</span> <span style="color: #339933;">=</span> MyServiceFactory<span style="color: #339933;">::</span><span style="color: #004000;">createService</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<p>The corresponding XML code is :</p>
<div class="codecolorer-container xml notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;service</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;serviceFactory&quot;</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;factory&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;MyServiceFactory&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;method</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;createService&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/service<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></div>
<p>This should be nice if you want to reuse your old Singleton implementations, among other things&#8230;</p>
<div class="codecolorer-container xml notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;service</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;singleton&quot;</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;factory&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;Mysingleton&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;method</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;getInstance&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/service<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></div>
<h2 id="toc-download-it">Download it ! </h2>
<p>Convinced ? To get the latest version of SpiralDi, you have many solutions :</p>
<h3 id="toc-via-the-mercurial-repository">Via the mercurial repository</h3>
<div class="codecolorer-container bash notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">hg clone https:<span style="color: #000000; font-weight: bold;">//</span>ametaireau<span style="color: #000000; font-weight: bold;">@</span>bitbucket.org<span style="color: #000000; font-weight: bold;">/</span>ametaireau<span style="color: #000000; font-weight: bold;">/</span>spiraldi<span style="color: #000000; font-weight: bold;">/</span></div></div>
<h3 id="toc-via-the-archives">Via the archives</h3>
<p>The code is available in the following formats : <a href="http://bitbucket.org/ametaireau/spiraldi/get/tip.zip">zip</a>, <a href="http://bitbucket.org/ametaireau/spiraldi/get/tip.gz">gz</a> ou <a href="http://bitbucket.org/ametaireau/spiraldi/get/tip.bz2">bz2</a></p>
<p>You can also <a href="http://bitbucket.org/ametaireau/spiraldi/">directly check the repository</a>.</p>
<p>That&#8217;s all ! You can now have fun using it ! For functionnality requests, bug report, etc. <a href="http://bitbucket.org/ametaireau/spiraldi/issues/new/">Please</a> !</p>
<h2 id="toc-interesting-readings">Interesting readings</h2>
<p>If you want to know more about dependencies injection, here are some interesting readings on the subject :</p>
<ul>
<li><a href="http://www.martinfowler.com/articles/injection.html">Martin Fowler&#8217;s article on dependencies injection</a></li>
<li>Fabien potencier&#8217;s suite of articles (<a href="http://fabien.potencier.org/article/11/what-is-dependency-injection">1</a>,<a href="http://fabien.potencier.org/article/12/do-you-need-a-dependency-injection-container">2</a>,<a href="http://fabien.potencier.org/article/13/introduction-to-the-symfony-service-container">3</a>,<a href="http://fabien.potencier.org/article/14/symfony-service-container-using-a-builder-to-create-services">4</a>,<a href="http://github.com/fabpot/Pimple/tree/master">5</a>)</li>
<li>Another one from Padraic Brady (<a href="http://blog.astrumfutura.com/archives/394-The-Case-For-Dependency-Injection-Part-1.html">1</a>,<a href="http://blog.astrumfutura.com/archives/395-The-Case-For-Dependency-Injection-Part-2.html">2</a>) </li>
<li>Fabien Potencier has also published a di container <a href="http://twittee.org/">that feet in a tweet</a>. to see, just for fun <img src='http://www.notmyidea.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </li>
</ul>
<h2 id="toc-going-further">Going further ?</h2>
<p>SpiralDi is of course not the only PHP lightweight container. Recently, a lot of container are flowering on the web. Frameworks like Symfony and Flow3<sup>1</sup> are giving a good place to DI. So much the better !</p>
<ul>
<li><a href="http://svn.symfony-project.com/components/dependency_injection/">Symfony&#8217;s services container</a></li>
<li><a href="http://github.com/beberlei/yadif/tree/master">Yadim</a></li>
<li><a href="http://flow3.typo3.org/documentation/reference/object/">Flow3 Objects</a></li>
<li><a href="http://www.beberlei.de/sphicy/">Sphicy</a></li>
<li><a href="http://www.sourceforge.net/projects/phemto">Phemto</a></li>
<li><a href="http://www.seasar.org/en/php5/DIContainer.html">Seasar</a></li>
<li><a href="http://garden.tigris.org/">Garden</a></li>
<li><a href="http://en.wikipedia.org/wiki/Xyster_Framework">Xyster</a></li>
<li><a href="http://www.lionframework.org/">Lion</a></li>
</ul>
<ol class="footnotes"><li id="footnote_0_226" class="footnote">It is new, beautiful, written for PHP 5.3, using AOP, <em>Domain Model</em> persistence&#8230; and of course dependencies injection ! Keep an eye on it : <a href="http://flow3.typo3.org/">Flow3 </a></li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.notmyidea.org/article/en-introduction-to-spiral-dependency-injection-container-in-php/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Injection de dépendances &#8211; Utilisation du SpiralDi Container</title>
		<link>http://www.notmyidea.org/article/fr-introduction-to-spiral-dependency-injection-container-in-php/</link>
		<comments>http://www.notmyidea.org/article/fr-introduction-to-spiral-dependency-injection-container-in-php/#comments</comments>
		<pubDate>Tue, 23 Jun 2009 09:05:38 +0000</pubDate>
		<dc:creator>Alexis Metaireau</dc:creator>
				<category><![CDATA[Architecture logicielle]]></category>
		<category><![CDATA[php-fr]]></category>
		<category><![CDATA[Injection de dépendances]]></category>
		<category><![CDATA[IoC]]></category>
		<category><![CDATA[spiral]]></category>

		<guid isPermaLink="false">http://www.notmyidea.org/?p=189</guid>
		<description><![CDATA[Cet article est également disponible en version anglaise. Un grand merci à Frédéric Sureau pour son travail de traduction.
Suite à mon précédent article, j&#8217;ai continué à travailler sur l&#8217;injecteur de dépendances de Spiral, que je viens de publier dans une version standalone. 
Voici un tour d&#8217;horizon des fonctionnalités apportées par SpiralDi, ainsi que quelques exemples [...]]]></description>
			<content:encoded><![CDATA[<p class="info">Cet article est également <a href="http://www.notmyidea.org/article/en-introduction-to-spiral-dependency-injection-container-in-php">disponible en version anglaise</a>. Un grand merci à Frédéric Sureau pour son travail de traduction.</p>
<p>Suite à mon <a href="http://www.notmyidea.org/article/dependency-injection-singleton-design-pattern-ioc-dendencies-dependences/">précédent article</a>, j&#8217;ai continué à travailler sur l&#8217;injecteur de dépendances de <a href="http://bitbucket.org/ametaireau/spiral/wiki/Home">Spiral</a>, que je viens de publier dans une <a href="http://bitbucket.org/ametaireau/spiraldi/">version <em>standalone</em></a>. </p>
<p>Voici un tour d&#8217;horizon des fonctionnalités apportées par SpiralDi, ainsi que quelques exemples d&#8217;utilisation.<br />
<span id="more-189"></span></p>
<h2>Table des matières</h2>
<div class="toc">
<ol>
<li><a href="http://www.notmyidea.org/article/fr-introduction-to-spiral-dependency-injection-container-in-php/#toc-tour-dhorizon">Tour d&#8217;horizon</a></li>
<li><a href="http://www.notmyidea.org/article/fr-introduction-to-spiral-dependency-injection-container-in-php/#toc-principes">Principes</a>
<ol>
<li><a href="http://www.notmyidea.org/article/fr-introduction-to-spiral-dependency-injection-container-in-php/#toc-portee-des-services-scopes">Portée des services (Scopes)</a></li>
</ol>
</li>
<li><a href="http://www.notmyidea.org/article/fr-introduction-to-spiral-dependency-injection-container-in-php/#toc-utilisation-avancee">Utilisation &laquo;&nbsp;avancée&raquo;&nbsp;</a>
<ol>
<li><a href="http://www.notmyidea.org/article/fr-introduction-to-spiral-dependency-injection-container-in-php/#toc-utilisation-des-references-et-des-methodfactory">Utilisation des Références et des <em>MethodFactory</em></a></li>
<li><a href="http://www.notmyidea.org/article/fr-introduction-to-spiral-dependency-injection-container-in-php/#toc-heritage-et-surcharge-de-services">Héritage et surcharge de services</a></li>
<li><a href="http://www.notmyidea.org/article/fr-introduction-to-spiral-dependency-injection-container-in-php/#toc-container-aware">Container Aware</a></li>
</ol>
</li>
<li><a href="http://www.notmyidea.org/article/fr-introduction-to-spiral-dependency-injection-container-in-php/#toc-factories">Factories</a></li>
<li><a href="http://www.notmyidea.org/article/fr-introduction-to-spiral-dependency-injection-container-in-php/#toc-telechargez-le">Téléchargez le ! </a>
<ol>
<li><a href="http://www.notmyidea.org/article/fr-introduction-to-spiral-dependency-injection-container-in-php/#toc-via-le-depot-mercurial">Via le dépôt mercurial</a></li>
<li><a href="http://www.notmyidea.org/article/fr-introduction-to-spiral-dependency-injection-container-in-php/#toc-via-les-archives">Via les archives</a></li>
</ol>
</li>
<li><a href="http://www.notmyidea.org/article/fr-introduction-to-spiral-dependency-injection-container-in-php/#toc-et-ailleurs">Et ailleurs ?</a></li>
<li><a href="http://www.notmyidea.org/article/fr-introduction-to-spiral-dependency-injection-container-in-php/#toc-lectures-interessantes">Lectures intéressantes</a></li>
</ol>
</div>
<h2 id="toc-tour-dhorizon">Tour d&#8217;horizon</h2>
<p>SpiralDi arrive avec son lot de nouveautés, pour certaines inspirées de l&#8217;excellent framework Java Spring. Il est désormais possible, en vrac, de:</p>
<ul>
<li>Utiliser des <em>factories</em> pour renseigner les valeurs des parametres (pratique pour la configuration)</li>
<li>Utiliser un système d&#8217;héritage, pour alléger les fichiers de configuration</li>
<li>Utiliser des <em>Factories</em> pour résoudre les services</li>
<li>Injecter directement le conteneur à certains services, dits <em>ContainerAware</em></li>
</ul>
<p>Mais peut être que ça ne vous parles pas trop, nous y reviendrons tout à l&#8217;heure.</p>
<h2 id="toc-principes">Principes</h2>
<p>Si vous n&#8217;êtes pas à l&#8217;aise avec le principe d&#8217;inversion de contrôle, je vous conseille d&#8217;aller lire mon <a href="http://www.notmyidea.org/article/dependency-injection-singleton-design-pattern-ioc-dendencies-dependences/">introduction sur l&#8217;injection de dépendances</a>.</p>
<p>L&#8217;utilisation d&#8217;un conteneur léger se fait toujours en deux étapes:</p>
<ul>
<li>La description et le renseignement du <em>schéma</em> de services qui pourront être utilisés par la suite</li>
<li>la demande de résolution de ces derniers, via le <em>conteneur</em></li>
</ul>
<p>SpiralDi fournit plusieurs manières de décrire le <em>Schema</em>. La plus appropriée est surement l&#8217;XML, mais il est également possible de passer via du PHP si cela vous semble plus pratique. Nous prendrons ici l&#8217;exemple du XML. Voici un fichier de description assez simple, qui décrit deux services:</p>
<div class="codecolorer-container xml notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt; ?xml <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;1.0&quot;</span> <span style="color: #000066;">encoding</span>=<span style="color: #ff0000;">&quot;UTF-8&quot;</span><span style="color: #000000; font-weight: bold;">?&gt;</span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;container<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;service</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;db&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;Database&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;constructor<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;argument</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;localhost&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;argument</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;root&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;argument</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;password&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/constructor<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/service<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;service</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;user&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;User&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;method</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;setDb&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;argument</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;service&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;db&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/method<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/service<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/container<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></div>
<p>Une fois le fichier écrit, il faut le transformer dans un format compréhensible par SpiralDi: le Schema.</p>
<div class="codecolorer-container php notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000088;">$builder</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> SpiralDi_SchemaBuilder_Xml<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$builder</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setFileName</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;schema.xml&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$schema</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$builder</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">buildSchema</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<p>Nous pouvons désormais exploiter notre Schema. La première utilité d&#8217;un Schéma est d&#8217;être utilisé pour résoudre nos objets. Nous verrons un peu plus tard qu&#8217;il peut avoir d&#8217;autres utilités. Passons donc le <em>Schema</em> au <em>Conteneur</em>:</p>
<div class="codecolorer-container php notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666; font-style: italic;">// construction du conteneur</span><br />
<span style="color: #000088;">$container</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> SpiralDi_Container_Default<span style="color: #009900;">&#40;</span><span style="color: #000088;">$schema</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #666666; font-style: italic;">// récupération du service souhaité</span><br />
<span style="color: #000088;">$myUser</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$container</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">user</span><span style="color: #339933;">;</span></div></div>
<p>Plutôt sympa non? Le conteneur s&#8217;est occupé de tout: résolution des dépendances de l&#8217;objet, et injection de ces dernières quand nécessaire.</p>
<h3 id="toc-portee-des-services-scopes">Portée des services (Scopes)</h3>
<p>Les services construits via SpiralDi ont une durée de vie contrôlée.<br />
Par défaut, plusieurs demandes au conteneur pour un même service retournerons la même instance de l&#8217;objet, il s&#8217;agit de la portée de type <em>singleton</em>.<br />
Le conteneur est configuré par défaut pour que les services qu&#8217;ils crée aient une portée de type <em>singleton</em>.</p>
<p>Il est possible d&#8217;utiliser la portée <em>prototype</em> pour qu&#8217;un nouvel objet soit créé à chaque appel du service, en utilisant la propriété</p>
<div class="codecolorer-container text notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">scope=&quot;prototype&quot;</div></div>
<p>dans le fichier XML.</p>
<h2 id="toc-utilisation-avancee">Utilisation &laquo;&nbsp;avancée&raquo;&nbsp;</h2>
<p>Vous savez désormais comment décrire &laquo;&nbsp;basiquement&raquo;&nbsp; vos services et leurs dépendances. Voyons maintenant quelques concepts un peu plus poussés.</p>
<h3 id="toc-utilisation-des-references-et-des-methodfactory">Utilisation des Références et des <em>MethodFactory</em></h3>
<p>Il peut arriver que l&#8217;on ai besoin d&#8217;injecter des paramètres de manière dynamique. Imaginez que vous ne connaissiez pas la valeur des paramètres à injecter, ceux-ci étant contenus dans un objet de configuration par exemple.</p>
<p>Nous souhaitons donc que le conteneur construise nos objets en utilisant des informations contenues dans la configuration. Le conteneur est donc capable de s&#8217;occuper de générer le code suivant à notre place:</p>
<div class="codecolorer-container php notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000088;">$config</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Config<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$service</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Db<span style="color: #009900;">&#40;</span><span style="color: #000088;">$config</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">host</span><span style="color: #339933;">,</span> <span style="color: #000088;">$config</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">user</span><span style="color: #339933;">,</span> <span style="color: #000088;">$config</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">password</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<p>Pour cela, il faut utiliser le système de réferences:</p>
<div class="codecolorer-container xml notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;service</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;db&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;Database&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;constructor<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;argument</span> <span style="color: #000066;">ref</span>=<span style="color: #ff0000;">&quot;config&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;host&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;argument</span> <span style="color: #000066;">ref</span>=<span style="color: #ff0000;">&quot;config&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;user&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;argument</span> <span style="color: #000066;">ref</span>=<span style="color: #ff0000;">&quot;config&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;password&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/constructor<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/service<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></div>
<p>Il est également possible de spécifier la méthode à utiliser pour résoudre les arguments,</p>
<div class="codecolorer-container text notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">getParam()</div></div>
<p>par exemple, pour arriver à quelque chose de ce genre:</p>
<div class="codecolorer-container php notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000088;">$config</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Config<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$service</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Db<span style="color: #009900;">&#40;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$config</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getParam</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;host&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; <span style="color: #000088;">$config</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getParam</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;user&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; <span style="color: #000088;">$config</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getParam</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;password&quot;</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<p>Le code XML est alors le suivant:</p>
<div class="codecolorer-container xml notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;argument</span> <span style="color: #000066;">ref</span>=<span style="color: #ff0000;">&quot;config&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;host&quot;</span> <span style="color: #000066;">factoryMethod</span>=<span style="color: #ff0000;">&quot;getParam&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span></div></div>
<h3 id="toc-heritage-et-surcharge-de-services">Héritage et surcharge de services</h3>
<p>Assez souvent, certains services à injecter se ressemblent. Il est possible d&#8217;utiliser un système d&#8217;héritage pour rendre la description des services moins rébarbative. Il ne s&#8217;agit pas d&#8217;un héritage &laquo;&nbsp;concret&raquo;&nbsp; dans nos classes, mais du principe de l&#8217;héritage. Ainsi, une description peut en étendre une autre, facilitant à la fois son écriture et sa compréhension.</p>
<div class="codecolorer-container xml notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;service</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;extendedService&quot;</span> <span style="color: #000066;">extends</span>=<span style="color: #ff0000;">&quot;config&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;method</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;method2&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;argument</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;value&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/method<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/service<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></div>
<h3 id="toc-container-aware">Container Aware</h3>
<p>Dans certains cas, il peut être utile qu&#8217;un service soit conscient de l&#8217;existence du conteneur, et qu&#8217;il puisse y accéder. Il est facile d&#8217;injecter le conteneur dans un service, en utilisant le type &laquo;&nbsp;container&raquo;&nbsp;, ou la facilité &laquo;&nbsp;containerAware&raquo;&nbsp;:</p>
<div class="codecolorer-container xml notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;service</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;containerAwareService&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;Service&quot;</span> <span style="color: #000066;">containerAware</span>=<span style="color: #ff0000;">&quot;true&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
<span style="color: #808080; font-style: italic;">&lt;!-- est exactement équivalent à--&gt;</span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;service</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;containerAwareService&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;Service&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;method</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;setDiContainer&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;argument</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;container&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/method<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/service<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></div>
<p>Du coté de votre classe, si celle-ci doit récupérer le conteneur, elle à simplement à implémenter l&#8217;interface <em>SpiralDi_ContainerAware</em>. Lors de sa construction, la méthode <em>setDiContainer</em> sera directement appelée. </p>
<p>A noter que dans ce cas, il n&#8217;est pas nécessaire de définir votre service comme étant &laquo;&nbsp;ContainerAware&raquo;&nbsp;, le conteneur étant capable de le découvrir tout seul. </p>
<h2 id="toc-factories">Factories</h2>
<p>Il est également possible d&#8217;utiliser des Factory depuis le DI, pour générer un comportement comme celui ci</p>
<div class="codecolorer-container php notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000088;">$service</span> <span style="color: #339933;">=</span> MyServiceFactory<span style="color: #339933;">::</span><span style="color: #004000;">createService</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<p>Le code XML correspondant est le suivant:</p>
<div class="codecolorer-container xml notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;service</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;serviceFactory&quot;</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;factory&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;MyServiceFactory&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;method</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;createService&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/service<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></div>
<p>Cela peut s&#8217;avérer pratique pour récupérer vos anciennes implémentations du pattern Singleton entres autres&#8230;</p>
<div class="codecolorer-container xml notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;service</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;singleton&quot;</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;factory&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;Mysingleton&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;method</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;getInstance&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/service<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></div>
<h2 id="toc-telechargez-le">Téléchargez le ! </h2>
<p>Convaincu ? Pour récupérer la dernière version de SpiralDi, vous avez le choix entre plusieurs solutions:</p>
<h3 id="toc-via-le-depot-mercurial">Via le dépôt mercurial</h3>
<div class="codecolorer-container bash notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">hg clone https:<span style="color: #000000; font-weight: bold;">//</span>ametaireau<span style="color: #000000; font-weight: bold;">@</span>bitbucket.org<span style="color: #000000; font-weight: bold;">/</span>ametaireau<span style="color: #000000; font-weight: bold;">/</span>spiraldi<span style="color: #000000; font-weight: bold;">/</span></div></div>
<h3 id="toc-via-les-archives">Via les archives</h3>
<p>Le code est disponible en <a href="http://bitbucket.org/ametaireau/spiraldi/get/tip.zip">zip</a>, <a href="http://bitbucket.org/ametaireau/spiraldi/get/tip.gz">gz</a> ou <a href="http://bitbucket.org/ametaireau/spiraldi/get/tip.bz2">bz2</a></p>
<p>Vous pouvez aussi aller <a href="http://bitbucket.org/ametaireau/spiraldi/">jeter directement un oeil au dépot</a>.<br />
Et voila! Vous avez de quoi vous amuser ! Pour toute demande de fonctionnalité, rapport de bug etc, <a href="http://bitbucket.org/ametaireau/spiraldi/issues/new/">n&#8217;hésitez surtout pas</a>!</p>
<h2 id="toc-et-ailleurs">Et ailleurs ?</h2>
<p>SpiralDi n&#8217;est bien évidemment pas le seul Conteneur Léger écrit en PHP. Depuis peu, ces derniers commencent d&#8217;ailleurs à fleurir sur la toile. Les frameworks Symfony et Flow3<sup>1</sup> leur font d&#8217;ailleurs la part belle, et c&#8217;est tant mieux! Quelques alternatives possibles au conteneur de Spiral donc:</p>
<ul>
<li><a href="http://svn.symfony-project.com/components/dependency_injection/">Le service container de symfony</a></li>
<li><a href="http://github.com/beberlei/yadif/tree/master">Yadim</a></li>
<li><a href="http://flow3.typo3.org/documentation/reference/object/">Flow3 Objects</a></li>
<li><a href="http://www.beberlei.de/sphicy/">Sphicy</a></li>
</ul>
<h2 id="toc-lectures-interessantes">Lectures intéressantes</h2>
<p>Si vous souhaitez aller plus loin, voici quelques lectures intéressantes sur le sujet de l&#8217;injection de dépendances:</p>
<ul>
<li><a href="http://www.martinfowler.com/articles/injection.html">L&#8217;article de Martin Fowler sur l&#8217;injection de dépendances</a></li>
<li>La série d&#8217;articles de Fabien potencier (<a href="http://fabien.potencier.org/article/11/what-is-dependency-injection">1</a>,<a href="http://fabien.potencier.org/article/12/do-you-need-a-dependency-injection-container">2</a>,<a href="http://fabien.potencier.org/article/13/introduction-to-the-symfony-service-container">3</a>,<a href="http://fabien.potencier.org/article/14/symfony-service-container-using-a-builder-to-create-services">4</a>,<a href="http://github.com/fabpot/Pimple/tree/master">5</a>)</li>
<li>Celle de Padraic Brady (<a href="http://blog.astrumfutura.com/archives/394-The-Case-For-Dependency-Injection-Part-1.html">1</a>,<a href="http://blog.astrumfutura.com/archives/395-The-Case-For-Dependency-Injection-Part-2.html">2</a>) </li>
<li><a href="http://www.dotnetguru.org/articles/dossiers/ioc/ioc.htm">Les conteneurs légers du futur</a>, par Sami Jabber</li>
</ul>
<ol class="footnotes"><li id="footnote_0_189" class="footnote">Il est tout nouveau, tout beau, en PHP 5.3, utilise l&#8217;AOP, la persistance <em>Domain Model</em> &#8230; et l&#8217;injection de dépendances! A suivre de très près: <a href="http://flow3.typo3.org/">Flow3 </a></li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.notmyidea.org/article/fr-introduction-to-spiral-dependency-injection-container-in-php/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Introduction à l&#8217;injection de dépendances: le cas du singleton.</title>
		<link>http://www.notmyidea.org/article/dependency-injection-singleton-design-pattern-ioc-dendencies-dependences/</link>
		<comments>http://www.notmyidea.org/article/dependency-injection-singleton-design-pattern-ioc-dendencies-dependences/#comments</comments>
		<pubDate>Mon, 25 May 2009 14:36:58 +0000</pubDate>
		<dc:creator>Alexis Metaireau</dc:creator>
				<category><![CDATA[Architecture logicielle]]></category>
		<category><![CDATA[Injection de dépendances]]></category>
		<category><![CDATA[IoC]]></category>
		<category><![CDATA[singleton]]></category>
		<category><![CDATA[spiral]]></category>

		<guid isPermaLink="false">http://www.notmyidea.org/?p=67</guid>
		<description><![CDATA[L&#8217;architecture logicielle est un des aspects du développement qui m&#8217;intéresse particulièrement. Ça fait d&#8217;ailleurs un bout de temps que l&#8217;idée d&#8217;un article à propos des dépendances (de l&#8217;injection de dépendances) et du cas du singleton me trotte dans la tête, alors, le voici:
Avant tout, il faut bien comprendre que sans contexte il n&#8217;existe pas de [...]]]></description>
			<content:encoded><![CDATA[<p>L&#8217;architecture logicielle est un des aspects du développement qui m&#8217;intéresse particulièrement. Ça fait d&#8217;ailleurs un bout de temps que l&#8217;idée d&#8217;un article à propos des dépendances (de l&#8217;injection de dépendances) et du cas du singleton me trotte dans la tête, alors, le voici:</p>
<p>Avant tout, il faut bien comprendre que sans contexte il n&#8217;existe pas de manière plus censée qu&#8217;une autre pour construire une application. Il existe par contre un ensemble de bonnes pratiques qu&#8217;il est bon de connaitre et d&#8217;appliquer, dans la plus large mesure possible. Ces pratiques sont souvent mal connues, et nombre d&#8217;entre elles sont appliquées à la va vite.</p>
<p>Nous allons tenter d&#8217;expliquer ici pourquoi et comment l&#8217;implémentation la plus rependue du singleton favorise la création de dépendances, et comment nous pouvons y remédier, grâce à l&#8217;injection de dépendances.<br />
<span id="more-67"></span></p>
<h3 id="toc-le-singleton">Le singleton</h3>
<div id="attachment_140" class="wp-caption alignright" style="width: 160px"><img class="size-thumbnail wp-image-140" title="singleton" src="http://www.notmyidea.org/wp-content/uploads/2009/05/singleton-150x150.jpg" alt="Le singleton, à l'origine de dépendances" width="150" height="150" /><p class="wp-caption-text">Le singleton, à l&#39;origine de dépendances</p></div>
<p>Le Singleton est un patron de conception (souvent le premier patron de conception qui nous est présenté) qui doit être appliqué avec précaution. Son utilisation est souvent mal comprise et celui ci peut être considéré à tort comme une solution &laquo;&nbsp;miracle&raquo;&nbsp; pour accéder facilement à un objet, comme on le ferait d&#8217;une variable globale. On dit d&#8217;ailleurs aussi qu&#8217;il s&#8217;agit de l&#8217;<em>antipattern</em> singleton, à raison. Pourquoi ?</p>
<p>Très rapidement, un singleton est une classe dont il existe un nombre défini d&#8217;instances. Typiquement, le singleton est utilisé afin de réduire le nombre possible d&#8217;instances d&#8217;une classe à une seule. Cela peut être très utile, et est utilisé dans de nombreux cas à bon escient (je pense par exemple à l&#8217;accès à une base de données).</p>
<p>Un des défauts majeur de ce motif, est l&#8217;implémentation la plus souvent présentée, qui va de paire avec l&#8217;usage de méthodes statiques pour récupérer une instance de la classe. Pour mieux comprendre, voici l&#8217;implémentation type, en PHP (le motif est sensiblement le même dans de nombreux langages):</p>
<div class="codecolorer-container php notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">class</span> DbConnection_MySql <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> static <span style="color: #000088;">$_instance</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">function</span> __construct <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> static <span style="color: #000000; font-weight: bold;">function</span> getInstance <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$_instance</span> instanceof <span style="color: #000000; font-weight: bold;">self</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$_instance</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #000000; font-weight: bold;">self</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$_instance</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> connect<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// do some stuff</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>Ici, pour récupérer l&#8217;instance de la classe, il est nécessaire de faire appel à la méthode statique <em>getInstance </em>de la classe <em>DbConnection_Mysql</em>.</p>
<p>Il est alors nécessaire, dans la classe utilisatrice du singleton (imaginons qu&#8217;il s&#8217;agisse d&#8217;une classe User), de <em>hardcoder</em> le nom de la classe DbConnection_Mysql, la classe A devenant alors <span style="text-decoration: underline;">dépendante</span> de cette implémentation particulière du singleton.</p>
<div class="codecolorer-container php notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">class</span> User<span style="color: #009900;">&#123;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> __construct<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// dépendance avec la classe DbConnection</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$dbc</span> <span style="color: #339933;">=</span> DbConnection_MySql<span style="color: #339933;">::</span><span style="color: #004000;">getInstance</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>Avec cette implémentation, il est impossible de changer la classe en charge de la connexion à la base de données sans modifier le code. Imaginons que nous souhaitons utiliser la classe <em>DbConnection_Oracle</em> par exemple, nous sommes bloqués. Il s&#8217;agit d&#8217;une problème de conception, et peut faire perdre un temps important lors du développement.</p>
<h3 id="toc-inversion-de-controle-injection-de-dependances">Inversion de contrôle / Injection de dépendances</h3>
<p>Comme nous venons de le voir, le singleton, ou plutôt, cette implémentation du singleton, introduit et favorise les dépendances entre nos classes.</p>
<p>Une des solutions possible est d&#8217;inverser le flux de contrôle de notre application: au lieu que ce soit la classe <em>User</em> qui appelle directement <em>DbConnection_Mysql</em>, celui ci peut être crée en amont, pour être ensuite injecté dans la classe qui souhaite l&#8217;utiliser. De cette manière,  Ce principe à un nom, il s&#8217;agit de <span style="text-decoration: underline;">l&#8217;injection de dépendances</span>.</p>
<h4 id="toc-theorie">Théorie</h4>
<p><em>Alice</em> a besoin d&#8217;une Glace pour la <em>manger()</em>.<br />
<em>Alice</em> aime les <em>GlaceALaFraise</em>&#8230; Si on donne de l&#8217;argent à <em>Alice</em> elle achète systématiquement une <em>GlaceALaFraise</em>. <em>Alice</em> est bloquée au seul parfum &laquo;&nbsp;fraise des bois&raquo;&nbsp; aussi savoureux soit-il.</p>
<p>Pour lui faire découvrir de nouvelles saveurs sa <em>Maman</em> décide de ne plus laisser <em>Alice</em> choisir sa <em>Glace</em> elle-même, mais se charge de choisir pour elle une <em>GlaceAuPaté</em>. </p>
<p>Quels que soit les goûts d&#8217;<em>Alice</em>, une <em>GlaceAuPaté</em> reste une <em>Glace</em>, et donc <em>Alice</em> est tout à fait à même de la <em>manger()</em><sup>1</sup>.</p>
<p>Le concept exposé ici est connu comme le <em><a href="http://en.wikipedia.org/wiki/Hollywood_principle">principe d&#8217;Holywood</a></em>: &laquo;&nbsp;Ne vous appelez pas vous même, nous vous appellerons&raquo;&nbsp;.</p>
<p>Ce qu&#8217;il faut retenir, c&#8217;est qu&#8217;<em>Alice</em> peut, si elle le souhaite, <em>manger()</em> tout type de <em>Glace</em>, même si au départ <em>Alice</em> n&#8217;à besoin de <em>manger()</em> q&#8217;une <em>GlaceALaFraise</em>. Nous favorisons ici la réutilisations du code: nous pouvons réutiliser Alice facilement et substituer sa <em>Glace</em> par une autre facilement.</p>
<h4 id="toc-application-a-notre-exemple">Application à notre exemple</h4>
<p>Reprenons l&#8217;exemple des utilisateurs et de l&#8217;utilisation de la DbConnection pour y appliquer ce principe d&#8217;inversion de contrôle. Notre code ressemblerait alors à quelque chose dans cet esprit:</p>
<div class="codecolorer-container php notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000088;">$dbc</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> DbConnection_Default<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$user</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> ClassA_Default<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$user</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setDbConnection</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$dbc</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<p>Avec les deux interfaces/implémentations suivantes pour DbConnection et User:</p>
<div class="codecolorer-container php notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;height:420px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666; font-style: italic;">// Interfaces</span><br />
<span style="color: #000000; font-weight: bold;">interface</span> DbConnection <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">function</span> __construct<span style="color: #009900;">&#40;</span><span style="color: #000088;">$host</span><span style="color: #339933;">,</span> <span style="color: #000088;">$user</span><span style="color: #339933;">,</span> <span style="color: #000088;">$password</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">function</span> connect<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">interface</span> User<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">function</span> setDbConnection<span style="color: #009900;">&#40;</span>DbConnection<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #666666; font-style: italic;">// Implementations</span><br />
<span style="color: #000000; font-weight: bold;">class</span> DbConnection_Mysql implements DbConnection<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> __construct<span style="color: #009900;">&#40;</span><span style="color: #000088;">$host</span><span style="color: #339933;">,</span> <span style="color: #000088;">$user</span><span style="color: #339933;">,</span> <span style="color: #000088;">$password</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// store parameters into the object</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> connect<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// connect to the database</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">class</span> User_Default implements User<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> setDbConnection<span style="color: #009900;">&#40;</span>DbConnection <span style="color: #000088;">$dbc</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// store $dbc into the object</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>Ici, il subsiste des dépendances dans le code. Il s&#8217;agit de dépendances vis à vis de contrats (interfaces) et non d&#8217;implémentations données (classes), puisque j&#8217;ai choisi d&#8217;utiliser le paradigme de <a href="http://fr.wikipedia.org/wiki/Programmation_par_contrat">programmation par contrats</a>.</p>
<p>Nous avons parlé de singleton et de création de dépendances, mais l&#8217;injection de dépendances est applicable à tout type de classes, et devrait d&#8217;ailleurs être utilisé dans la plupart des projet d&#8217;importante envergure.</p>
<h3 id="toc-utilisation-dun-conteneur">Utilisation d&#8217;un conteneur</h3>
<div id="attachment_170" class="wp-caption alignright" style="width: 197px"><img src="http://www.notmyidea.org/wp-content/uploads/2009/05/exemple.png" alt="schéma des dépendances entre nos classes" title="exemple" width="187" height="155" class="size-full wp-image-170 alignleft" /><p class="wp-caption-text">schéma des dépendances entre nos classes</p></div>
<p>Pour aller un peu plus loin, il peut être utile et efficace de déléguer la tâche de création des objets à un conteneur. Il s&#8217;agit d&#8217;une classe, en charge de la création de tous les objets, ce dernier pouvant résoudre les dépendances nécessaires à la création de l&#8217;objet souhaité.</p>
<p>Nous avons donc le schéma de dépendances décrit à gauche. Une fois ces informations fournies au conteneur (via un fichier de configuration), nous pouvons facilement récupérer l&#8217;object <em>User_Default</em> en le demandant à notre conteneur:</p>
<div class="codecolorer-container text notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$container-&gt;user</div></div>
<p>. Ce dernier se charge alors de créer l&#8217;ensemble des dépendances de cet objet (un objet de la classe DbConnection_Mysql ici). Plutôt sympa, non ?</p>
<p>Pour faire en sorte que la classe d&#8217;accès aux données soit un singleton, c&#8217;est le schéma qu&#8217;il faut alors modifier (via le fichier de configuration ici.)</p>
<p>Ici, j&#8217;ai essentiellement parlé de dépendances entre classes. Cependant, de la même manière, il est possible de contrôler tous les arguments passés à nos objets, qu&#8217;il s&#8217;agisse de tableaux, de chaines de caractère ou autres.</p>
<h3 id="toc-moi-aussi-jen-veux-spiral-di-container">Moi aussi j&#8217;en veux ! Spiral Di Container</h3>
<p>Pour mon usage personnel, j&#8217;ai développé un injecteur de dépendances flexible, permettant d&#8217;appliquer ce modèle à mes futurs développements. Il existe déjà des projets similaires, mais ces derniers font un usage trop abusif &#8211; à mon gout &#8211; du mécanisme de réflexion, perdant alors grandement en performance.</p>
<p>Voyons comment nous pouvons utiliser le conteneur dans notre cas. Cela revient à créer le schéma de dépendances. Cela est possible pour le moment par 2 biais: via XML ou directement via php.</p>
<h4 id="toc-directement-via-php">Directement via php</h4>
<div class="codecolorer-container php notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000088;">$fluent</span><br />
<span style="color: #339933;">-&gt;</span><span style="color: #004000;">registerService</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'user'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'User_Default'</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #339933;">-&gt;</span><span style="color: #004000;">call</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'setDbConnection'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">withServices</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'dbc'</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #339933;">-&gt;</span><span style="color: #004000;">registerService</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'dbc'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'DbConnection_Mysql'</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #339933;">-&gt;</span><span style="color: #004000;">construct</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">with</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'localhost'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'root'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">''</span><span style="color: #009900;">&#41;</span></div></div>
<h4 id="toc-via-un-fichier-xml">Via un fichier XML</h4>
<div class="codecolorer-container xml notmyidea" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;container<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;service</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;user&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;User_Default&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;method</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;setDbConnection&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;argument</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;string&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;dbc&quot;</span> <span style="color: #000066;">service</span>=<span style="color: #ff0000;">&quot;true&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/method<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/service<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;service</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;dbc&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;DbConnection_Mysql&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;method</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;__construct&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;argument</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;string&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;localhost&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;argument</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;string&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;root&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;argument</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;string&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/method<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/service<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/container<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></div>
<p>Il est à noter que le fichier XML à été directement généré via le <em>Dumper</em> Xml, en utilisant le schema.</p>
<p>Si vous êtes interessé pour regarder plus en détail le fonctionnement de ce conteneur, les sources sont d&#8217;ores et déjà disponibles via le framework de travail spiral, disponible via <a href="http://bitbucket.org/ametaireau/spiral-php52/src/di/">son dépot mercurial</a>.</p>
<p>L&#8217;injecteur de dépendances est présent dans la partie /core/Di de l&#8217;architecture. Une version standalone devrait bientôt voir le jour.</p>
<p>Si cet article vous à plu, je publierais prochainement une série d&#8217;article expliquant en détail comment utiliser un conteneur de dépendances, en m&#8217;appuyant sur des exemples concrets que j&#8217;ai pu rencontrer.</p>
<p>Ah, et j&#8217;oubliais, un grand merci aux relecteurs pour votre aide précieuse ! (Fred, David, Florent, Joel, Nico &#8230;)</p>
<ol class="footnotes"><li id="footnote_0_67" class="footnote">Merci Frédéric pour ton super exemple !</li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.notmyidea.org/article/dependency-injection-singleton-design-pattern-ioc-dendencies-dependences/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
	</channel>
</rss>
