考虑这个例子:
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();
}
}
虽然我从来没有见过像这样使用过它的人,但它还要好得多。这是一个好方法吗?
答案 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潜力。