If I have a parent class that is extended by lots and lots of other classes, and I want to make sure the parent class's constructor is ALWAYS run, is it a bad开发者_StackOverflow idea to declare the constructor final
?
I was thinking of doing something like this:
class ParentClass {
public final function __construct() {
//parent class initialization...
$this->construct();
}
protected function init() {
echo 'constructing<br>';
}
}
class ChildClass extends ParentClass {
protected function init() {
//child class initialization
echo 'constructing child<br>';
}
}
that way the child class can have a sort-of constructor, and the parent class's constructor will always execute. Is this bad practice?
Declaring a final
__construct
ensures that no one who extends your class can implement a method with the same name. On the surface of it, this would seem like it would mean no one else can declare a constructor for sub-classes of this class, but this is not true, since the PHP 4 style of ClassName()
still works just fine as an alternate name for the constructor. So really, declaring a constructor as final gets you nothing in PHP.
As of PHP 5.3.3, I have tested this with 5.6 and 7.0, declaring the __construct
method of a class final
will prevent any child class overriding the constructor either using __construct
or the PHP 4 style of ClassName()
(note that the PHP 4 style is deprecated as of PHP 7). Preventing a child class declaring a constructor will ensure that the parent constructor is always called. This will, of course, not allow any child classes to implement their own constructor logic. There would definitely be practical use cases for this though I would not recommend it as good practice generally.
Some examples:
Without declaring __construct
final
class ParentClassWithoutFinal {
private $value = "default";
public function __construct() {
$this->value = static::class;
}
function __toString() {
return $this->value;
}
}
class ChildClassA extends ParentClassWithoutFinal {
public function __construct() {
// Missing parent::__construct();
}
}
echo (new ChildClassA()); // ouput: default
With final __construct
class ParentClassWithFinal extends ParentClassWithoutFinal {
public final function __construct() {
parent::__construct();
}
}
class ChildClassB extends ParentClassWithFinal {
}
echo (new ChildClassB()); // output: ChildClassB
Trying to declare __construct
in a child class
class ChildClassC extends ParentClassWithFinal {
public function __construct() {
}
}
// Fatal error: Cannot override final method ParentClassWithFinal::__construct()
Trying to declare ClassName()
constructor in a child class
class ChildClassD extends ParentClassWithFinal {
public function ChildClassD() {
}
}
// Fatal error: Cannot override final ParentClassWithFinal::__construct() with ChildClassD::ChildClassD()
// Also in PHP 7: Deprecated: Methods with the same name as their class will not be constructors in a future version of PHP; ChildClassD has a deprecated constructor
After finalizing the constructor, you can't pass any variables to initializing function. It forces users of you class to use globals as settings for their child classes.
In Zend Framework using overridable init() is common practice, but I've never seen finalizing a constructor there.
精彩评论