我如何获得一个PHP类的构造函数来调用其父类的构造函数

我需要在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 } } 

我知道这是一个奇怪的事情,我试图find一种手段,但没有闻起来不好,但我很好奇,如果有可能的话。

编辑

我想我应该张贴所选答案的理由。 原因是; 这是最优雅的解决scheme,想要在保留所有的价值的同时调用“祖父母”的构造函数的问题。 这当然不是最好的方法,也不是OOP友好的,但这不是问题的要求。

对于晚些时候遇到这个问题的人 – 请find另一个解决scheme 。 我能find一个更好的方法,不会对class级结构造成严重破坏。 所以你应该。

丑陋的解决方法是将一个布尔parameter passing给Papa,表明您不希望parsing包含在其构造函数中的代码。 即:

 // main class that everything inherits class Grandpa { public function __construct() { } } class Papa extends Grandpa { public function __construct($bypass = false) { // only perform actions inside if not bypassing if (!$bypass) { } // call Grandpa's constructor parent::__construct(); } } class Kiddo extends Papa { public function __construct() { $bypassPapa = true; parent::__construct($bypassPapa); } } 

你必须使用Grandpa::__construct() ,没有其他的快捷方式。 另外,这也破坏了Papa类的封装 – 在Papa阅读或者工作时,假设__construct()方法在施工期间被调用应该是安全的,但是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 // 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"; 

我最终提出了一个解决问题的替代解决scheme。

  • 我创造了一个延续爷爷的中级课程。
  • 然后,爸爸和基德都延续了这堂课。
  • Kiddo需要Papa的一些中间function,但不喜欢它的构造函数,所以类有附加function,并扩展它。

我已经upvoted另外两个答案,提供了一个丑陋的问题有效但丑陋的解决scheme:)

美丽的解决scheme

 <?php class Grandpa { public function __construct() { echo "Grandpa's constructor called\n"; } } class Papa extends Grandpa { public function __construct() { echo "Papa's constructor called\n"; // call Grandpa's constructor parent::__construct(); } } class Kiddo extends Papa { public function __construct() { echo "Kiddo's constructor called\n"; $reflectionMethod = new ReflectionMethod(get_parent_class(get_parent_class($this)), '__construct'); $reflectionMethod->invoke($this); } } $kiddo = new Kiddo(); $papa = new Papa(); 

对此有一个更简单的解决scheme,但是它要求您确切知道您的当前类已经经历了多lessinheritance。 幸运的是,get_parent_class()的参数允许你的类数组成员作为一个string的类名以及一个实例本身。

请记住,这也固有地依赖于静态地调用类__construct()方法,尽pipe在inheritance对象的实例范围内,这种特殊情况下的差异可以忽略不计(PHP,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()的局限性,在不知道已经发生了多lessinheritance的情况下,这不是一个可行的解决scheme,但是在受控环境下,它可以按预期工作。

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

我得到了预期的结果:

老兄

爷爷

这是一个function不是bug,请检查以供参考:

https://bugs.php.net/bug.php?id=42016

这只是它的工作方式。 如果它看到它来自正确的上下文,这个调用版本不强制执行静态调用。

相反,它会保持$这个并且对它感到满意。

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; 

它也按预期工作:

老兄

爷爷

你好

但是如果你尝试初始化一个新的爸爸,你会得到一个E_STRICT错误:

 $papa = new Papa; 

严格标准:非静态方法Kiddo :: hello()不应该被静态调用,假设$ this来自不兼容的上下文

您可以使用instanceof来确定您是否可以在父方法中调用Children :: method():

 if ($this instanceof Kiddo) Kiddo::hello(); 

您可以从您想要的位置调用Grandpa :: __构造,$ 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(); 

好的,又一个丑陋的解决scheme:

在Papa中创build一个函数,如:

 protected function call2Granpa() { return parent::__construct(); } 

然后在Kiddo中使用:

parent::call2Granpa(); //而不是在Papa中调用构造函数。

我认为它可以工作…我还没有testing,所以我不知道如果对象创build正确。

我用这种方法,但与非构造函数。

 <?php class grand_pa { public function __construct() { echo "Hey I am Grand Pa <br>"; } } class pa_pa extends grand_pa { // no need for construct here unless you want to do something specifically within this class as init stuff // the construct for this class will be inherited from the parent. } class kiddo extends pa_pa { public function __construct() { parent::__construct(); echo "Hey I am a child <br>"; } } new kiddo(); ?> 

当然,这期望你不需要在pa_pa的构造中做任何事情。 运行这将输出:

嘿,我是大霸王嘿,我是一个孩子

关于php的有趣的细节:扩展类可以使用静态事物中父类的非静态函数。 外面你会得到一个严格的错误。

 error_reporting(E_ALL); class GrandPa { public function __construct() { print("construct grandpa<br/>"); $this->grandPaFkt(); } protected function grandPaFkt(){ print(">>do Grandpa<br/>"); } } class Pa extends GrandPa { public function __construct() { parent::__construct(); print("construct Pa <br/>"); } public function paFkt(){ print(">>do Pa <br>"); } } class Child extends Pa { public function __construct() { GrandPa::__construct(); Pa::paFkt();//allright //parent::__construct();//whatever you want print("construct Child<br/>"); } } $test=new Child(); $test::paFkt();//strict error 

所以在扩展类(Child)中可以使用

 parent::paFkt(); 

要么

 Pa::paFkt(); 

访问父母(或grandPa's)(非私人)function。

外部类def

 $test::paFkt(); 

将严重错误(非静态函数)。

 // main class that everything inherits class Grandpa { public function __construct() { $this->___construct(); } protected function ___construct() { // grandpa's logic } } class Papa extends Grandpa { public function __construct() { // call Grandpa's constructor parent::__construct(); } } class Kiddo extends Papa { public function __construct() { parent::___construct(); } } 

注意“___construct”不是一些神奇的名字,你可以称之为“doGrandpaStuff”。

  class Grandpa { public function __construct() { echo"Hello Kiddo"; } } class Papa extends Grandpa { public function __construct() { } public function CallGranddad() { parent::__construct(); } } class Kiddo extends Papa { public function __construct() { } public function needSomethingFromGrandDad { parent::CallGranddad(); } } 

从PHP 7ü可以使用

parent::parent::__construct();