我如何獲得一個PHP類構造函數來調用其父類的父類的構造函數


Answers

你必須使用Grandpa::__construct() ,沒有其他的快捷方式。 另外,這破壞了Papa類的封裝 - 在閱讀或使用Papa ,假定在構建過程中將調用__construct()方法應該是安全的,但Kiddo類不會這樣做。

Question

我需要在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友好的,但這不是問題的要求。

對於晚些時候遇到此問題的任何人 - 請找到另一個解決方案 。 我能夠找到一種更好的方法,不會對班級結構造成嚴重破壞。 你應該如此。




<?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”,試試這個:

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,請檢查以供參考:

link

這只是它的工作方式。 如果它看到它來自正確的上下文,則此調用版本不會執行靜態調用。

相反,它會保持$這個並且對它感到滿意。

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



關於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)(非私人)功能。

外部類def

$test::paFkt();

將嚴重錯誤(非靜態函數)。




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



我最終提出了解決問題的替代解決方案。

  • 我創建了一個延續爺爺的中級課程。
  • 然後爸爸和基德都延長了那堂課。
  • Kiddo需要Papa的一些中間功能,但不喜歡它的構造函數,因此該類具有額外的功能,並且都將其擴展。

我已經提出了另外兩個答案,為一個醜陋的問題提供了有效但又醜陋的解決方案:)




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