- Symfony 教程
- Symfony - 首頁
- Symfony - 簡介
- Symfony - 安裝
- Symfony - 架構
- Symfony - 元件
- Symfony - 服務容器
- Symfony - 事件與事件監聽器
- Symfony - 表示式
- Symfony - 捆綁包
- 建立簡單的Web應用程式
- Symfony - 控制器
- Symfony - 路由
- Symfony - 檢視引擎
- Symfony - Doctrine ORM
- Symfony - 表單
- Symfony - 驗證
- Symfony - 檔案上傳
- Symfony - Ajax 控制
- Cookie & 會話管理
- Symfony - 國際化
- Symfony - 日誌記錄
- Symfony - 郵件管理
- Symfony - 單元測試
- Symfony - 高階概念
- Symfony - REST 版本
- Symfony - CMF 版本
- 完整的執行示例
- Symfony 有用資源
- Symfony - 快速指南
- Symfony - 有用資源
- Symfony - 討論
Symfony - 服務容器
在任何應用程式中,隨著應用程式的增長,物件往往會增加。隨著物件數量的增加,物件之間的依賴關係也會增加。為了使應用程式成功,需要正確處理物件依賴關係。
如元件章節所述,Symfony 提供了一個簡單有效的元件 **DependencyInjection** 來處理物件依賴關係。服務容器是一個包含物件的容器,其中物件之間具有正確解析的依賴關係。讓我們在本節中學習如何使用 DependencyInjection 元件。
讓我們建立一個 **Greeter** 類。Greeter 類的目的是像以下示例所示那樣向用戶問好。
$greeter = new Greeter('Hi');
$greeter->greet('Jon'); // print "Hi, Jon"
Greeter 類的完整程式碼如下所示。
class Greeter {
private $greetingText;
public function __construct($greetingText) {
$this->greetingText = $greetingText;
}
public function greet($name) {
echo $this->greetingText . ", " . $name . "\r\n";
}
}
現在,讓我們將 Greeter 類新增到服務容器中。Symfony 提供了 **ContainerBuilder** 來建立一個新的容器。建立容器後,可以使用容器的 register 方法將其中的 Greeter 類註冊到容器中。
use Symfony\Component\DependencyInjection\ContainerBuilder;
$container = new ContainerBuilder();
$container
->register('greeter', 'Greeter')
->addArgument('Hi');
這裡,我們使用了靜態引數來指定問候語文字“Hi”。Symfony 也提供了動態設定引數的功能。要使用動態引數,我們需要選擇一個名稱並在 % 之間指定它,並且可以使用容器的 **setParameter** 方法設定引數。
$container = new ContainerBuilder();
$container
->register('greeter', 'Greeter')
->addArgument('%greeter.text%');
$container->setParameter('greeter.text', 'Hi');
我們已經註冊了一個帶有正確設定的 Greeter 類。現在,我們可以要求容器使用容器的 **get** 方法提供一個正確配置的 Greeter 物件。
$greeter = $container->get('greeter');
$greeter->greet('Jon'); // prints "Hi, Jon"
我們已經成功地將一個類 Greeter 註冊到容器中,從容器中獲取了它並使用了它。現在,讓我們建立另一個類 **User**,它使用 Greeter 類,並看看如何註冊它。
class User {
private $greeter;
public $name;
public $age;
public function setGreeter(\Greeter $greeter) {
$this->greeter = $greeter;
}
public function greet() {
$this->greeter->greet($this->name);
}
}
User 類透過其一個 setter 方法 **setGreeter** 獲取 Greeter 類。對於這種情況,Symfony 提供了一個方法 **addMethodCall** 和一個類 **Reference** 來引用另一個類,如下面的程式碼所示。
use Symfony\Component\DependencyInjection\Reference;
$container
->register('user', 'User')
->addMethodCall('setGreeter', array(new Reference('greeter')));
最後,我們註冊了兩個類 **Greeter** 和 **User**,它們之間存在著緊密的關聯。現在,我們可以安全地從容器中獲取正確配置了 Greeter 類的 User 物件,如下面的程式碼所示。
$container->setParameter('greeter.text', 'Hi');
$user = $container->get('user');
$user->name = "Jon";
$user->age = 20;
$user->greet(); // Prints "Hi, Jon"
我們已經看到了如何使用 PHP 本身在容器中配置物件。Symfony 還提供了其他機制,例如 XML 和 YAML 配置檔案。讓我們看看如何使用 YAML 配置容器。為此,請安裝 **symfony/config** 和 **symfony/yaml** 元件以及 **symfony/dependency-injection** 元件。
cd /path/to/dir mkdir dependency-injection-example cd dependency-injection-example composer require symfony/dependency-injection composer require symfony/config composer require symfony/yaml
YAML 配置將寫入一個單獨的檔案 **services.yml** 中。YAML 配置由兩個部分組成:**parameters** 和 **services**。Parameters 部分定義所有必需的引數。Services 部分定義所有物件。Services 部分進一步細分為多個部分,即 **class、arguments** 和 **calls**。Class 指定實際類。Arguments 指定建構函式的引數。最後,calls 指定 setter 方法。可以使用 @ 符號引用另一個類,例如 @greeter。
parameters:
greeter.text: 'Hello'
services:
greeter:
class: Greeter
arguments: ['%greeter.text%']
user:
class: User
calls:
- [setGreeter, ['@greeter']]
現在,可以使用 **FileLoader** 和 **YamlFileLoader** 載入和配置 services.yml,如下面的程式碼所示。
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
$yamlContainer = new ContainerBuilder();
$loader = new YamlFileLoader($yamlContainer, new FileLocator(__DIR__));
$loader->load('services.yml');
$yamlUser = $yamlContainer->get('user');
$yamlUser->name = "Jon";
$yamlUser->age = 25;
$yamlUser->greet();
完整的程式碼列表如下所示。
main.php
<?php
require __DIR__ . '/vendor/autoload.php';
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
use Symfony\Component\DependencyInjection\Reference;
class Greeter {
private $greetingText;
public function __construct($greetingText) {
$this->greetingText = $greetingText;
}
public function greet($name) {
echo $this->greetingText . ", " . $name . "\r\n";
}
}
class User {
private $greeter;
public $name;
public $age;
public function setGreeter(\Greeter $greeter) {
$this->greeter = $greeter;
}
public function greet() {
$this->greeter->greet($this->name);
}
}
$container = new ContainerBuilder();
$container
->register('greeter', 'Greeter')
->addArgument('%greeter.text%');
$container
->register('user', 'User')
->addMethodCall('setGreeter', array(new Reference('greeter')));
$container->setParameter('greeter.text', 'Hi');
$greeter = $container->get('greeter');
$greeter->greet('Jon');
$user = $container->get('user');
$user->name = "Jon";
$user->age = 20;
$user->greet();
$yamlContainer = new ContainerBuilder();
$loader = new YamlFileLoader($yamlContainer, new FileLocator(__DIR__));
$loader->load('services.yml');
$yamlHello = $yamlContainer->get('greeter');
$yamlHello->greet('Jon');
$yamlUser = $yamlContainer->get('user');
$yamlUser->name = "Jon";
$yamlUser->age = 25;
$yamlUser->greet();
?>
services.yml
parameters:
greeter.text: 'Hello'
services:
greeter:
class: Greeter
arguments: ['%greeter.text%']
user:
class: User
calls:
- [setGreeter, ['@greeter']]
Symfony Web 框架廣泛使用依賴注入元件。所有元件都由集中式服務容器繫結。Symfony Web 框架透過 **container** 屬性在其所有 **Controller** 中公開容器。我們可以透過它獲取其中註冊的所有物件,例如 logger、mailer 等。
$logger = $this->container->get('logger');
$logger->info('Hi');
要查詢容器中註冊的物件,請使用以下命令。
cd /path/to/app php bin/console debug:container
在安裝章節中建立的 **hello** Web 應用程式中大約有 200 多個物件。