Symfony 服務容器:使用 XML 或 YAML 文件描述服務

本文首發於 Symfony 服務容器:使用 XML 或 YAML 文件描述服務,轉載請註明出處。

本文是依賴注入(Depeendency Injection)系列教程的第 5 篇文章,本系列教程主要講解如何使用 PHP 實現一個輕量級服務容器,教程包括:php


術語

  • Depeendency Injection 譯做 依賴注入
  • Depeendency Injection Container 譯做 依賴注入容器
  • Container 譯做 容器
  • Service Container 譯做 服務容器
  • Session 譯做 會話
  • Object-Oriented 譯做 面向對象
  • mock 譯做 模擬
  • anti-patterns 譯做 反模式
  • hardcoded 譯做 硬編碼
  • dumper 譯做 轉存器
  • loader 譯做 加載器

上一篇文章 Symfony 服務容器:使用建造者建立服務 帶領你們學習了使用 spServiceContainerBuilder 類描述待建立的服務功能。今天,咱們將學習如何使用 loader 和 dumper 結合 XML 或 YAML 文件描述待建立服務。html

SVN 版本庫有更新,若是您以前有檢出版本庫,請更新。若是尚未檢出可到 http://svn.symfony-project.co... 檢出(譯註:該版本庫已中止維護)。

Symfony 依賴注入組件提供加載服務的輔助類。默認組件包含兩種加載器:sfServiceContainerLoaderFileXml 用於加載 XML 文件;sfServiceContainerLoaderFileYaml 用於加載 YAML 文件。數據庫

在講解 XML 和 YAML 配置文件使用以前,先來看下 Symfony 提供的另一個依賴注入組件:dumper objects。服務轉存器接收一個容器對象並將該對象轉換成其它格式。固然,這個組件也能夠用於 XML 和 YAML 文件的打包處理。性能優化

爲了講解 XML 配置文件使用方法,咱們將以前使用 PHP 代碼描述服務的定義過程,經過使用 sfServiceContainerDumperXml 轉存器container.xml 配置進行定義。服務器

下面是以前定義 Zend_Mail 服務的實現:session

<?php
require_once '/PATH/TO/sfServiceContainerAutoloader.php';
sfServiceContainerAutoloader::register();

$sc = new sfServiceContainerBuilder();

$sc->
  register('mail.transport', 'Zend_Mail_Transport_Smtp')->
  addArgument('smtp.gmail.com')->
  addArgument(array(
    'auth'     => 'login',
    'username' => '%mailer.username%',
    'password' => '%mailer.password%',
    'ssl'      => 'ssl',
    'port'     => 465,
  ))->
  setShared(false)
;

$sc->
  register('mailer', '%mailer.class%')->
  addMethodCall('setDefaultTransport', array(new sfServiceReference('mail.transport')))
;

使用下面的代碼將這個服務容器轉存爲 XML 文件:負載均衡

$dumper = new sfServiceContainerDumperXml($sc);

file_put_contents('/somewhere/container.xml', $dumper->dump());

「轉存器」類構造函數第一個參數接受一個服務容器,方法 dump() 能夠將這個服務容器轉成其它格式。運行正常的話將會生成相似下方數據的 container.xml 文件:svn

<container xmlns="http://symfony-project.org/2.0/container">
  <parameters>
    <parameter key="mailer.username">foo</parameter>
    <parameter key="mailer.password">bar</parameter>
    <parameter key="mailer.class">Zend_Mail</parameter>
  </parameters>
  <services>
    <service id="mail.transport" class="Zend_Mail_Transport_Smtp" shared="false">
      <argument>smtp.gmail.com</argument>
      <argument type="collection">
        <argument key="auth">login</argument>
        <argument key="username">%mailer.username%</argument>
        <argument key="password">%mailer.password%</argument>
        <argument key="ssl">ssl</argument>
        <argument key="port">465</argument>
      </argument>
    </service>
    <service id="mailer" class="%mailer.class%">
      <call method="setDefaultTransport">
        <argument type="service" id="mail.transport">
      </argument></call>
    </service>
  </services>
</container>

XML 格式支持匿名服務。匿名服務無需定義服務名稱,可直接在使用的上下文環境中定義。當某個服務僅在某個做用域範圍內使用時,使用匿名服務會很是方便:函數

<service id="mailer" class="%mailer.class%">
   <call method="setDefaultTransport">
     <argument type="service">
       <service class="Zend_Mail_Transport_Smtp">
         <argument>smtp.gmail.com</argument>
         <argument type="collection">
           <argument key="auth">login</argument>
           <argument key="username"><span class="hljs-variable">%mailer</span>.username%</argument>
           <argument key="password"><span class="hljs-variable">%mailer</span>.password%</argument>
           <argument key="ssl">ssl</argument>
           <argument key="port"><span class="hljs-number">465</span></argument>
         </argument>
       </service>
     </argument>
   </call>
 </service>

使用這個 XML 配置文件也很是簡單,僅需一個 XML 服務加載類便可完成:工具

require_once '/PATH/TO/sfServiceContainerAutoloader.php';
sfServiceContainerAutoloader::register();

$sc = new sfServiceContainerBuilder();

$loader = new sfServiceContainerLoaderFileXml($sc);
$loader->load('/somewhere/container.xml');

相似於轉存器,「加載器」的構造函數的第一個參數同爲一個服務容器,「加載器」的 load() 方法可以從文件中讀取配置並完成將服務向「服務容器」的註冊功能。如此即可以正常使用服務容器了。

若是將 XML 轉存器替換爲 sfServiceContainerDumperYaml 類,則會以 YAML 文件生成配置文件:

