2.3. 最佳实践指南

未匹配的标注

最佳实践

这是一本关于如何最好地使用PHP-DI和依赖注入的权威指南。

尽管它可能无法涵盖所有情况并能让所有人满意,但它可以帮助你更好的入门依赖注入

如果您不同意该指南中的内容,没关系。 任何事情是你都应该保持自己的观点 ;)。这不会阻止你按自己的想法使用PHP-DI

使用容器和依赖项注入的规则

以下是一些基本规则:

  1. 永远不要直接从容器中获取条目(始终使用依赖项注入)
  2. 编写与容器分离的代码
  3. 针对接口做类型提示, 将接口的实现配置在容器配置中

编写controllers

controllers中使用依赖注入通常是最痛苦的地方。

如果我们以Symfony 2为例(通常适用于很多框架),则可以选择以下选项:

  • 将容器注入控制器中,并调用$ container-> get(...)

这非常糟糕,请参阅规则1。

当您有超过5个依赖项时,这是很痛苦的,您的构造函数就会像这15行样板代码

  • 在属性中注入依赖项

这是我们建议的解决方案。

例:

class UserController
{
    /**
     * @Inject
     * @var FormFactoryInterface
     */
    private $formFactory;

    public function createForm($type, $data, $options)
    {
        // $this->formFactory->...
    }
}

如您所见,此解决方案只需要很少的代码,易于理解并且获得了IDE的支持(自动补全,重构等)。

属性注入通常不受欢迎,理由如下:

  • 注入私有属性会破坏封装
  • 它不是显式依赖:没有协议说明您的类需要将该属性才能工作
  • 如果您使用PHP-DI的注解来标记要注入的依赖项,则您的类依赖于容器(违反了规则2)

但是,如果您照抄最佳实践,那您的controllers将不包含业务逻辑(仅将调用路由到模型并将绑定的值绑定到视图)。

所以:

  • 你不会对它进行单元测试 (但这并不意味着您不会在界面上编写功能测试)
  • 您将不需要在其他地方重用它
  • 如果您更改框架,可能得重写controllers(或其中的一部分)
    (因为大多数依赖项(如请求,响应,模板系统等)都已更改)

该解决方案提供了许多好处,而没有重大缺点,因此我们建议在控制器中使用注解.

编写 services

鉴于service旨在重用,测试并独立于您的框架, 因此我们不建议您使用注解注入依赖项.

相反, 我们建议使用 构造函数注入和自动装配:

class OrderService implements OrderServiceInterface
{
    private $paymentService;

    public function __construct(PaymentServiceInterface $paymentService)
    {
        $this->paymentService = $paymentService;
    }

    public function processOrder($order)
    {
        $this->paymentService->...
    }
}

通过使用自动装配(默认情况下启用), 您无需在配置中绑定构造函数的参数。PHP-DI会通过检查来猜测需要注入对象的参数的类型。

在某些情况下,自动装配是不够的,因为某些参数将是标量(字符串,整数等)。此时,您将需要显式定义要在该标量参数中注入的内容,为此,您可以:

  • 使用DI\create()定义方法或类的所有注入 (即每个参数) 。

例:

<?php
// config.php
return [
    // ...
    OrderService::class => DI\create()
        ->constructor(DI\get(SomeOtherService::class), 'a value'),
];
  • 或者使用DI\autowire()只定义标量参数,然后PHP-DI 会自动装配剩余部分。

例:

<?php
// config.php
return [
    // ...
    OrderService::class => DI\autowire()
        ->constructorParameter('paramName', 'a value'),
];

由于避免重新定义所有内容,因此通常首选此方案。

旁注: 根据规则3,,我们建议 针对接口进行类型提示。在这种情况下,
您将需要将接口映射到容器应在配置中使用的实现:

<?php
// config.php
return [
    // ...
    OrderServiceInterface::class => DI\get(OrderService::class),
];

使用库

使用loggers, ORMs之类的库时,你有时需要对其进行配置。

在这种情况下,建议您在配置文件中定义这些依赖项。当配置有些复杂时,我们还建议使用匿名函数。

匿名函数允许您编写真实的PHP代码,这很棒棒,因为您
可以使用该库的文档,可以获得IDE支持,并且您是PHP开发人员,所以,您懂得该怎么使用这门语言;)。

这是一个 Monolog,做logger的例子:

<?php
// config.php

use Monolog\Logger;
use Monolog\Handler\StreamHandler;

return [
    // ...

    Psr\Log\LoggerInterface::class => DI\factory(function () {
        $logger = new Logger('mylog');

        $fileHandler = new StreamHandler('path/to/your.log', Logger::DEBUG);
        $fileHandler->setFormatter(new LineFormatter());
        $logger->pushHandler($fileHandler);

        return $logger;
    }),
];

当然了,如你所见,我们使用 PSR-3 interface 进行注入。 这样我们只要更改一下配置,就可以用任意的PSR-3 logger来替换Monolog

本文章首发在 LearnKu.com 网站上。

本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://learnku.com/docs/php-di/6.0/best...

译文地址:https://learnku.com/docs/php-di/6.0/best...

上一篇 下一篇
贡献者:3
讨论数量: 0
发起讨论 查看所有版本


暂无话题~