我如何得到一个PHP类构造函数调用它的父's父's构造函数?

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

我知道这是一件很奇怪的事情,我正试图找到一种不难闻的方法,但尽管如此,我很好奇这是否可能。

301021 次浏览

你必须使用Grandpa::__construct(),它没有其他快捷方式。此外,这也破坏了Papa类的封装——当读取或处理Papa时,应该可以安全地假设__construct()方法将在构造过程中被调用,但Kiddo类不会这样做。

丑陋的解决方法是将一个布尔参数传递给Papa,表明您不希望解析它的构造函数中包含的代码。即:

// 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);
}
}

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

<?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";

我最终想出了一个解决问题的替代方案。

  • 我创建了一个中间类,扩展了爷爷。
  • 然后爸爸和孩子都延长了这个课程。
  • Kiddo需要Papa的一些中间功能,但不喜欢它的构造函数,所以类有额外的功能,并扩展了它。

我对另外两个答案大加赞赏,它们为一个更丑陋的问题提供了有效但丑陋的解决方案:)

好吧,还有一个丑陋的解决方案:

在Papa中创建一个函数:

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

然后在Kiddo中使用:

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

我认为它可以工作…我还没有测试过,所以我不确定是否 对象被正确创建。< / p >

我使用了这种方法,但是使用了非构造函数。

对此有一个更简单的解决方案,但它要求您确切地知道当前类已经经历了多少继承。幸运的是,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()的限制,对于不知道发生了多少继承的情况,这不是一个可行的解决方案,但在受控的情况下,它可以按预期工作。

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();
}
}

你可以从你想要的地方调用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();
// 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"。

我同意“太多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 < a href = " 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


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的构造中做任何事情。运行该命令将输出:

嘿,我是爷爷 嘿,我是一个孩子

漂亮的解决方案使用Reflection

<?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();
    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的有趣细节:扩展类可以在静态事务中使用父类的非静态函数。在外面你会得到一个严格的错误。

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();

访问父(或祖父)(非私有)函数。

类定义之外

$test::paFkt();

将trostrict错误(非静态函数)。

从PHP 7你可以使用

parent::parent::__construct();