前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >PHP 语言官方团队推荐的依赖注入工具

PHP 语言官方团队推荐的依赖注入工具

作者头像
Tinywan
发布2024-03-02 08:16:50
1170
发布2024-03-02 08:16:50
举报
文章被收录于专栏:开源技术小栈开源技术小栈

依赖注入容器

依赖注入(Dependency Injection,DI)容器就是一个对象,它知道怎样初始化并配置对象及其依赖的所有对象。

安装

代码语言:javascript
复制
composer require php-di/php-di

基本用法

1.使用依赖注入

首先,让我们使用依赖注入来编写代码,而不考虑PHP-DI:

代码语言:javascript
复制
class Mailer
{
    public function mail($recipient, $content)
    {
        // send an email to the recipient
    }
}
代码语言:javascript
复制
class UserManager
{
    private $mailer;

    public function __construct(Mailer $mailer)
    {
        $this->mailer = $mailer;
    }

    public function register($email, $password)
    {
        // The user just registered, we create his account
        // ...

        // We send him an email to say hello!
        $this->mailer->mail($email, 'Hello and welcome!');
    }
}

正如我们所看到的, UserManagerMailer 作为构造器参数:这就是依赖注入!

2.创建容器

您可以非常轻松地创建一个为开发预先配置的容器实例:

代码语言:javascript
复制
$container = new DI\Container();

如果你想注册定义文件(在PHP定义中解释)或调整一些选项,你可以使用容器构建器:

代码语言:javascript
复制
$builder = new DI\ContainerBuilder();
$builder->...
$container = $builder->build();

3.创建对象

如果没有PHP-DI,我们将不得不像这样手动“连接”依赖项:

代码语言:javascript
复制
$mailer = new Mailer();
$userManager = new UserManager($mailer);

相反,我们可以让PHP-DI找出依赖关系:

代码语言:javascript
复制
$userManager = $container->get('UserManager');

在后台,PHP-DI将创建一个Mailer对象和一个UserManager对象。

它怎么知道要注入什么?容器使用一种称为自动装配的技术。这不是PHP-DI独有的,但这仍然很棒。它将扫描代码并查看构造函数中需要哪些参数。

在我们的示例中, UserManager 构造函数接受一个 Mailer 对象:PHP-DI知道它需要创建一个对象。非常简单,但非常有效。

webman 框架应用

在webman里依赖自动注入是可选功能,此功能默认关闭。如果你需要依赖自动注入,推荐使用php-di,以下是webman结合php-di的用法。

安装

代码语言:javascript
复制
composer require psr/container ^1.1.1 php-di/php-di ^6 doctrine/annotations ^1.14

修改配置config/container.php,其最终内容如下:

代码语言:javascript
复制
$builder = new \DI\ContainerBuilder();
$builder->addDefinitions(config('dependence', []));
$builder->useAutowiring(true);
$builder->useAnnotations(true);
return $builder->build();

config/container.php里最终返回一个符合PSR-11规范的容器实例。如果你不想使用 php-di ,可以在这里创建并返回一个其它符合PSR-11规范的容器实例。

构造函数注入

新建app/service/Mailer.php(如目录不存在请自行创建)内容如下:

代码语言:javascript
复制
<?php
namespace app\service;

class Mailer
{
    public function mail($email, $content)
    {
        // 发送邮件代码省略
    }
}

app/controller/UserController.php内容如下:

代码语言:javascript
复制
<?php
namespace app\controller;

use support\Request;
use app\service\Mailer;

class UserController
{
    private $mailer;

    public function __construct(Mailer $mailer)
    {
        $this->mailer = $mailer;
    }

    public function register(Request $request)
    {
        $this->mailer->mail('hello@webman.com', 'Hello and welcome!');
        return response('ok');
    }
}

正常情况下,需要以下代码才能完成app\controller\UserController的实例化:

