我需要在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
}
}
我知道这是一件很奇怪的事情,我试图找到一种味道不好的方法,但是,我很好奇是否有可能。
修改
我想我应该发布所选答案的理由。原因是;它是最优雅的解决方案,希望在保留所有值的同时调用“祖父母”的构造函数。它当然不是最好的方法,也不是OOP友好的,但这不是问题所在。
对于稍后遇到此问题的任何人 - 请找到其他解决方案。我能够找到一种更好的方法,不会对类结构造成严重破坏。你也应该这样做。
答案 0 :(得分:135)
丑陋的解决方法是将一个布尔参数传递给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);
}
}
答案 1 :(得分:69)
您必须使用Grandpa::__construct()
,没有其他快捷方式。此外,这会破坏Papa
类的封装 - 在阅读或处理Papa
时,应该可以安全地假设在构造期间将调用__construct()
方法,但Kiddo
方法1}}类不会这样做。
答案 2 :(得分:49)
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();
}
}
答案 3 :(得分:19)
我最终找到了解决问题的替代解决方案。
我提出了另外两个答案,为一个更丑陋的问题提供了有效但丑陋的解决方案:)
答案 4 :(得分:16)
另一个不使用标志的选项可能适用于您的情况:
<?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";
答案 5 :(得分:16)
使用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();
答案 6 :(得分:9)
我同意“太多的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;
我得到了预期的结果:
老兄
爷爷
这是一个不是错误的功能,请查看以供参考:
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();
答案 7 :(得分:8)
对此有一个更简单的解决方案,但它要求您确切知道当前类经历了多少继承。幸运的是,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()的限制,对于您不知道有多少继承发生的情况,这不是一个可行的解决方案,但在受控环境中,它可以按预期工作。
答案 8 :(得分:7)
您可以从您想要的地方调用Grandpa :: __构造,$ this关键字将引用您当前的类实例。 但是要小心这个方法,你不能从这个其他上下文访问受保护的属性和当前实例的方法,只能访问公共元素。 =&gt;所有工作和officialy supported。
实施例
// 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();
答案 9 :(得分:4)
关于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();
将抛出严格的错误(非静态函数)。
答案 10 :(得分:2)
好的,又一个丑陋的解决方案:
在Papa中创建一个函数,如:
protected function call2Granpa() {
return parent::__construct();
}
然后在Kiddo中使用:
parent::call2Granpa();
//而不是在Papa中调用构造函数。
我认为它可以工作......我没有测试过,所以我不确定是否可以 对象是正确创建的。
我使用了这种方法但使用了非构造函数。
答案 11 :(得分:2)
<?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的构造中做任何事情。运行它将输出:
嘿,我是大霸王 嘿,我还是个孩子答案 12 :(得分:1)
// 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”。
答案 13 :(得分:-2)
从php 7你可以使用
parent::parent::__construct();