Pau*_*ulo 194 php oop inheritance constructor class
我需要在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
}
}
Run Code Online (Sandbox Code Playgroud)
我知道这是一件很奇怪的事情,我试图找到一种味道并不难闻的手段但是,我很好奇是否有可能.
编辑
我想我应该发布所选答案的理由.原因是; 它是最优雅的解决方案,希望在保留所有值的同时调用"祖父母"的构造函数.它当然不是最好的方法,也不是OOP友好的,但这不是问题的问题.
对于以后遇到此问题的任何人 - 请找到另一种解决方案.我能够找到一种更好的方法,不会对类结构造成严重破坏.你也应该这样.
Cor*_*lou 148
丑陋的解决方法是将一个布尔参数传递给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);
}
}
Run Code Online (Sandbox Code Playgroud)
too*_*php 71
你必须使用Grandpa::__construct(),没有其它的捷径.此外,这破坏了Papa类的封装- 在阅读或处理时Papa,应该可以安全地假设该__construct()方法将在构造期间被调用,但是Kiddo类不会这样做.
小智 52
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();
}
}
Run Code Online (Sandbox Code Playgroud)
Ale*_*kin 21
美丽的解决方案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();
Run Code Online (Sandbox Code Playgroud)
Pau*_*ulo 19
我最终找到了解决问题的替代解决方案.
我提出了另外两个答案,为一个更丑陋的问题提供了有效但丑陋的解决方案:)
Mit*_*aro 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";
Run Code Online (Sandbox Code Playgroud)
我同意"太多的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;
Run Code Online (Sandbox Code Playgroud)
我得到了预期的结果:
老兄
爷爷
这是一个不是bug的功能,请查看以供参考:
https://bugs.php.net/bug.php?id=42016
这只是它的工作方式.如果它看到它来自正确的上下文,则此调用版本不会强制执行静态调用.
相反,它只会保留$ this并对它感到满意.
parent :: method()以相同的方式工作,您不必将方法定义为static,但可以在同一个上下文中调用它.试试这个更有趣:
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;
Run Code Online (Sandbox Code Playgroud)
它也按预期工作:
老兄
爷爷
你好
但是如果你尝试初始化一个新的Papa,你会得到一个E_STRICT错误:
$papa = new Papa;
Run Code Online (Sandbox Code Playgroud)
严格的标准:非静态方法Kiddo :: hello()不应该静态调用,假设$ this来自不兼容的上下文
您可以使用instanceof来确定是否可以在父方法中调用Children :: method():
if ($this instanceof Kiddo) Kiddo::hello();
Run Code Online (Sandbox Code Playgroud)
对此有一个更简单的解决方案,但它要求您确切地知道当前类已经经历了多少继承.幸运的是,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!'
Run Code Online (Sandbox Code Playgroud)
同样,由于debug_backtrace()的限制,这对于您不知道发生了多少继承的情况不是一个可行的解决方案,但在受控环境中,它可以按预期工作.
您可以从您想要的位置调用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();
Run Code Online (Sandbox Code Playgroud)
关于 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
Run Code Online (Sandbox Code Playgroud)
所以在扩展类(Child)中你可以使用
parent::paFkt();
Run Code Online (Sandbox Code Playgroud)
或者
Pa::paFkt();
Run Code Online (Sandbox Code Playgroud)
访问父母(或祖父)(非私人)的功能。
课外定义
$test::paFkt();
Run Code Online (Sandbox Code Playgroud)
会引发严格错误(非静态函数)。