Quick Start Symfony DI (Inxección de Dependencia) Tutorial

Por Watkin Steven Lloyd , sábado 14 de agosto de 2010 14:21

¿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:

  1. 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
  2. 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
  3. 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.

4 Responses to "Quick Start Symfony DI (Inxección de Dependencia) Tutorial"

  1. [...] 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 [...]

  2. Hari KT di:

    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

  3. 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.

  4. [...] 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

Deixe unha resposta













Panorama Tema por Themocracy

6 visitantes en liña agora
2 persoas, 4 bots, 0 membros
Max visitantes hoxe: 11 ás 01:06 UTC
Este mes: 22 en 2011/08/06 12:30 UTC
Este ano: 130 en 28-03-2011 22:40 UTC
Todas as horas: 130 en 28-03-2011 10:40 UTC