require_once '/PATH/TO/sfYaml.php';

$dumper = new sfServiceContainerDumperYaml($sc);

file_put_contents('/somewhere/container.yml', $dumper->dump());
上面的代碼僅在首次加載 sfYAML 組件( http://svn.symfony-project.co...)時才能正常處理,由於它是服務容器加載器和轉存器必要的依賴。

生成的 YAML 文件內容以下:

parameters:
  mailer.username: foo
  mailer.password: bar
  mailer.class:    Zend_Mail

services:
  mail.transport:
    class:     Zend_Mail_Transport_Smtp
    arguments: [smtp.gmail.com, { auth: login, username: %mailer.username%, password: %mailer.password%, ssl: ssl, port: 465 }]
    shared:    false
  mailer:
    class: %mailer.class%
    calls:
      - [setDefaultTransport, [@mail.transport]]

但使用 XML 配置比 YAML 配置有更多優點:

  • 當 XML 文件被載入時,會使用內置的 services.xsd 文件進行校驗;
  • IDE 可自動補全 XML 文件;
  • XML 文件相比 YAML 文件效率更高;
  • XML 格式無其它擴展依賴(YAML 格式依賴於 sfYAML 組件)。

固然,你也能夠一塊兒使用這些加載器和轉存器,將某種格式文件轉存爲另一種:

// Convert an XML container service definitions file to a YAML one
$sc = new sfServiceContainerBuilder();

$loader = new sfServiceContainerLoaderFileXml($sc);
$loader->load('/somewhere/container.xml');

$dumper = new sfServiceContainerDumperYaml($sc);
file_put_contents('/somewhere/container.yml', $dumper->dump());
簡短截說,這裏不會列出全部 YAML 和 XML 格式的全部可能性。固然,你能夠很容易學會如何使用這些轉存器和加載器。

使用 YAML 或 XML 配置文件,可讓咱們可以使用 GUI 工具建立服務。同時,也給咱們帶來更多樂趣。

其1、也是最重要的一個功能就是提供引入資源的能力。一個資源能夠是任何一種配置文件:

<container xmlns="http://symfony-project.org/2.0/container">
  <imports>
    <import resource="default.xml">
  </import></imports>
  <parameters>
    
  </parameters>
  <services>
    
  </services>
</container>

imports 節點所配置的文件須要在其它配置節點以前引入。默認,會從當前文件目錄查找這個文件並引入,你也能夠經過「加載器」的第二個參數設置文件查找目錄:

$loader = new sfServiceContainerLoaderFileXml($sc, array('/another/path'));
$loader->load('/somewhere/container.xml');

甚至,能夠在 XML 配置中,定義 YAML 加載器及 YAML 配置文件名:

<container xmlns="http://symfony-project.org/2.0/container">
  <imports>
    <import resource="default.yml" class="sfServiceContainerLoaderFileYaml">
  </import></imports>
</container>

反過來也同樣:

imports:
  - { resource: default.xml, class: sfServiceContainerLoaderFileXml }

imports 提供一種靈活的方式管理服務定義文件。此外它提供了複用的可能。繼續咱們以前說到的「會話」功能。當在測試環境下,會話存儲多是一個模擬對象;相反,當使用負載均衡須要纔多臺 Web 服務器裏存儲會話數據,可能會使用相似 MySQL 數據庫進行存儲。此時,就須要一種基於配置的解決方案,並依據不一樣開發環境導入所需配置:

<container xmlns="http://symfony-project.org/2.0/container">
  <parameters>
    <parameter key="session.class">sfSessionStorage</parameter>
  </parameters>  
</container>


<container xmlns="http://symfony-project.org/2.0/container">
  <imports>
    <import resource="session.xml">
  </import></imports>

  <parameters>
    <parameter key="session.class">sfSessionTestStorage</parameter>
  </parameters>
</container>


<container xmlns="http://symfony-project.org/2.0/container">
  <imports>
    <import resource="session.xml">
  </import></imports>

  <parameters>
    <parameter key="session.class">sfMySQLSessionStorage</parameter>
  </parameters>
</container>

使用時也異常簡單:

$loader = new sfServiceContainerLoaderFileXml($sc, array(
  '/framework/config/default/',
  '/project/config/',
));
$loader->load('/somewhere/session_'.$environment.'.xml');

也許有的朋友在面對 XML 配置文件時會留下傷心的淚水,由於 XML 文件也許是世上最難以閱讀的數據格式。有 Symfony 開發經驗的朋友或許已經可以輕鬆編寫 YAML 格式配置文件。更高級一些,咱們還能夠將服務定義從一個文件中分離出來。咱們能夠將服務定義在 services.xml 文件中,並將它所需的參數定義到 parameters.xml 文件內。或者,在 parameters.yml 文件中定義所需的參數配置。此外,咱們還提供一個內置的 INI 文件加載器,它可以從標準 INI 文件讀取配置參數:

<container xmlns="http://symfony-project.org/2.0/container">
  <imports>
    <import resource="config.ini" class="sfServiceContainerLoaderFileIni">
  </import></imports>
</container>

以上示例僅涉及「加載器」和「轉存器」基本使用,但我但願您已經瞭解到 XML 和 YAML 配置文件的強大。對於哪些對服務容器及須要加載太多配置文件的性能持懷疑態度的開發者,下一篇文章或許會讓他們改變本身的觀點。因爲下一篇文章是系列文章的終章,我還將討論服務依賴可視化相關內容。

原文: http://fabien.potencier.org/s...

相關文章
相關標籤/搜索