miladrahimi/phpcontainer

该包已被废弃且不再维护。未建议替换包。

PHP项目的依赖注入(IoC)容器

v5.3.3 2023-11-30 15:37 UTC

This package is auto-updated.

Last update: 2023-11-30 22:58:30 UTC


README

Latest Stable Version Total Downloads Build codecov Scrutinizer Code Quality License

PhpContainer

使用PHP编程语言编写的依赖注入(控制反转)容器,符合PSR-11标准。

特性

  • 单例、短暂和闭包绑定
  • 显式和隐式绑定
  • 类型和命名绑定
  • 自动注入

概述

依赖反转 是面向对象设计中的一个基本概念。

它引出了诸如 依赖注入控制反转 以及创建 IoC容器 的重要思想。

对于PHP项目,有PhpContainer这个方便的工具,它提供了一个符合 PSR-11标准 的依赖注入容器(IoC容器)。

安装

要将PhpContainer集成到项目中,请使用以下Composer命令

composer require miladrahimi/phpcontainer:5.*

文档

显式绑定

显式绑定涉及直接将一个抽象与一个具体实现相连接。这种绑定可以通过使用 singleton()transient()closure() 方法实现。

use MiladRahimi\PhpContainer\Container;

$container = new Container();

$container->singleton(DatabaseInterface::class, MySQL::class);
$container->transient(MailerInterface::class, MailTrap::class);
$container->closure('sum', function($a, $b) { return $a + $b; });

$database = $container->get(DatabaseInterface::class); // An instance of MySQL
$mailer = $container->get(MailerInterface::class); // An instance of MailTrap
$sum = $container->get('sum'); // A closure: $sum(6, 7) => 13

绑定方法

  • 单例绑定:容器只创建一次具体实现,并在需要时返回它。
  • 短暂绑定:每次需要时,容器都会克隆或创建全新的具体实现。
  • 闭包绑定:仅适用于闭包。它防止容器调用闭包(默认行为)。

以下示例演示了单例绑定和短暂绑定的区别。

use MiladRahimi\PhpContainer\Container;

$container = new Container();

$container->transient(InterfaceA::class, ClassA::class);
$container->singleton(InterfaceB::class, ClassB::class);

$a1 = $container->get(InterfaceA::class);
$a1->name = 'Something';

$a2 = $container->get(InterfaceA::class);
echo $a2->name; // NULL

$b1 = $container->get(InterfaceB::class);
$b1->name = 'Something';

$b2 = $container->get(InterfaceB::class);
echo $b2->name; // 'Something'

隐式绑定

当容器需要没有特定绑定的类时,它会尝试创建一个实例。在下面的示例中,它实例化了提供的代码中的 MySQL 类。但如果它遇到无法直接实例化的抽象类或接口,将发生错误。

use MiladRahimi\PhpContainer\Container;

$container = new Container();

// No (explicit) binding here!

$database = $container->get(MySQL::class);

绑定到对象

您可以将摘要连接到特定对象。使用单例绑定可以在需要时获取原始对象,而瞬态绑定每次请求时都提供对象的新副本。

use MiladRahimi\PhpContainer\Container;

$user = new User();
$user->name = 'Milad';

$container = new Container();

$container->singleton('user', $user);
// OR
$container->transient('user', $user);

构造函数自动注入

具体类可能包含具有默认值或可以被容器解析的构造函数参数。

use MiladRahimi\PhpContainer\Container;

class Notifier implements NotifierInterface
{
    public MailInterface $mail;
    public Vonage $vonage;
    public string $sender;

    public function __constructor(MailInterface $mail, Vonage $vonage, $sender = 'PhpContainer')
    {
        $this->mail = $mail;
        $this->vonage = $vonage;
        $this->sender = $sender;
    }
}

$container = new Container();
$container->transient(MailInterface::class, MailTrap::class);
$container->transient(NotifierInterface::class, Notifier::class);

$notifier = $container->get(NotifierInterface::class);
print_r($notifier->mail);   // $mail would be an instnace of MailTrap (explicit binding)
print_r($notifier->vonage); // $vonage would be an instnace of Vonage (implicit binding)
print_r($notifier->sender); // $sender would be "PhpContainer" (default value)

使用闭包进行绑定

以下示例说明了如何使用闭包进行绑定。

use MiladRahimi\PhpContainer\Container;

$container = new Container();

$container->singleton(Config::class, function () {
    return new JsonConfig('/path/to/config.json');
});

// $config would be auto-injected
$container->singleton(Database::class, function (Config $config) {
    return new MySQL(
        $config->get('database.host'),
        $config->get('database.port'),
        $config->get('database.name'),
        $config->get('database.username'),
        $config->get('database.password')
    );
});

在单例绑定中,容器执行闭包一次,并在需要时检索结果。相反,在瞬态绑定中,容器每次需要时都会调用闭包。如果您打算将抽象绑定到闭包,而容器不需要立即执行,则可以使用closure()方法。

使用闭包解析

您可以使用call方法,允许容器执行提供的函数或闭包并解析其参数。

use MiladRahimi\PhpContainer\Container;

$container = new Container();
$container->singleton(MailInterface::class, MailTrap::class);

// Direct Closure call
$response = $container->call(function(MailerInterface $mailer) {
    return $mailer->send('info@example.com', 'Hello...');
});

// Direct function call
function sendMail(MailerInterface $mailer) {
    return $mailer->send('info@example.com', 'Hello...');
}
$response = $container->call('sendMail');

// Direct method call
class UserManager {
    function sendMail(MailerInterface $mailer) {
        return $mailer->send('info@example.com', 'Hello...');
    }
}
$response = $container->call([UserManager::class, 'sendMail']);

基于类型和基于名称的绑定

PhpContainer支持基于类型和基于名称的绑定。以下示例演示了这些类型的绑定。

use MiladRahimi\PhpContainer\Container;

$container = new Container();

// Type-based binding
$container->singleton(Database::class, MySQL::class);
$container->call(function(Database $database) {
    $database->ping();
});

// Name-based binding
$container->singleton('$number', 666);
$container->call(function($number) {
    echo $number; // 666
});

错误处理

容器可能会由于多种原因引发ContainerException。它可能在发生ReflectionException时出现,这表明提供了抽象缺少具体实现。此外,当容器无法将参数值注入具体构造函数或闭包时,也会发生此异常。

许可证

PhpContainer由Milad Rahimi创建,并按照MIT许可证发布。