椭圆形/容器反射

提供自动装配功能的Psr-11容器装饰器

1.0.4 2018-02-23 09:45 UTC

This package is auto-updated.

Last update: 2024-08-26 00:33:08 UTC


README

本软件包提供了一种Psr-11容器装饰器,使其能够自动装配到任何Psr-11容器实现中。

要求 php >= 7.0

安装 composer require ellipse/container-reflection

运行测试 ./vendor/bin/kahlan

入门

本软件包提供了一个Ellipse\Container\ReflectionContainer类,可以用来装饰任何Psr-11容器。默认情况下,它为所有现有类启用自动装配,修改了原始容器的->has()->get()方法的行为。

现在->has()方法对于原始容器中包含的别名以及当给定的别名是现有类名时都返回true。

当给定的别名已定义时,->get()方法返回原始容器中的值。否则,当别名是一个现有的类名时,则使用自动装配来返回该类的新实例。这意味着使用PHP反射功能来提取类的构造函数参数,并调用反射容器的->get()方法来检索所有类型提示为类名的参数的值。对于其他参数,使用它们的默认值。一旦检索到了所有类构造函数参数的值,就使用这些值构建该类的新实例。当多次调用时,返回该类的同一实例,就像任何Psr-11容器会做的那样。

此自动装配功能可以被限制为实现指定接口列表的类。

<?php

namespace App;

interface SomeInterface
{
    //
}
<?php

namespace App;

class SomeClass implements SomeInterface
{
    //
}
<?php

namespace App;

class SomeOtherClass
{
    public function __construct(SomeInterface $class1, YetSomeOtherClass $class2)
    {
        //
    }
}
<?php

namespace App;

class YetSomeOtherClass
{
    //
}
<?php

use Some\Psr11Container;

use Ellipse\Container\ReflectionContainer;

use App\SomeInterface;
use App\SomeClass;
use App\SomeOtherClass;
use App\YetSomeOtherClass;

// Get an instance of some Psr-11 container.
$container = new Psr11Container;

// Add some definitions into the original container.
$container->set('some.value', function () {

    return 'something';

});

$container->set(SomeInterface::class, function () {

    return new SomeClass;

});

// Decorate the container.
$container = new ReflectionContainer($container);

// Now ->has() returns true for all those aliases:
$container->has('some.value');
$container->has(SomeInterface::class);
$container->has(SomeClass::class);
$container->has(SomeOtherClass::class);
$container->has(YetSomeOtherClass::class);

// ->get() still returns the values contained in the original container:
$container->get('some.value'); // returns 'something'
$container->get(SomeInterface::class); // returns the defined instance of SomeClass

// now ->get() can also build instances of non contained classes.
// Here an instance of SomeOtherClass is build by injecting the contained implementation of SomeInterface and a new instance of YetSomeOtherClass.
$container->get(SomeOtherClass::class);

// On multiple call the same instance is returned.
$someotherclass1 = $container->get(SomeOtherClass::class);
$someotherclass2 = $container->get(SomeOtherClass::class);

$someotherclass1 === $someotherclass2; // true

限制自动装配

ReflectionContainer类接受一个可选的接口名称数组作为第二个参数。当此数组不为空时,只有实现至少一个这些接口的类才会启用自动装配。

例如,当应用程序有很多控制器时,将它们全部注册到容器中可能是一项繁琐的任务。为了允许灵活性,同时又不失去对应用程序服务创建方式的控制,可以将ReflectionContainer配置为仅允许实现ControllerInterface的类进行自动装配。

<?php

namespace App\Controllers;

interface ControllerInterface
{
    //
}
<?php

namespace App\Controllers;

use App\SomeDependency;

class SomeController implements ControllerInterface
{
    private $dependency;

    public function __construct(SomeDependency $dependency)
    {
        $this->dependency = $dependency;
    }

    public function index()
    {
        //
    }
}
<?php

namespace App\Controllers;

use App\SomeOtherDependency;

class SomeOtherController implements ControllerInterface
{
    private $dependency;

    public function __construct(SomeOtherDependency $dependency)
    {
        $this->dependency = $dependency;
    }

    public function index()
    {
        //
    }
}
<?php

use Some\Psr11Container;

use Ellipse\Container\ReflectionContainer;

use App\Controllers\ControllerInterface;
use App\Controllers\SomeController;
use App\Controllers\SomeOtherController;
use App\SomeDependency;
use App\SomeOtherDependency;

// Get an instance of some Psr-11 container.
$container = new Psr11Container;

// Register 'App\SomeDependency' into the original container.
$container->set(SomeDependency::class, function () {

    return new SomeDependency;

});

// Allow auto wiring only for classes implementing ContainerInterface.
$container = new ReflectionContainer($container, [ControllerInterface::class]);

// This returns an new instance of SomeController with the defined instance of SomeDependency injected.
$controller = $container->get(SomeController::class);

// This fails because as SomeOtherDependency is not defined in the original container.
$controller = $container->get(SomeOtherController::class);