wart/wart

扩展Pimple依赖注入容器,并提供自动类解析、实例化和(构造函数)注入

0.2.0 2014-02-22 12:29 UTC

This package is not auto-updated.

Last update: 2024-09-10 15:47:43 UTC


README

扩展Pimple依赖注入容器,并提供自动类解析、实例化和(构造函数)注入

概要

<?php

namespace Foo\Bar;

class Baz
{
    public function hello()
    {
        echo "Hello from baz\n";
    }
}

class Bla
{
    protected $baz;
    public function __construct(Baz $baz)
    {
        $this->baz = $baz;
    }
    public function hello()
    {
        $this->baz->hello();
        echo "Hello from bla\n";
    }
}

$container = new Wart;
$container['\Foo\Bar\Baz']->hello(); # prints "Hello from baz\n"
$container['\Foo\Bar\Bla']->hello(); # prints "Hello from baz\nHello from bla\n"

安装

composer.phar require wart/wart "*"

自动解析类实例

默认启用自动解析。它允许通过仅将类名作为容器键来实例化类

<?php

$container['\Foo\Bar\Baz']->hello();

可以通过在获取之前手动设置容器键或通过构造函数参数来禁用自动解析

<?php

// auto resolving only works on non existing keys!
$container = new Wart;
$container['\Foo\Bar\Baz'] = 'bla';
echo $container['\Foo\Bar\Baz']; # still "bla"

// disable on construct
$container = new Wart(array(), array('autoResolve' => false));

// disable later on
$container->setAutoResolve(false);

// this will not work anymore (unless it has been set manually)
echo $container['\Foo\Bar\Baz'];

别名

别名允许将服务接口映射到实际实现

$container->setAliases(['\Foo\Bar\BazInterface' => '\Foo\Bar\Baz']);
$container['\Foo\Bar\BazInterface']; # returns Baz

可以使用setAliases设置别名,也可以将其传递给Wart构造函数

$container = new \Wart([], [
    'aliases' => [
        '\Foo\Bar\BazInterface' => '\Foo\Bar\Baz'
    ]
]);

附加命名空间

可以将附加命名空间传递给Wart构造函数

<?php

$container = new Wart(array(), array('namespaces' => array('\Foo', '\Foo\Bar')));
$container['Baz']->hello(); # checks for \Baz and \Foo\Baz and \Foo\Bar\Baz - in that order!

或稍后设置(替换!)

<?php

$container = new Wart;
$container->setNamespaces(array('\Foo', '\Foo\Bar'));
$container['Baz']->hello(); # checks for \Baz and \Foo\Baz and \Foo\Bar\Baz - in that order!

请注意顺序!

手动创建和自动注册类实例

禁用自动解析时,可以预先生成类实例

<?php

$container = new Wart(array(), array('autoResolve' => false));
$container['\Foo\Bar\Baz']->hello(); # would throw and exception -> key does not exist
$instance = $container->create('\Foo\Bar\Baz');
$instance->hello();
$container['\Foo\Bar\Baz']->hello(); # now the key exists

create方法立即创建一个实例。如果您只想预先注册一个实例以供以后使用,请使用autoRegister

<?php

$container = new Wart(array(), array('autoResolve' => false));
$container['\Foo\Bar\Baz']->hello();  # would throw and exception -> key does not exist
$container->autoRegister('\Foo\Bar\Baz'); # does not return anything
$container['\Foo\Bar\Baz']->hello();  # now the key exists

附加构造函数参数

要使用附加构造函数参数,您可以使用createArgs参数或使用setCreateArgs方法设置它们

<?php

namespace Foo\Bar;

class Baz
{
    protected $param;
    public function __construct($param)
    {
        $this->param = $param;
    }
    public function hello()
    {
        echo "Hello {$this->param}\n";
    }
}

class Bla
{
    protected $param;
    public function __construct(Baz $baz, $param)
    {
        $this->param = $param;
    }
    public function hello()
    {
        echo "Hello {$this->param}\n";
    }
}

class Yadda
{
    protected $scalar;
    public function __construct(Baz $baz, $scalar, Bla $bla)
    {
        $this->scalar = $scalar;
    }
    public function hello()
    {
        echo "Hello {$this->scalar}\n";
        $this->bla->Hello();
    }
}

$container = new Wart(array(), array(
    'createArgs' => array(
        '\Foo\Bar\Baz'   => ['world'],
        '\Foo\Bar\Bla'   => ['you'],
        '\Foo\Bar\Yadda' => function (array $createArgs, $className, \Wart $cnt) {
            // $createArgs contains the constructor parameters Wart has already figured out (i.e. all with class type hints)
            // Must return an array with all constructor args
            if ($buildArgs && $buildArgs[0] instanceof \Foo\Bar\Baz) use ($container) { # Wart found
                return [$buildArgs[0], "!", $cnt['\Foo\Bar\Baz']];
            }
            throw new \Exception("Oh no!");
        }
    )
));
$container->autoRegister('\Foo\Bar\Baz');   # does not return anything and does NOT create an object instance just yet
$container['\Foo\Bar\Baz']->hello();    # prints "Hello world\n"
$container['\Foo\Bar\Bla']->hello();    # prints "Hello you\n"
$container['\Foo\Bar\Yadda']->hello();  # prints "Hello !\nHello you\n"

您还可以使用setCreateArgs在以后设置(替换!)构造函数参数

<?php

$container = new Wart;
$container->setCreateArgs(array(
    '\Foo\Bar\Baz'   => ['world']
));

限制

构造函数参数签名顺序

请注意,Wart仅支持自动确定类型提示为类的构造函数参数。

以下Wart尝试解析和注入

<?php

class Foo
{
    public function __construct(Bar $bar) {}
}

以下Wart无法注入,除非您使用setCreateArgs方法或上面的createArgs参数。

<?php

class Foo
{
    public function __construct($bar) {}
}

如果构造函数参数签名顺序是“相反的”,Wart也无法解析它。以下将不会(自动)工作

<?php

class Bla
{
    public function __construct($param, Baz $baz) # << Baz $baz is on second position, Wart gives up on first as it's not typehinted to a class
    {
    }
}

循环依赖

Wart具有简单的循环依赖识别功能。然而,其能力有限(特别是在构造函数参数顺序的上下文中,见上面)

以下会被Wart识别(并抛出RuntimeException

<?php

class Foo {
    public function __construct(Bar $bar) {}
}

class Bar {
    public function __construct(Baz $baz) {}
}

class Baz {
    public function __construct(Foo $foo) {}
}

其他情况:无法保证(欢迎补丁,除非它们大大增加了复杂性)。