dc/ioc

简单的IoC容器

0.1.4 2015-06-16 11:00 UTC

This package is not auto-updated.

Last update: 2024-09-14 15:00:49 UTC


README

DC\IoC - IoC container for PHP

安装

$ composer install dc/ioc

或者将其添加到 composer.json

"require": {
	"dc/ioc": "0.*"
}
$ composer install

注册

您可以使用容器注册对象、类和工厂函数。

注册一个类

$container = new \DC\IoC\Container();
$container
	->register('\Car') // fully qualified namespace
    ->to('\IVehicle')
    ->withContainerLifetime(); // lives as long as the container

注册一个实例(实例注册不支持生命周期,它们始终与容器一样长)

$container
	->register(new \Car())
	->to('\IVehicle');

注册一个工厂函数

$container
	->register(function() {
		new \Car();
	})->to('\IVehicle');

理解生命周期

有三种可能的生命周期注册:withPerResolveLifetime()withContainerLifetime()withSingletonLifetime()。当您将类名或工厂函数传递给 register() 时可以使用这些,但如果不传递对象实例,则不能使用。

  • withPerResolveLifetime() 每次解析时都会创建一个新实例。
  • withContainerLifetime() 将从该容器解析相同的实例。
  • withSingletonLifetime() 将从所有容器解析相同的实例。

解析服务

您可以直接查询容器来解析服务。

$vehicle = $container->resolve('\IVehicle');

如果您为相同的接口或类名有多个注册,您可以使用 resolveAll()

$vehicles = $container->resolveAll('\IVehicle');

构造函数注入

使用类型提示将依赖项注入到类中。

class Trailer {
	public __construct(\IVehicle $vehicle) {
		// attach your Trailer to you IVehicle, or something
	}
}

$container->resolve("Trailer"); // you don't even have to register Trailer

如果您不想使用类型提示,可以使用 PhpDoc 注释代替。这在您想获取某个数组的数组时特别有用,因为 PHP 的类型提示语法不支持这一点。

class Trailer {
    /**
     * @param $matchesVehicles array|\IVehicle[]
     */
	public __construct(array $matchesVehicles) {

	}
}

甚至更简单

class Trailer {
    /**
     * @param $matchesVehicles \IVehicle[]
     */
	public __construct($matchesVehicles) {

	}
}

属性注入

通过容器解析的所有对象将扫描其非静态属性以查找可能的依赖项。要标记属性为可注入,它需要一个 @var 和一个 @inject PhpDoc 声明。

class Car {
   /**
    * @inject
    * @var \Trailer
    */
   private $trailer;
}

对于尚未通过容器解析的对象(即您自己构建的对象),您可以使用 inject() 方法应用属性注入。

$car = new Car();
$container->inject($car);

工厂注入

当您向注册提供工厂函数时,您可以像在构造函数中一样注入其他服务。您可以选择依赖类型提示或 PhpDoc 注释(用于注入数组)。

$container->register(function(\IFoo $foo) {
    return new Bar($foo);
})->to('\Bar');
$container->register(
	/**
     * @param $foos \IFoo[]
     */
	function(array $foos) {
		return new Bar($foos);
	})->to('\Bar');

模块

如果您有一个需要注册大量服务的大项目,实现模块可能是最佳选择。

扩展 \DC\IoC\Modules\Module 并指定您的模块名称以及它所依赖的模块。

class MyModule extends \DC\IoC\Modules\Module {
    public __construct() {
        parent::__construct("package-name", ["dc/router"]);
    }
    
    public register(\DC\IoC\Container $container) {
        $container->register('\Foo')->to('\Bar');
    }
}

在(最好在)注册您的服务之前,首先注册所有模块

$container->registerModules([new MyModule(), new \DC\Router\Module()]);

容器将尝试以正确的顺序注册任何依赖。

性能

可以在本存储库的 perf/ 文件夹中找到一些粗略的性能测试。它们显示以下(数字来自在我机器上运行的虚拟机)

  • 单个注册大约使用 600 字节内存,耗时 0.03 毫秒除非您正在注册数千个服务,否则速度和内存不应成为限制因素。对于每个页面视图少于一百个注册的典型设置,您应该期望它在大多数情况下只增加不到 25 毫秒。
  • 解析是微不足道的。返回 10 个对象的 resolveAll-调用平均耗时 0.09 毫秒(解析 10 个对象)。
  • 构造函数和函数注入使用反射完成,这通常被认为很慢。同样,解析单个接口需要 0.06 毫秒