代码语言:javascript
复制
$mailer = new Mailer;
$user = new UserController($mailer);

当使用php-di后,开发者无需手动实例化控制器中的Mailer,webman会自动帮你完成。如果在实例化Mailer过程中有其它类的依赖,webman也会自动实例化并注入。开发者不需要任何的初始化工作。

注意必须是由框架或者php-di创建的实例才能完成依赖自动注入,手动new的实例无法完成依赖自动注入,如需注入,需要使用support\Container接口替换new语句,例如:

代码语言:javascript
复制
use app\service\UserService;
use app\service\LogService;
use support\Container;

// new关键字创建的实例无法依赖注入
$user_service = new UserService;
// new关键字创建的实例无法依赖注入
$log_service = new LogService($path, $name);

// Container创建的实例可以依赖注入
$user_service = Container::get(UserService::class);
// Container创建的实例可以依赖注入
$log_service = Container::make(LogService::class, [$path, $name]);

注解注入

除了构造函数依赖自动注入,我们还可以使用注解注入。继续上面的例子,app\controller\UserController更改成如下:

代码语言:javascript
复制
<?php
namespace app\controller;

use support\Request;
use app\service\Mailer;
use DI\Annotation\Inject;

class UserController
{
    /**
     * @Inject
     * @var Mailer
     */
    private $mailer;

    public function register(Request $request)
    {
        $this->mailer->mail('hello@webman.com', 'Hello and welcome!');
        return response('ok');
    }
}

这个例子通过 @Inject 注解注入,并且由 @var 注解声明对象类型。这个例子和构造函数注入效果一样,但是代码更精简。

注意webman在1.4.6版本之前不支持控制器参数注入,例如以下代码当webman<=1.4.6时是不支持的

代码语言:javascript
复制
<?php
namespace app\controller;

use support\Request;
use app\service\Mailer;

class UserController
{
    // 1.4.6版本之前不支持控制器参数注入
    public function register(Request $request, Mailer $mailer)
    {
        $mailer->mail('hello@webman.com', 'Hello and welcome!');
        return response('ok');
    }
}

自定义构造函数注入

有时候构造函数传入的参数可能不是类的实例,而是字符串、数字、数组等数据。例如Mailer构造函数需要传递smtp服务器ip和端口:

代码语言:javascript
复制
<?php
namespace app\service;

class Mailer
{
    private $smtpHost;

    private $smtpPort;

    public function __construct($smtp_host, $smtp_port)
    {
        $this->smtpHost = $smtp_host;
        $this->smtpPort = $smtp_port;
    }

    public function mail($email, $content)
    {
        // 发送邮件代码省略
    }
}

这种情况无法直接使用前面介绍的构造函数自动注入,因为php-di无法确定smtp_host smtp_port的值是什么。这时候可以尝试自定义注入。

config/dependence.php(文件不存在请自行创建)中加入如下代码:

代码语言:javascript
复制
return [
    // ... 这里忽略了其它配置
    
    app\service\Mailer::class =>  new app\service\Mailer('192.168.1.11', 25);
];

这样当依赖注入需要获取app\service\Mailer实例时将自动使用这个配置中创建的app\service\Mailer实例。

我们注意到,config/dependence.php 中使用了new来实例化Mailer类,这个在本示例没有任何问题,但是想象下如果Mailer类依赖了其它类的话或者Mailer类内部使用了注解注入,使用new初始化将不会依赖自动注入。解决办法是利用自定义接口注入,通过Container::get(类名) 或者 Container::make(类名, [构造函数参数])方法来初始化类。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2024-03-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 开源技术小栈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 依赖注入容器
  • 安装
  • 基本用法
    • 1.使用依赖注入
      • 2.创建容器
        • 3.创建对象
        • webman 框架应用
          • 安装
            • 构造函数注入
              • 注解注入
                • 自定义构造函数注入
                相关产品与服务
                容器服务
                腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档