PHP-DI和依赖注入的最佳实践

栏目: PHP · 发布时间: 6年前

内容简介:PHP-DI是用PHP编写的、强大的和实用的、框架无关的依赖注入容器。这是一个关于如何使用PHP-DI和依赖注入的最佳实践指南。文章来源于PHP-DI,作者:Matthieu Napoli和贡献者。PHP-DI是用PHP编写的、强大的和实用的、框架无关的依赖注入容器。原文地址(英文):

PHP-DI是用 PHP 编写的、强大的和实用的、框架无关的依赖注入容器。这是一个关于如何使用PHP-DI和依赖注入的最佳实践指南。

文章来源于PHP-DI,作者:Matthieu Napoli和贡献者。PHP-DI是用PHP编写的、强大的和实用的、框架无关的依赖注入容器。

原文地址(英文): http://php-di.org/doc/best-pr...

PHP-DI在【本站实用开源目录】链接: http://www.worldlink.com.cn/o...

这是一个关于如何使用PHP-DI和依赖注入的最佳实践指南。

虽然它可能不包括每个案例,并满足每个人,但它可作为抛砖引玉,以帮助您开始依赖注入。

如果你不同意该指南中解释的任何内容,那没关系。你应该对这些问题提出自己的见解:)。它不会阻止你以你想要的方式使用PHP-DI。

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

以下是一些基本规则:

不要直接从容器中获取一个条目(总是使用依赖注入)

更普遍的是,编写代码解耦的容器

针对接口的类型约束,要在容器的配置中配置使用哪种实现

#编写控制器

在控制器中使用依赖注入通常是最痛苦的。

如果我们以Symfony 2为例(但这通常适用于每个框架),这里有你的选择:

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

这是不好的,见规则n°1。

在构造函数中注入依赖性(在Symfony中作为服务的控制器)

这是痛苦的,当你有5个以上的依赖项,你的构造函数是15行样板代码

在属性中注入依赖性

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

例如:

class UserController
{
    /**
     * @Inject
     * @var FormFactoryInterface
     */
    private $formFactory;
    public function createForm($type, $data, $options)
    {
        // $this->formFactory->...
    }
}

如你所见,这个解决方案需要很少的代码,很容易理解和利于IDE支持(自动完成,重构,...)。

属性注入通常让人皱眉头,这是有一定的原因的:

注入私有属性破坏了封装

它不是一个显式的依赖:没有约定,说你的类需要设置属性以工作

如果使用PHP-DI的注解来标记要注入的依赖关系,那么您的类依赖于容器(请参见上面的第2条规则)

如果您遵循关于如何编写应用程序的一般最佳实践,您的控制器将不包含业务逻辑(仅对模型进行路由调用并绑定返回的值以查看)。

因此:

你不会对它进行单元测试(这并不意味着你不会在接口上写功能测试)

你不需要在别处重用它

如果你改变框架,你可能不得不重写它(或其部分)(因为大多数依赖,如请求、响应、模板系统等将改变)

此解决方案提供了许多优点,没有主要的缺点,因此我们建议在控制器中使用注解。

编写服务

给定一个服务旨在被重用、测试和独立于你的框架,我们不建议使用注解注入依赖。 相反,我们建议使用构造函数注入和自动装配:

class OrderService implements OrderServiceInterface
{
    private $paymentService;
    public function __construct(PaymentServiceInterface $paymentService)
    {
        $this->paymentService = $paymentService;
    }
    public function processOrder($order)
    {
        $this->paymentService->...
    }
}

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

在某些情况下,使用自动装配还不够,因为一些参数将是一个标量(string,int,...)。 此时,您需要明确定义要在该标量参数中注入的内容,为此,您可以:

定义方法/类的全部注入(即,每个参数)。

例如:

<?php // config.php return [

// ...
OrderService::class => DI\object()
    ->constructor(DI\get(SomeOtherService::class), 'a value'),

];

或者只定义标量参数,让PHP-DI使用自动装配。

例如:

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

这个解决方案通常是优选的,避免重新定义一切。

旁注:如规则n°3中所述,我们建议对接口进行类型约束。 在这种情况下,您将需要将接口映射到容器在配置中应该使用的实现:

使用库

当使用库,如日志记录器,ORM,...有时需要配置它们。

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

匿名函数允许你编写真正的PHP代码,这是伟大的,因为你可以使用库的文档,得到IDE支持,作为一个PHP开发人员,你懂的:)。

这里是一个例子,Monolog,一个PHP记录器:

<?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接口进行注入。 这样,我们可以随时用任何PSR-3记录器替换Monolog,只需更改此配置即可。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Effective Java

Effective Java

Joshua Bloch / Addison-Wesley Professional / 2018-1-6 / USD 54.99

The Definitive Guide to Java Platform Best Practices—Updated for Java 9 Java has changed dramatically since the previous edition of Effective Java was published shortly after the release of Jav......一起来看看 《Effective Java》 这本书的介绍吧!

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具