D'inici ràpid Symfony DI (injecció de dependència) Tutorial
Què és la injecció de dependències (DI)?
La injecció de dependència és una tècnica que permet als objectes dèbilment acoblats dins d'una aplicació de programari. En general, si un objecte requereix l'accés a la funcionalitat d'un altre seria una instància interna que condueix a sistemes fortament acoblats. Mitjançant la implementació de la injecció de dependència que s'injecten els objectes necessaris llestos per al seu ús (de vegades també es va referir a la inversió de control - COI). Prenem l'exemple següent:
<? Php classe DecisionMaker { makeDecision funció pública (matriu de paràmetres $) { / / Necessita l'adaptador de base de dades $ Dp = new DecisionParameters (); $ ParameterScore = getScore $ dp-> ($ paràmetres); / * ... Alguns decisió més lògica ... * / retorn ($ parameterScore> 50); } }
Aquesta peça de codi es diu que és ben acoblat a la DecisionParameters objecte. Re-escriure l'anterior de manera imprecisa que tindríem una mena ....
<? Php classe DecisionMaker { privat $ _dp; funció pública __construct ($ dp) { $ This-> _dp = $ dp; } makeDecision funció pública (matriu de paràmetres $) { $ ParameterScore = _dp $ this-> -> getScore ($ paràmetres); / * ... Alguns decisió més lògica ... * / retorn ($ parameterScore> 50); } }
Mentre que obtenir els avantatges del codi imprecisa estem afegint complexitat tal que cada vegada que un objecte es crea una instància que també hem de crear instàncies de les seves dependències i en passar aquests també. Per exemple, això:
elecció = $ DecisionMaker nou (); echo $ makeDecision elecció-> (array ('esforç' => 'baix', 'return' => 'alta'));
ara es converteix en:
$ Dp = new DecisionParameters (); $ = Elecció del nou DecisionMaker ($ dp); echo $ makeDecision elecció-> (array ('esforç' => 'baix', 'return' => 'alta'));
Aquesta situació es fa més dolorós com el nombre de dependències d'una classe s'incrementa, i el que si les dependències de si mateixos tenen dependències? Això pot molt ràpidament convertir-se en un malson de l'administració d'objectes! Introduïu els contenidors de dependència de la injecció (o marcs) ...
Contenidors d'injecció de dependència / Marc
Dependència contenidors d'injecció (o marcs) manejar el procés de creació d'objectes, instàncies i injectar les dependències abans de tornar a una instància de la persona que truca.
En el seu codi en lloc de crear nous objectes directament demanem una còpia de l'objecte del contenidor DI. L'objecte que es torna ja té totes les seves dependències injectat i l'objecte està llest per a funcionar.
Symfony injecció de dependències de contenidors
Symfony és probablement més conegut per la seva pila completa MVC marc però, també han llançat una sèrie de components que poden utilitzar-se de forma independent. Per exemple, el contenidor d'injecció de dependència que anem a parlar aquí, un YAML programa d'anàlisi, un motor de plantilles, consulteu els components Symfony per a més.
El DI contenidor Symfony es basa en que des del Spring Framework en Java .
Bootstrapping
Per tal d'arrencar el marc de la injecció de dependència Symfony que utilitzi el codi tal com es preveu a continuació. He escollit usar YAML només perquè és fàcil de llegir i de configuració. Per a la velocitat màxima és possible que vulgueu escriure les seves contenidors a la plana de PHP (el contenidor Symfony pot fer això per a vostè un cop la configuració), o, alternativament, la memòria cau tot el recipient amb Zend_Cache , o similar.
Per instal lar Symfony DI seguiu les instruccions que s'inclouen aquí http://components.symfony-project.org/dependency-injection/installation , i afegir a la ruta.
/ / Carregar el contenidor Symfony DI requereixen "sfServiceContainerBuilder.php; envàs = $ sfServiceContainerBuilder nou (); $ Gestor = sfServiceContainerLoaderFileYaml nova ($ contenidor); $ Gestor de càrrega-> (APPLICATION_PATH '/ config / di / services.yml.);
En primer lloc tenim una instància d'un nou contenidor i, a continuació carreguem la nostra configuració d'un arxiu YAML. Nota: el contenidor DI pot carregar configuració de diversos formats, com XML , YAML, PHP, INI i *. Tendeixo a incloure un únic arxiu YAML i importar fitxers des d'altres no.
Diversos arxius de configuració es poden importar amb diferents formats, les definicions més recents sobreescriure els que ja han estat definits. Els arxius de configuració poden incloure referències als objectes i paràmetres.
* INI només és capaç de definir els paràmetres i no és capaç d'importar arxius d'altres
Exemple de configuració
importacions: - {Recursos: daos.yml} paràmetres: nom d'usuari: fals serveis: # Model de client model.customer: classe: Pro_Customer les trucades: - [SetLogger, [@ utils.logger]] - [SetDao, [@ data.userdata.mysql]] - [SetUserName, [% username%]] # Model del producte model.product: classe: Pro_Product arguments: [% username%, {tipus:%% accesslevel, lastlogin:%% lastlogin}] les trucades: - [SetDao, [@ data.product.mysql]] # Logger utils.logger: classe: Pro_Logger constructor: getInstance les trucades: - [SetHandle, [@ utils.filewriter]]
Crec que el codi anterior és bastant explica per si mateix, però per a major claredat vaig a explicar cada part ara.
En primer lloc definim algunes importacions (és a dir, altres arxius a analitzar), m'agrada el meu grup de configuracions de danys exemple en un arxiu, els serveis públics en un altre i el nom del fitxer correctament. Encara que una mica més lent que accelera el manteniment dels arxius de configuració. També és possible analitzar els arxius d'altres formats utilitzant diferents indicadors d'importació. Els arxius s'analitzen amb vista amb noves definicions sobreescriure o modificar els serveis prèviament definits / paràmetres.
A continuació es defineix un paràmetre, un paràmetre general, pot ser qualsevol tipus de variable de PHP. En aquest moment jo no sabia el que el meu paràmetre de nom d'usuari ha de ser (el que necessito per a autenticar per això!), Pel que he definit un valor predeterminat i vaig a substituir aquest valor més tard. Tingueu en compte, les classes no es creen instàncies fins que pregunti per ells per definir els paràmetres d'una mica més endavant està perfectament bé. Arran d'això definir alguns serveis:
- Una instància de Pro_Customer, passar una instància del meu registrador de la setLogger () mètode, afegiu a la meva MySQL objecte d'accés a dades (DAO), i passi el nom d'usuari també. Cada vegada que demano per a aquest objecte que vull una nova instància
- Crear una instància de Pro_Product, passar arguments de nom d'usuari i una gran varietat d'opcions per al constructor. Després de setDao instàncies truqueu al () i passar-li el meu producte DAO
- Dóna'm una còpia de Pro_Logger, instància que mitjançant el mètode getInstance () i passar una còpia de la meva objecte escriptor d'arxius a través setHandle () una vegada que la seva càrrega. El meu escriptor fitxer es defineix en un dels meus importacions.
Dins de la configuració dels serveis d'arxius es fa referència anteposant el nom amb un símbol '@', els paràmetres es fa referència anteposant i annexar amb '%' símbols, eg@utils.logger% username%.
Addició de dades post càrrega
De vegades no saps quin és el valor dels paràmetres han de ser fins després d'haver bootstrap, ja que amb el nostre nom d'usuari per sobre dels paràmetres. Per tal de sobreescriure el valor de la offsetSet () s'utilitza, en primer lloc passar el nom del paràmetre seguit del seu nou valor:
offsetSet $ envàs-> ('username', $ nom); Obtenir objectes del contenidor
Un cop configurat en lloc de crear instàncies d'objectes que ara van directament al contenidor de DI per obtenir instàncies. Amb la DI Symfony que anomenem el mètode GetService (), passant d'una cadena que descriu la variable que voleu recuperar, per exemple,
registrador de $ = $ per contenidor> GetService ('utils.logger'); Es realitzarà l'equivalent a:
$ Logger = Pro_Logger:: getInstance (); FileWriter $ = Pro_Writer_FileWriter nou (); $ Logger-> SetHandler ($ FileWriter);
És possible determinar si el recipient té una instància d'un servei trucant a la hasService () mètode, que torna un valor booleà.
No cal tenir accés al contenidor més enllà del nivell superior de la seva aplicació ja que una vegada la recuperació d'una instància de totes les dependències necessàries fins al més profund de la seva aplicació ia la configuració i l'espera de ser cridats.
Proves unitàries
La injecció de dependència també té l'avantatge agregat de permetre que els objectes que s'analitzaran en forma aïllada. Prenent l'exemple de la classe DecisionMaker abans d'implementar la configuració d'injecció de dependència dels nostres resultats de la prova també depèn de la implementació de la classe DecisionParameters.
Si la volta a classe diferents resultats DecisionParameters les nostres proves podrien començar, si no per causes alienes a la nostra. Ús de la injecció de dependència que ara pot passar en un objecte DecisionParameters que retorna un conegut / fixa conjunt de resultats per a determinats paràmetres d'entrada, estem provant ara DecisionMaker al marge de qualsevol factor extern, és a dir, si les nostres proves s'inicien si no es poden atribuir directament a alguna cosa canvis en la classe DecisionMakeer. Això és particularment important en el cas que es confia en les dades de prova d'una base de dades per a la seva anàlisi.
Configuració de l'aplicació
La forma en que la seva aplicació es comporta en el seu servidor de producció, inevitablement serà diferent de la configuració del seu desenvolupament. Per exemple, en un entorn de desenvolupament el nivell de registre seria molt més granular que en el seu sistema de producció. En alterar la seva dependència dels fitxers de configuració de la injecció de contenidors poc (o analitzar un fitxer de configuració addicional) l'alteració de la conducta en funció de l'entorn es fa simple.
Per tipus de lusió a les interfícies en lloc de les implementacions de l'hora d'establir les dependències també és possible intercanviar els components dels components compatibles amb unes poques línies de YAML o XML. Per exemple, actualment pot accedir a la seva base de dades MySQL a través d'un DAO (Data Access Object), però amb el temps que pot desenvolupar una DOP, Zend_Db, o Doctrina aplicació d'aquesta DAO. Mitjançant l'addició de la nova implementació en el seu arxiu de configuració de sobte tots els objectes que utilitza l'antiga implementació de MySQL estan usant la seva nova posada en pràctica sense necessitat d'atacar a les entranyes de la seva aplicació.
Notes
- En establir la residència: cert en la configuració que es donen sempre la mateixa instància d'un objecte. Això és molt útil quan es tracta d'objectes que contenen recursos com connexions a bases de dades, identificadors d'arxiu, etc
- Hi ha dos mètodes pels quals les dependències pot ser injectat. Un d'ells és passar les dependències amb el constructor, o bé a través de mètodes d'establiment. El patró generalment acceptat és passar les dependències necessàries a través del constructor i opcionals a través d'incubadores. La meva preferència personal és utilitzar setembre per a tot, però això és fins el desenvolupador individual
Finalment ....
Juntament amb un breu debat sobre la injecció de dependència i els seus avantatges i inconvenients que això ha estat també una guia d'inici ràpid per a l'aplicació de la injecció de dependències de Symfony contenidors ... espero que hagis vist que és sorprenentment ràpid i fàcil. Des d'aquí vostè podrà començar a utilitzar la injecció de dependència a través de la seva sol.licitud i esperem que amb moltes més de les característiques avançades (encara que l'exemple simple cobreix la gran majoria de la funcionalitat que requereixen). Com sempre et assenyalen el manual per a més informació.


















































[...] Aquest lloc ha estat esmentat a Twitter per Vicente Jousse, Steven Lloyd Watkin. Steven Lloyd Watkin va dir: http://bit.ly/cUO2ov d'inici ràpid de la dependència Symfony # marc d'injecció # php # ZF [...]
Gran article.
Tinc un dubte ara. Quan bootstrapping estem carregant els fitxers de configuració YAML. Llavors, que creen objectes per a tots, que no necessitem?
Per exemple: tinc un una mica de classe que s'utilitza només de vegades. Així es crea un objecte o és prou intel ligent com per carregar a través de les funcions de càrrega automàtica quan estic trucant mètode getInstance (). No vaig haver de dir per què.
Gràcies
No, les classes només es carreguen quan són requerits.
Al getInstance () exemple de la classe es crea una instància com:
$ Class = Classe:: getInstance ();
En lloc de:
classe $ = nova classe ();
Generalment això es fa servir quan l'aplicació del patró Singleton.
[...] El que li permet utilitzar DI en el projecte d'una manera fàcil. Steven Lloyd Watkin passar el seu temps a escriure una guia d'inici ràpid tutorial.It's val la pena esmentar que Symfony DI de contenidors és una biblioteca independent disponible com [...] Symfony