- 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 多个对象。