Php,可以使用DI的特性吗?

时间:2017-06-17 09:00:56

标签: php dependency-injection traits

考虑这个例子:

class MyClass
{
    public function doSomething()
    {
        $this->injected->getIt();
    }
}

到目前为止这么简单(除injected之外没有注入)。所以,完整版:

class MyClass
{
    /**
     * @var Injected
     */
    private $injected;

    public function __constructor(Injected $injected)
    {
        $this->injected = $injected;
    }

    public function doSomething()
    {
        $this->injected->getIt();
    }
}

但我发现它很无聊。为什么要用大量的DI代码污染我的班级?让我们把它分成两个实体:

trait MyClassTrait
{
    /**
     * @var Injected
     */
    private $injected;

    public function __constructor(Injected $injected)
    {
        $this->injected = $injected;
    }
}

class MyClass
{
    use MyClassTrait;

    public function doSomething()
    {
        $this->injected->getIt();
    }
}
虽然我从来没有见过像这样使用过它的人,但它还要好得多。这是一个好方法吗?

2 个答案:

答案 0 :(得分:1)

例如:

<?php

class Factory
{
    private $services = [];

    public function __construct() {
        $this->services[self::class] = $this;
    }

    public function getByType($type){
        if(isset($services[$type])){
            return $services[$type];
        }

        if(class_exists($type)){
            $reflection = new ReflectionClass($type);
            $constructor = $reflection->getConstructor();

            $parameters = [];
            if($constructor)
            foreach($constructor->getParameters() as $parameter){
                if($parameter->getClass()) {
                    $parameters[] = $this->getByType($parameter->getClass()->name);
                } else if($parameter->isDefaultValueAvailable()){
                    $parameters[] = $parameter->getDefaultValue();
                }
            }

            return $services[$type] = $reflection->newInstanceArgs($parameters);
        } // else throw Exception...
    }
}

abstract class DI
{        
    public function __construct(Factory $factory) {           
        $reflection = new ReflectionClass(get_class($this));
        foreach($reflection->getProperties() as $property){
            preg_match('/@var ([^ ]+) @inject/', $property->getDocComment(), $annotation);
            if($annotation){
                $className = $annotation[1];
                if(class_exists($className)){
                    $property->setAccessible(true);
                    $property->setValue($this, $factory->getByType($className));
                } // else throw Exception...
            }
        }
    }
}

class Injected
{
    public function getIt($string){
        echo $string.'<br />';
    }
}


class DIByConstructor
{
    /** @var Injected */
    private $byConstructor;

    public function __construct(Injected $injected) {
        $this->byConstructor = $injected;
    }

    public function doSomething()
    {
        echo 'Class: '.self::class.'<br />';
        $this->byConstructor->getIt('By Constructor');
        echo '<br />';
    }      
}

class DIByAnnotation extends DI
{
    /** @var Injected @inject */
    private $byAnnotation;

    public function doSomething()
    {
        echo 'Class: '.self::class.'<br />';
        $this->byAnnotation->getIt('By Annotation');
        echo '<br />';
    }      
}

class DIBothMethods extends DI
{
    /** @var Injected */
    private $byConstructor;

    /** @var Injected @inject */
    private $byAnnotation;

    public function __construct(Factory $factory, Injected $injected) {
        parent::__construct($factory);
        $this->byConstructor = $injected;
    }

    public function doSomething()
    {
        echo 'Class: '.self::class.'<br />';
        $this->byConstructor->getIt('By Constructor');
        $this->byAnnotation->getIt('By Annotation');
        echo '<br />';
    }      
}

$factory = new Factory();

$DIByConstructor = $factory->getByType('DIByConstructor');
$DIByConstructor->doSomething();

$DIByAnnotation = $factory->getByType('DIByAnnotation');
$DIByAnnotation->doSomething();

$DIBothMethods = $factory->getByType('DIBothMethods');
$DIBothMethods->doSomething();

答案 1 :(得分:1)

请注意,随着@Kazz的临近(通过注释输入DI),您不能引用接口,而是要引用类。因此,这对于以几乎零的冗长速度进行快速实例化非常有好处,但最后,您将失去所有的DI潜力。