README

依赖注入。

构建状态

Tests

Latest Stable Version Latest Unstable Version

安装

stubbles/ioc 以 Composer 包的形式分发。要将它作为您的包的依赖项安装,请使用以下命令

composer require "stubbles/ioc": "^11.0"

需求

stubbles/ioc 至少需要 PHP 8.2。

控制反转

stubbles/ioc 提供了一个非常简单易用但功能强大的 控制反转容器,它支持基于构造函数和设置器的依赖注入。 stubbles/ioc 的 IoC 容器模仿了 Google Guice 并使用类型提示注解。如果您从未听说过类型提示或注解,您应首先阅读关于这两个主题的章节

示例代码

想象一下,您正在构建一个汽车配置器。为了遵循良好的设计原则,您为汽车的所有组件定义了接口,并提供了一些实现这些组件的类。

您应用程序中的接口包括

interface Car {
    public function moveForward($miles);
}
interface Person {
    public function sayHello();
}
interface Tire {
    public function rotate();
}
interface Engine {
    public function start();
}

实现包括

class BMW implements Car {
    private $driver;
    private $engine;
    private $tire;

    public function __construct(Engine $engine, Tire $tire, Person $driver) {
        $this->engine = $engine;
        $this->tire   = $tire;
        $this->driver = $driver;
    }
    public function moveForward($miles) {
        $this->driver->sayHello();
        $this->engine->start();
        $this->tire->rotate();
    }
}

class Schst implements Person {
    public function sayHello() {
        echo "My name is Stephan\n";
    }
}

class Goodyear implements Tire {
    public function rotate() {
        echo "Rotating Goodyear tire\n";
    }
}

class TwoLitresEngine implements Engine {
    public function start() {
        echo "Starting 2l engine\n";
    }
}

没有依赖注入框架

要创建 Car 实现的一个新实例,需要以下代码

    $tire   = new Goodyear();
    $engine = new TwoLitresEngine();
    $schst  = new Schst();

    $bmw    = new BMW($engine, $tire, $schst);
    $bmw->moveForward(50);

手动创建对象如这种方式有几个缺点

  • 您的应用程序绑定到具体的实现,而不是接口
  • 更改实现意味着更改现有代码,这可能会破坏它
  • 对象的创建散布在您的应用程序中

当然,真实的应用程序有更多类,所以事情只会变得更糟。

进入 '控制反转'

stubbles/ioc 通过提供处理所有依赖注入的功能来尝试解决这些问题,这使得您的应用程序没有样板代码。

此外,它允许您集中定义或模块化接口或抽象类型的具体实现。

简单示例

定义具体实现是通过 stubbles\ioc\Binder 的一个实例来完成的

$binder = new \stubbles\ioc\Binder();
$binder->bind('Car')->to('BMW');
$binder->bind('Tire')->to('Goodyear');
$binder->bind('Person')->to('Schst');
$binder->bind('Engine')->to('TwoLitresEngine');

在这段简短的代码片段中,您将上面示例中的接口绑定到它们的具体实现。

如果您现在需要一个引擎的实例,您可以使用绑定器创建一个 stubbles\ioc\Injector,它可以用来创建所需的 Engine

$injector = $binder->getInjector();
$engine = $injector->getInstance('Engine');
var_dump($engine);

现在这段代码片段将显示

object(TwoLitresEngine)#48 (0) {
}

正如预期的那样,它创建了一个具体实现的实例,您将其绑定到接口。

接下来,您可能还想用相同的方法获取 Car 的实例

    $injector = $binder->getInjector();
    $car = $injector->getInstance('Car');
    var_dump($car);
object(BMW)#33 (3) {
  ["driver:private"]=>
  NULL
  ["engine:private"]=>
  object(TwoLitresEngine)#37 (0) {
  }
  ["tire:private"]=>
  object(Goodyear)#40 (0) {
  }
}

stubbles/ioc 创建了一个新的 BMW 实例,因为您将其绑定到 Car,并且因为 BMW 的构造函数需要一个 Tire 和一个 Engine 实例,所以它也创建了这些实例。为了确定要使用的具体类,stubbles/ioc 使用了您在 stubbles\ioc\Binder 实例中定义的绑定。

你还可以看到,尽管你为Person指定了绑定,但Stubbles并没有将对象注入到$driver属性中。stubbles/ioc永远不会通过setter方法注入任何依赖。

其他特性