本文探讨如何构建一个简单的依赖注入容器(DI 容器)PHP 包。文中所有代码,包括 PHPDoc 注解和单元测试(100% 代码覆盖率),都已上传至 GitHub 仓库,并在 Packagist 上列出。
关键要点:
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中文网其他相关文章!