我需要在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();

其他回答

从PHP 7你可以使用

家长:家长:__construct ();

另一个不使用标志的选项可能适用于您的情况:

<?php
// main class that everything inherits
class Grandpa 
{
    public function __construct(){
        $this->GrandpaSetup();
    }

    public function GrandpaSetup(){
        $this->prop1 = 'foo';
        $this->prop2 = 'bar';
    }
}

class Papa extends Grandpa
{
    public function __construct()
    {
        // call Grandpa's constructor
        parent::__construct();
        $this->prop1 = 'foobar';
    }

}
class Kiddo extends Papa
{
    public function __construct()
    {
        $this->GrandpaSetup();
    }
}

$kid = new Kiddo();
echo "{$kid->prop1}\n{$kid->prop2}\n";

你可以从你想要的地方调用Grandpa::__construct, $this关键字将指向你当前的类实例。但是使用此方法时要注意,您不能从其他上下文中访问当前实例的受保护属性和方法,只能访问公共元素。所有工作和官方支持。

例子

// main class that everything inherits
class Grandpa 
{
    public function __construct()
    {
        echo $this->one; // will print 1
        echo $this->two; // error cannot access protected property
    }

}

class Papa extends Grandpa
{
    public function __construct()
    {
        // call Grandpa's constructor
        parent::__construct();
    }
}

class Kiddo extends Papa
{
    public $one = 1;
    protected $two = 2;
    public function __construct()
    {
        Grandpa::__construct();
    }
}

new Kiddo();
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 not a bug, it works that way in php
        Grandpa::__construct();
    }
}

我同意“太多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();