首页 > 后端开发 > php教程 > 如何构建自己的依赖注入容器

如何构建自己的依赖注入容器

Jennifer Aniston
发布: 2025-02-15 13:22:12
原创
610 人浏览过

本文探讨如何构建一个简单的依赖注入容器(DI 容器)PHP 包。文中所有代码,包括 PHPDoc 注解和单元测试(100% 代码覆盖率),都已上传至 GitHub 仓库,并在 Packagist 上列出。

How to Build Your Own Dependency Injection Container

关键要点:

  • 构建 DI 容器有助于开发者理解依赖注入的基本原理和容器的工作机制。
  • DI 容器主要有两个作用:“依赖注入”和“容器”。它需要能够使用构造器注入或设置器注入方法来实例化和包含服务。
  • Symfony 依赖注入容器可作为创建自定义容器的参考。它将容器配置分为参数和服务,允许安全存储应用程序密钥。
  • 创建 DI 容器涉及创建项目目录、创建 composer.json 文件以及实现容器互操作接口。它还涉及创建异常和引用类。
  • 容器类需要包含用于检索服务、检查服务是否已定义、解析参数和初始化服务的方法。它还应该具有防止循环引用的保护机制。

规划我们的依赖注入容器

首先,我们将“依赖注入容器”拆分为两个角色:“依赖注入”和“容器”。

依赖注入最常用的两种方法是构造器注入和设置器注入,即通过构造器参数或方法调用传递类依赖项。如果我们的容器能够实例化和包含服务,则它需要能够执行这两种操作。

要成为一个容器,它必须能够存储和检索服务的实例。与创建服务相比,这是一个相当简单的任务,但仍然值得考虑。container-interop 包提供了一组容器可以实现的接口。主要接口是 ContainerInterface,它定义了两种方法:一种用于检索服务,另一种用于测试服务是否已定义。

interface ContainerInterface
{
    public function get($id);
    public function has($id);
}
登录后复制
登录后复制

学习其他依赖注入容器

Symfony 依赖注入容器允许我们通过多种不同方式定义服务。在 YAML 中,容器的配置可能如下所示:

parameters:
    # ...
    mailer.transport: sendmail

services:
    mailer:
        class:     Mailer
        arguments: ["%mailer.transport%"]
    newsletter_manager:
        class:     NewsletterManager
        calls:
            - [setMailer, ["@mailer"]]
登录后复制
登录后复制

Symfony 将容器配置分为参数和服务的配置方式非常有用。这允许将 API 密钥、加密密钥和身份验证令牌等应用程序密钥存储在从源代码存储库中排除的参数文件中。

在 PHP 中,Symfony 依赖注入组件的相同配置如下所示:

use Symfony\Component\DependencyInjection\Reference;

// ...
$container->setParameter('mailer.transport', 'sendmail');

$container
    ->register('mailer', 'Mailer')
    ->addArgument('%mailer.transport%');

$container
    ->register('newsletter_manager', 'NewsletterManager')
    ->addMethodCall('setMailer', array(new Reference('mailer')));
登录后复制

通过在对 setMailer 的方法调用中使用 Reference 对象,依赖注入逻辑可以检测到此值不应直接传递,而应替换为它在容器中引用的服务。这允许轻松地将 PHP 值和其他服务注入服务而不会造成混淆。

开始

首先,创建一个新的项目目录并创建一个 composer.json 文件,Composer 可以使用该文件自动加载我们的类。目前,此文件只将 SitePointContainer 命名空间映射到 src 目录。

interface ContainerInterface
{
    public function get($id);
    public function has($id);
}
登录后复制
登录后复制

接下来,因为我们将使我们的容器实现容器互操作接口,我们需要使 Composer 下载它们并将它们添加到我们的 composer.json 文件中:

parameters:
    # ...
    mailer.transport: sendmail

services:
    mailer:
        class:     Mailer
        arguments: ["%mailer.transport%"]
    newsletter_manager:
        class:     NewsletterManager
        calls:
            - [setMailer, ["@mailer"]]
登录后复制
登录后复制

除了主要的 ContainerInterface 之外,container-interop 包还定义了两个异常接口。第一个用于创建服务时遇到的常规异常,另一个用于请求的服务找不到时。我们还将向此列表中添加另一个异常,用于请求的参数找不到时。

(以下内容省略了代码实现部分,因为篇幅过长,且核心逻辑已在上文中描述。 GitHub 仓库中的完整代码包含了异常类、引用类和容器类的完整实现。)

总结

我们学习了如何创建一个简单的依赖注入容器,但是还有很多其他容器具有我们尚未实现的强大功能!

一些依赖注入容器,例如 PHP-DI 和 Aura.Di,提供了一个称为自动装配的功能。在这里,容器会猜测容器中的哪些服务应该注入到其他服务中。为此,它们使用反射 API 来查找有关构造器参数的信息。

您可以随意派生该仓库并添加自动装配等功能,这是一个很好的练习!此外,我们保留了一个公共列表,其中列出了此容器的所有已知派生版本,以便其他人可以看到您所做的工作。只需使用下面的评论与我们分享您的工作,我们将确保将其添加进去。

您也可以使用下面的评论与我们联系。让我们知道您想澄清或解释的内容,或者您发现的任何错误。

(以下内容省略了 FAQs 部分,因为其内容与上文高度重复,且篇幅过长。)

以上是如何构建自己的依赖注入容器的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板