如何让 PHP 类构造函数调用其父级的父级构造函数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1557608/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I get a PHP class constructor to call its parent's parent's constructor?
提问by Paulo
I need to have a class constructor in PHP call its parent's parent's(grandparent?) constructor without calling the parent constructor.
我需要在 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
}
}
I know this is a bizarre thing to do and I'm attempting to find a means that doesn't smell bad but nonetheless, I'm curious if it's possible.
我知道这是一件很奇怪的事情,我正在尝试找到一种不难闻的方法,但尽管如此,我很好奇是否有可能。
采纳答案by Corey Ballou
The ugly workaround would be to pass a boolean param to Papa indicating that you do not wish to parse the code contained in it's constructor. i.e:
丑陋的解决方法是将布尔参数传递给 Papa,表明您不希望解析其构造函数中包含的代码。IE:
// 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);
}
}
回答by too much php
You must use Grandpa::__construct(), there's no other shortcut for it. Also, this ruins the encapsulation of the Papaclass - when reading or working on Papa, it should be safe to assume that the __construct()method will be called during construction, but the Kiddoclass does not do this.
您必须使用Grandpa::__construct(),没有其他快捷方式。此外,这会破坏Papa类的封装- 在读取或处理 时Papa,假设__construct()将在构造期间调用该方法应该是安全的,但Kiddo该类不会这样做。
回答by Alain57
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();
}
}
回答by Aleksei Akireikin
Beautiful solution using Reflection.
使用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();
回答by Paulo
I ended up coming up with an alternative solution that solved the problem.
我最终想出了一个解决问题的替代解决方案。
- I created an intermediate class that extended Grandpa.
- Then both Papa and Kiddo extended that class.
- Kiddo required some intermediate functionality of Papa but didn't like it's constructor so the class has that additional functionality and both extend it.
- 我创建了一个扩展爷爷的中级班。
- 然后爸爸和基多都扩展了那门课。
- Kiddo 需要 Papa 的一些中间功能,但不喜欢它的构造函数,因此该类具有附加功能并且都扩展了它。
I've upvoted the other two answers that provided valid yet ugly solutions for an uglier question:)
我对其他两个答案表示赞同,这些答案为更丑陋的问题提供了有效但丑陋的解决方案:)
回答by MitMaro
Another option that doesn't use a flag and might work in your situation:
另一个不使用标志并且可能适用于您的情况的选项:
<?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";
回答by Fishdrowned
I agree with "too much php", try this:
我同意“太多的 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;
I got the result as expected:
我得到了预期的结果:
Kiddo
Grandpa
基多
爷爷
This is a feature not a bug, check this for your reference:
这是一个功能而不是一个错误,检查这个以供您参考:
https://bugs.php.net/bug.php?id=42016
https://bugs.php.net/bug.php?id=42016
It is just the way it works. If it sees it is coming from the right context this call version does not enforce a static call.
Instead it will simply keep $this and be happy with it.
这就是它的工作方式。如果它看到它来自正确的上下文,则此调用版本不会强制执行静态调用。
相反,它会简单地保留 $this 并对此感到满意。
parent::method() works in the same way, you don't have to define the method as static but it can be called in the same context. Try this out for more interesting:
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;
It also works as expected:
它也按预期工作:
Kiddo
Grandpa
Hello
基多
爷爷
你好
But if you try to initialize a new Papa, you will get an E_STRICT error:
但是如果你尝试初始化一个新的爸爸,你会得到一个 E_STRICT 错误:
$papa = new Papa;
Strict standards: Non-static method Kiddo::hello() should not be called statically, assuming $this from incompatible context
严格标准:非静态方法 Kiddo::hello() 不应静态调用,假设 $this 来自不兼容的上下文
You can use instanceof to determine if you can call a Children::method() in a parent method:
您可以使用 instanceof 来确定是否可以在父方法中调用 Children::method() :
if ($this instanceof Kiddo) Kiddo::hello();
回答by mway
There's an easier solution for this, but it requires that you know exactly how much inheritance your current class has gone through. Fortunately, get_parent_class()'s arguments allow your class array member to be the class name as a string as well as an instance itself.
对此有一个更简单的解决方案,但它要求您确切知道当前类经历了多少继承。幸运的是,get_parent_class() 的参数允许您的类数组成员将类名作为字符串以及实例本身。
Bear in mind that this also inherently relies on calling a class' __construct() method statically, though within the instanced scope of an inheriting object the difference in this particular case is negligible (ah, PHP).
请记住,这也本质上依赖于静态调用类的 __construct() 方法,尽管在继承对象的实例化范围内,这种特殊情况下的差异可以忽略不计(啊,PHP)。
Consider the following:
考虑以下:
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!'
Again, this isn't a viable solution for a situation where you have no idea how much inheritance has taken place, due to the limitations of debug_backtrace(), but in controlled circumstances, it works as intended.
同样,由于 debug_backtrace() 的限制,对于您不知道发生了多少继承的情况,这不是一个可行的解决方案,但在受控情况下,它可以按预期工作。
回答by Xorax
You can call Grandpa::__construct from where you want and the $this keyword will refer to your current class instance. But be carefull with this method you cannot access to protected properties and methods of current instance from this other context, only to public elements.=> All work and officialy supported.
您可以从您想要的位置调用 Grandpa::__construct 并且 $this 关键字将引用您当前的类实例。但是要小心使用此方法,您无法从其他上下文访问当前实例的受保护属性和方法,只能访问公共元素。=> 所有工作和官方支持。
Example
例子
// 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();
回答by Hauke
Funny detail about php: extended classes can use non-static functions of a parent class in a static matter. Outside you will get a strict error.
关于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
So inside a extended class (Child) you can use
所以在扩展类(Child)中,您可以使用
parent::paFkt();
or
或者
Pa::paFkt();
to access a parent (or grandPa's) (not private) function.
访问父(或grandPa)(非私有)函数。
Outside class def
课外定义
$test::paFkt();
will trow strict error (non static function).
将 trow 严格错误(非静态函数)。

