liftkit/dependency-injection

LiftKit 的依赖注入库

v1.5.1 2023-03-15 11:41 UTC

This package is auto-updated.

Last update: 2024-09-15 14:59:07 UTC


README

一个简单但功能丰富的依赖注入库,具有自动类解析。

创建新的容器

use LiftKit\DependencyInjection\Container\Container;

$container = new Container;

规则

规则是一个匿名函数,用于定义如何创建一个对象。

$container->setRule(
  'SomeRule',
  function ()
  {
    return new SomeClass();
  }
);

$someObject = $container->getObject('SomeRule');

// $someObject will be an instance of SomeClass

单例规则

默认情况下,每次调用 getObject 时规则都会执行。为了强制它只执行一次,我们使用 setSingletonRule。对于该规则的每次 getObject 调用都将返回相同的对象。

$container->setSingletonRule(
  'SomeSingletonRule',
  function ()
  {
    return new SomeClass();
  }
);

$object1 = $container->getObject('SomeSingletonRule');
$object2 = $container->getObject('SomeSingletonRule');

// $object1 and $object2 are the same object

带参数的规则

某些规则可以传递参数。传递给 setRule 回调的第一个参数是容器本身。后续的参数是由传递给 getObject 的可选参数数组提供的。

$container->setRule(
  'SomeRuleWithParameters',
  function (Container $container, $arg1, $arg2)
  {
    return new SomeClass($arg1, $arg2);
  }
);

$someObject = $container->getObject('SomeRuleWithParameters', ['arg1', 'arg2']);

// SomeClass will be contructed with 'arg1' and 'arg2' as the parameters to is constructor.

引用其他规则的规则

$container->setRule(
  'Rule1',
  function ()
  {
    return new SomeClass;
  }
);

$container->setRule(
  'Rule2',
  function (Container $container)
  {
    return new OtherClass($container->getObject('Rule1'));
  }
);

$someObject = $container->getObject('Rule2');

// $someObject will be an instance of OtherClass with a new instance of SomeClass injected as its
// first contructor argument.

覆盖规则

可以通过重新定义来覆盖规则。这对于模块化代码非常有用。

$conatiner->setRule(
  'SomeRule',
  function ()
  {
    return new SomeClass;
  }
);

$container->setRule(
  'SomeRule',
  function ()
  {
    return new OtherClass;
  }
);

$someObject = $container->getObject('SomeRule');

// $someobject will be an instance of OtherClass

存储实例

您还可以存储已创建的对象并将其绑定到规则。

$someObject = new SomeObject;

$container->storeObject('SomeRule', $someObject);

$otherObject = $container->getObject('SomeRule');

// $someObject and $otherObject are the some object

自动解析

容器还可以将规则绑定到类。可以自动创建类的实例,方法是查看每个构造函数参数的类型提示。在下面的示例中,在创建 A 的实例之前,将自动创建 B 的实例。然后,将新创建的 B 实例注入到 A 的构造函数中。

class A
{
  private $b;
  
  public function __construct (B $b)
  {
    $this->b = $b;
  }
  
  public function getB ()
  {
    return $this->b;
  }
}

class B
{
  // placeholder class
}

$container->bindRuleToClass(
  'GiveMeANewA',
  A::class
);

$a = $container->getObject('GiveMeANewA');
$b = $a->getB();

// $a is a new instance of A. $b is a new instance of b.

带规则的自动解析

在某些情况下,您可能需要告诉注入器,当它遇到特定类的类型提示时,需要根据不同的规则创建实例。在下面的示例中,为 B 的构造创建了一个规则。当容器意识到在创建 A 时需要 B 的实例时,它将遵循该规则首先创建 B。在这种情况下,A 的构造函数被注入了由规则 'GiveMeANewB' 创建的 B 实例来创建 $a

$container->setRule(
  'GiveMeANewB',
  function ()
  {
    $b = new B;
    
    $b->createdByRule = true;
    
    return $b;
  }
);

$container->bindClassToRule(
  B::class,
  'GiveMeANewB'
);

$a = $container->getObject('GiveMeANewA');
$b = $a->getB();

// $b->createdByRule is true

带参数的自动解析

有时,需要将额外的参数传递给正在自动创建的新实例的构造函数。在下面的示例中,变量 $param1$param2 将注入到 C 的构造函数中,而 B 将由上面的规则 'GiveMeANewB' 创建。任何额外的参数都必须位于构造函数参数列表的末尾。

class C
{
  private $b;
  private $param1;
  private $param2;
  
  public function __construct (B $b, $param1, $param2)
  {
    $this->b      = $b;
    $this->param1 = $param1;
    $this->param2 = $param2;
  }
  
  public function getB ()
  {
    return $this->b;
  }
  
  public function getParam1 ()
  {
    return $this->param1;
  }
  
  public function getParam2 ()
  {
    return $this->param2;
  }
}

$container->bindRuleToClass(
  'GiveMeANewC',
  C::class
);

$param1 = 1;
$param2 = 2;

$c = $container->getObject(
  'GiveMeANewC',
  [
    $param1,
    $param2,
  ]
);

$b = $c->getB();
$cParam1 = $c->getParam1();
$cParam2 = $c->getParam2();

// $b is an instance of B
// $cParam1 is 1
// $cParam2 is 2

将类绑定到别名

有时,您可能希望当容器遇到特定的类型提示时解析为子类。在下面的示例中,将向 A 注入 D 的新实例,而不是 B 的实例。

class D extends B
{
  // placeholder class
}

$container->bindClassToAlias(
  B::class,
  D::class
);

$a = $container->getObject('GiveMeANewA');
$d = $a->getB();

// $d is an instance of D