我需要在PHP中有一个类构造函数调用父类的父类的(祖父母?)构造函数,而不调用父类构造函数。
// main class that everything inherits
class Grandpa
{
public function __construct()
{
}
}
class Papa extends Grandpa
{
public function __construct()
{
// call Grandpa's constructor
parent::__construct();
}
}
class Kiddo extends Papa
{
public function __construct()
{
// THIS IS WHERE I NEED TO CALL GRANDPA'S
// CONSTRUCTOR AND NOT PAPA'S
}
}
我知道这是一件很奇怪的事情,我正试图找到一种不难闻的方法,但尽管如此,我很好奇这是否可能。
我同意“太多php”,试试这个:
class Grandpa
{
public function __construct()
{
echo 'Grandpa<br/>';
}
}
class Papa extends Grandpa
{
public function __construct()
{
echo 'Papa<br/>';
parent::__construct();
}
}
class Kiddo extends Papa
{
public function __construct()
{
// THIS IS WHERE I NEED TO CALL GRANDPA'S
// CONSTRUCTOR AND NOT PAPA'S
echo 'Kiddo<br/>';
Grandpa::__construct();
}
}
$instance = new Kiddo;
我得到了预期的结果:
老姐
爷爷
这是一个功能而不是一个bug,检查一下以供参考:
https://bugs.php.net/bug.php?id=42016
这就是它的运作方式。如果它看到它来自正确的上下文,这个调用版本不会强制执行静态调用。
相反,它会简单地保留$this,并对它感到满意。
Parent::method()以同样的方式工作,你不必将方法定义为静态的,但它可以在相同的上下文中被调用。试试这个更有趣的:
class Grandpa
{
public function __construct()
{
echo 'Grandpa<br/>';
Kiddo::hello();
}
}
class Papa extends Grandpa
{
public function __construct()
{
echo 'Papa<br/>';
parent::__construct();
}
}
class Kiddo extends Papa
{
public function __construct()
{
// THIS IS WHERE I NEED TO CALL GRANDPA'S
// CONSTRUCTOR AND NOT PAPA'S
echo 'Kiddo<br/>';
Grandpa::__construct();
}
public function hello()
{
echo 'Hello<br/>';
}
}
$instance = new Kiddo;
它也像预期的那样工作:
老姐
爷爷
你好
但是如果你尝试初始化一个新的Papa,你会得到一个E_STRICT错误:
$papa = new Papa;
严格的标准:非静态方法Kiddo::hello()不应该被静态调用,假设$this来自不兼容的上下文
你可以使用instanceof来确定你是否可以在父方法中调用Children::method():
if ($this instanceof Kiddo) Kiddo::hello();
对此有一个更简单的解决方案,但它要求您确切地知道当前类已经经历了多少继承。幸运的是,get_parent_class()的参数允许类数组成员作为一个字符串作为类名,也可以作为实例本身。
请记住,这本质上也依赖于静态调用类的__construct()方法,尽管在继承对象的实例化范围内,这种特殊情况下的差异可以忽略不计(啊,PHP)。
考虑以下几点:
class Foo {
var $f = 'bad (Foo)';
function __construct() {
$this->f = 'Good!';
}
}
class Bar extends Foo {
var $f = 'bad (Bar)';
}
class FooBar extends Bar {
var $f = 'bad (FooBar)';
function __construct() {
# FooBar constructor logic here
call_user_func(array(get_parent_class(get_parent_class($this)), '__construct'));
}
}
$foo = new FooBar();
echo $foo->f; #=> 'Good!'
同样,由于debug_backtrace()的限制,对于不知道发生了多少继承的情况,这不是一个可行的解决方案,但在受控的情况下,它可以按预期工作。