问题
Yes, I know dependencies should be passed to the constructor. I'm not asking about coding styles or do's and dont's.
Many of the classes in my application are tied to an instance of a database driver class. For this I've created an abstract Factory class using PHP's late static binding. The only member of this class is a property to hold the driver's reference. It looks like this:
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 ];
}
}
As you can see, when I create an instance of the derived class, I pass an instance of the driver to its constructor. THEN set the property. I want to reverse this, if possible, by setting the property first then call the constructor. This way a derived class doesn't need to implement a constructor or worry about calling parent methods if it does.
I've looked into the Reflection
API to do this, but I can't seem to find anything that would work. Most Dependency Injection
links I found actually use the constructor. This needs to work on PHP 5.3.
For those who are adament that this is not possible, It can easily be done in PHP 5.4 using ReflectionClass::newInstanceWithoutConstructor()
.
回答1:
class Foo {
public function __construct() {
echo 'foo';
}
}
$r = new ReflectionClass('Foo');
$o = $r->newInstanceWithoutConstructor();
$o->bar = 'baz';
$o->__construct();
This is possible since PHP 5.4.
But really: no. Just no. Don't. An object's constructor should always be called when the object is instantiated. No sooner (obviously), no later. Constructors and appropriate encapsulation of the rest of the object guarantee that the object is always in a consistent state. Once you start taking it apart using ReflectionClass
no guarantees can be made anymore about the state of the object, and sanity and type safety go out the window.
Since you're on 5.3 you're lucky that there's no way to do this there. If you find yourself backed into a corner like this, you're simply doing it wrong. Perfectly complex programs have been written without needing to trick PHP's object model into delaying constructor invocation.
回答2:
"I know dependencies should be passed to the constructor", not true, in cases where dependencies are inherited by an overridden constructor, using it is a bad idea.
In these cases the class might not even use the constructor, meaning the only state the class holds are its dependencies and the methods are treated as static and thereafter stateless during the lifetime of the object.
This is very common in Symfony2 where some services loaded via DI do not include parameters passed to the constructor, or if they are, then extensions must be compatible.
回答3:
You cannot set the value of an object which does not exist yet, you need to instantiate your object, and then initialize it by passing the necessary parameters to the constructor and inside the constructor you have to use the parameters to initialize your object.
来源:https://stackoverflow.com/questions/23428656/is-there-any-way-to-set-a-property-before-calling-a-constructor