是的,我知道应该将依赖项传递给构造函数。我不是在询问编码风格,也不是在做什么,也不要问。
我的应用程序中的许多类都绑定到数据库驱动程序类的实例。为此,我使用PHP的后期静态绑定创建了一个抽象的Factory类。此类中唯一的成员是保存驱动程序引用的属性。它看起来像这样:
abstract class Factory {
static private $__instances;
static private $__default_driver;
protected $_driver;
static public function getInstance ( \Database\Driver $driver = null ) {
if ( ! isset($driver) ) {
if ( ! isset(self::$__default_driver) ) {
require ( \Core\Options::$database_driver[ 'path' ] );
self::$__default_driver = new \Core\Options::$database_driver[ 'class' ]( \Core\Options::$database_options );
}
$driver = self::$__default_driver;
}
$schema = $driver->getDatabase();
$class = get_called_class();
if ( ! isset(self::$__instances[ $schema ][ $class ]) ) {
self::$__instances[ $schema ][ $class ] = new $class( $driver );
self::$__instances[ $schema ][ $class ]->_driver = $driver;
}
return self::$__instances[ $schema ][ $class ];
}
}
如您所见,当我创建派生类的实例时,我将驱动程序的实例传递给它的构造函数。然后设置属性。如果可能的话,我想通过首先设置属性然后调用构造函数来反转它。这样,派生类不需要实现构造函数,也不用担心调用父方法。
我已经查看Reflection
API来执行此操作,但我似乎无法找到任何可行的方法。我发现的大多数Dependency Injection
链接实际上都使用了构造函数。这需要在PHP 5.3上运行。
对于那些无法做到这一点的人,It can easily be done in PHP 5.4使用ReflectionClass::newInstanceWithoutConstructor()
。
答案 0 :(得分:2)
class Foo {
public function __construct() {
echo 'foo';
}
}
$r = new ReflectionClass('Foo');
$o = $r->newInstanceWithoutConstructor();
$o->bar = 'baz';
$o->__construct();
这可以从PHP 5.4开始。
但是真的:没有。就是不行。不要。在实例化对象时,应始终调用对象的构造函数。不久(显然),不久之后。构造函数和对象其余部分的适当封装可确保对象始终处于一致状态。一旦你开始使用ReflectionClass
拆开它,就不能再保证对象的状态了,理智和类型安全就会消失。
因为你在5.3,你很幸运,那里没有办法做到这一点。如果你发现自己被这样的角落所支持,你只是做错了。编写了非常复杂的程序,无需欺骗PHP的对象模型来延迟构造函数调用。
答案 1 :(得分:0)
“我知道依赖项应该传递给构造函数”,而不是真的,如果依赖项被重写的构造函数继承,使用它是一个坏主意。
在这些情况下,类甚至可能不使用构造函数,这意味着类所拥有的唯一状态是它的依赖项,并且这些方法在对象的生命周期中被视为静态,之后是无状态的。
这在Symfony2中非常常见,其中通过DI加载的某些服务不包含传递给构造函数的参数,或者如果它们是,则扩展必须兼容。
答案 2 :(得分:0)
你不能设置一个尚不存在的对象的值,你需要实例化你的对象,然后通过将必要的参数传递给构造函数来初始化它,你必须使用参数来初始化你的对象