Quick Start Symfony DI (Inxección de Dependencia) Tutorial
¿Que é Inxección de Dependencia (DI)?
Inxección de dependencia é unha técnica que permite a obxectos feblemente encaixados en unha aplicación de software. Xeralmente, se un obxecto require acceso á función de outro que sería instanciado internamente levando a sistemas fortemente encaixados. Ao aplicar a inxección de dependencia que inxectar os obxectos necesarios listo para o seu uso (en ocasións tamén chamado de troco de control - COI). Mira o seguinte exemplo:
<? PHP Decisor clase { makeDecision función pública (array $ Parameters) { / / Necesito do adaptador de base de datos DecisionParameters dp $ = new (); ParameterScore getScore $ = $ dp-> ($ parametros); / * ... Un pouco de lóxica de decisións máis ... * / return ($ parameterScore> 50); } }
Este anaco de código dise ser fortemente asociada á DecisionParameters obxecto. Reescribir o anterior de forma flexible, teríamos algo así como ....
<? PHP class decisor {$ _dp privado; función pública __construct ($ dp) {$ this-> _dp = $ dp;} makeDecision función pública (array $ Parameters) {$ parameterScore getScore = $ this-> _dp-> ($ parámetros); * / ... Un pouco de lóxica de decisións máis ... * / Retorno ($ parameterScore> 50);}}
A pesar de gañar os beneficios de código flexible estamos engadindo complexidade tal que cada vez que un obxecto é instanciado tamén temos que instancia súas dependencias e pasar estes en demasiado. Por exemplo, esta:
$ Escolla decisor = new (); echo makeDecision $ escolla-> (array ('esforzo' => 'volver' de abaixo '=>' alta '));
torna-se agora:
DecisionParameters dp $ = new (); = $ Escolla decisor novo ($ dp); echo makeDecision $ escolla-> (array ('esforzo' => 'volver' de abaixo '=>' alta '));
Esta situación faise máis doloroso como o número de dependencias dunha clase aumenta, e que as dependencias propias dependencias? Isto pode moi rapidamente ser un pesadelo administración obxecto! Introduce os envases de inxección de dependencia (ou cadros) ...
Contedores de inxección de dependencia / Quadros
contedores de inxección de dependencia (ou cadros) xestione o proceso de creación do obxecto; instancia e inxectar as dependencias antes de regresar unha instancia para o interlocutor.
No seu código en vez de crear novos obxectos directamente solicitamos unha copia do obxecto do recipiente DI. O obxecto que está a ser devolto xa ten todas as súas dependencias e inxectado o obxecto está preparado para ir.
Symfony contedores de inxección de dependencia
Symfony pode ser máis coñecido pola súa pila completa MVC cadro pero eles tamén lanzaron unha serie de compoñentes que poden ser empregados de forma independente. Por exemplo, o contedores de inxección de dependencia que imos falar aquí, un YAML parser, un motor de templates, consulte compoñentes Symfony máis.
O Symfony recipiente DI baséase en que a partir do Spring Framework en Java .
Bootstrapping
Co fin de comezar a creación do framework symfony inxección de dependencia que usar o código como figura a continuación. Eu escollín usar YAML só porque a súa fácil lectura e configuración. Para a velocidade máxima que pode querer escribir os seus recipientes de simple PHP (Symfony o recipiente pode facelo por vostede así que a configuración), ou alternativamente caché todo o recipiente con Zend_Cache , ou similar.
Para instalar o Symfony DI segue as instruccións contidas aquí http://components.symfony-project.org/dependency-injection/installation , e engadir ao seu camiño.
/ / Carga o Symfony recipiente DI require 'sfServiceContainerBuilder.php; $ Container sfServiceContainerBuilder = new (); SfServiceContainerLoaderFileYaml $ loader = new ($ container); carga $ loader-> (APPLICATION_PATH '/ config / di / services.yml.);
En primeiro lugar, instancias un novo recipiente, e entón preme a nosa configuración dun arquivo YAML. Nota: o container de DI pode cargar a configuración de diversos formatos, como XML , YAML, PHP e INI *. Teño tendencia a incluír un arquivo YAML único e descargar multimedia a partir de alí.
Varios ficheiros de configuración poden ser importados usando diferentes formatos, os axustes recentes substituíndo aqueles que xa foron definidas. Os ficheiros de configuración poden incluír referencias a obxectos e parámetros.
* INI só é capaz de definir os parámetros e non podemos importar ficheiros de outros
Exemplo de configuración
importacións: - {Recurso: daos.yml} parámetros: username: false servizos: # Modelo Cliente model.customer: clase: Pro_Customer chamadas: - [SetLogger, [@ utils.logger]] - [SetDao, [@ data.userdata.mysql]] - [SetUserName, [% username%]] # Modelo do produto model.product: clase: Pro_Product argumentos: [% username%, {type:%% accesslevel, lastlogin:% lastlogin%}] chamadas: - [SetDao, [@ data.product.mysql]] # Loggia utils.logger: clase: Pro_Logger constructor: getInstance chamadas: - [SetHandle, [@ utils.filewriter]]
Eu creo que o código anterior é bastante auto-explicativo, pero para maior claridade Vou explicar cada parte agora.
Nun principio fora, definimos algunhas importacións (é dicir, outros arquivos para analizar), máis me gusta do meu grupo de opcións para cidadáns exemplo a un ficheiro, utilidades noutro eo nome do ficheiro adecuadamente. Aínda que un pouco máis lenta que acelera o mantemento dos arquivos de configuración. Seu tamén pode analizar ficheiros de outros formatos usando sinalizados de importación diferente. Os arquivos son analizados en orde con axustes recentes substituír ou cambiar os servizos previamente definidos / parámetros.
A continuación, definir un parámetro, un parámetro pode ser xeralmente calquera tipo de variable PHP. Neste momento eu non sabía que o meu parámetro nome debe ser (eu teño rexistrarse para iso!), Para que teña definido un valor estándar e eu vou substituír ese valor no mesmo. Nota, as clases non son instanciados ata preguntar a eles, para definir os parámetros de un pouco máis tarde, está perfectamente ben. Tras esta define algúns servizos:
- Instancia Pro_Customer, pase unha instancia da miña rexistro á setLogger () método, engade no meu MySQL Data Access Object (DAO), e pasar o nome tamén. Cada vez que podo facer este obxecto que quero unha nova instancia
- Crear unha instancia de Pro_Product, pasar argumentos de nome de usuario e unha serie de opcións para o constructor. Tras a instanciação setDao call () e pasalo meu produto DAO
- Dáme unha copia Pro_Logger, instancia-la mediante o método getInstance () e pasar unha copia do meu obxecto escritor de arquivos vía setHandle () unha vez que a súa carga. A miña escritora arquivo defínese nunha das miñas descargas.
Dentro da configuración de servizos arquivos son referenciadas precedendo o nome cun @ "símbolo", os parámetros referenciadas precedendo e engadindo con '%' símbolos, eg@utils.logger% username%.
Adición de post de carga de datos
Ás veces non sabe o que o valor dos parámetros debe ser ata que teña bootstrapped, como acontece co noso parámetro de nome de usuario anterior. Co fin de substituír o valor do offsetSet () do método utilizado, en primeiro lugar, pasando o nome do parámetro seguido polo seu novo valor:
offsetSet $ container-> ('username', $ username); Obtención de obxectos do contedores
Unha vez configurado, en vez de instancias obxectos directamente, agora vai a container de DI para obter instancias. Co DI Symfony chamamos GetService () método, pasando unha cadea que describe a variable que quere recuperar, por exemplo,
$ Loggia GetService = $ container-> ('utils.logger'); Isto executar o equivalente a:
$ Loggia = Pro_Logger:: getInstance (); $ FileWriter Pro_Writer_FileWriter = new (); $ SetHandler> de rexistro ($ FileWriter);
É posible determinar se o contedores ten unha instancia dun servizo, chamado de hasService (), método que retorna un valor booleano.
A súa non é necesario ter acceso ao recipiente máis aló do nivel alto da súa aplicación, dende xa recuperar unha instancia de todas as dependencias ata o máis fondo da súa aplicación de configuración e xa están á espera de ser chamado.
Probas Unitarios
Inxección de dependencia tamén ten a vantaxe adicional de permitir que obxectos sexan examinados por separado. Tomando o exemplo da clase decisor antes de aplicar a instalación de inxección de dependencia dos nosos resultados de proba foron tamén depende da implementación da clase DecisionParameters.
Caso o retorno DecisionParameters resultados distintas clases nosos probas pode comezar a fallar non por culpa nosa. Usando a inxección de dependencia, podemos agora pasar nun obxecto DecisionParameters que retorna un coñecido / fixo conxunto de resultados para os parámetros de entrada correcta, estamos probando agora decisor illado de todos os factores externos, é dicir, se os nosos probas comezan na falta deste pode ser directamente atribuído a algo cambio na clase DecisionMakeer. Isto é especialmente importante que debe estar baseada en datos de probas de unha base de datos para proba.
Configuración da aplicación
O xeito en que a súa aplicación se comporta no seu servidor de produción, inevitablemente, difiren na súa configuración de desenvolvemento. Por exemplo, nun ambiente de desenvolvemento o nivel de log sería moito máis granular que no seu sistema de produción. Ao cambiar a súa dependencia de inxección ficheiros de configuración do recipiente un pouco (ou analizar un arquivo de configuración adicional) a cambio de comportamento, dependendo do medio ambiente está feito simple.
Por indicación de tipo de implementacións de interfaces en vez de definir a súa súas dependencias tamén pode trocar compoñentes para compoñentes compatibles con algunhas liñas de YAML ou XML. Por exemplo, pode acceder á súa base de datos MySQL través dun DAO (Data Access Object), pero co tempo pode desenvolver unha DOP, Zend_Db, ou Doutrina implantación deste DAO. Engadindo a nova implantación no seu ficheiro de configuración de súpeto, todos os obxectos que usou a implantación do MySQL de idade están empregando agora a súa nova aplicación sen necesidade de atacar as entrañas da súa aplicación.
Notas
- Por definición compartida: true na configuración estamos sempre a mesma instancia dun obxecto. Isto é moi útil cando se trata con obxectos que contén recursos como conexións de base de datos, identificadores de arquivo, etc
- Existen dous métodos polos que as dependencias poden ser inxectados. Unha delas é para pasar as dependencias co constructor ou, alternativamente, a través de métodos Setter. O nivel xeralmente aceptado é pasar as dependencias a través do constructor e opcionais vía setters. A miña preferencia persoal é por setters para todo, pero iso é baixo o creador
Finalmente ....
Xunto cunha breve discusión sobre inxección de dependencia e as súas vantaxes e inconvenientes que foi tamén unha guía de iniciación rápida para a execución da inxección de dependencia Symfony Container ... espero que teña visto que é sorprendente fácil e rápida. A partir de aí vai ser capaz de comezar a usar inxección de dependencia a través da súa aplicación e mirar para máis usando moitos dos recursos avanzados (aínda que o sinxelo exemplo abrangue a gran maioría das funcionalidades que vai esixir). Como sempre, apunta-lle o manual para máis información.


















































[...] Este post foi mencionada en Twitter por Vincent Jousse, Steven Lloyd Watkin. Steven Lloyd Watkin dixo: http://bit.ly/cUO2ov de inicio rápido para o cadro de dependencia de inxección # # # ZF symfony php [...]
Excelente artigo.
Teño unha dúbida agora. Cando bootstrapping estamos cargando os ficheiros de configuración YAML. Entón, iso crea obxectos para todos, que non precisamos?
Por exemplo: eu teño unha aula algo que é usado só algunhas veces. El crea un obxecto ou é intelixente dabondo para cargar a través de funcións autoload cando estou chamando método getInstance (). Eu non conseguir isto, é dicir, o por que.
Grazas
Non, as clases son cargadas só cando da súa primeira requirida.
No getInstance () exemplo a clase é instanciada como:
$ Class = Clase:: getInstance ();
No canto de:
$ Clase = new Clase ();
Xeralmente isto é usado na implantación do estándar Singleton.
[...] Deixar usa no seu proxecto de DI dunha forma fácil. Steven Lloyd Watkin gastar o seu tempo en escribir un tutorial.It inicio rápido paga a pena mencionar que Symfony DI Container é unha biblioteca independente dispoñible como un [...] Symfony