web-dev-qa-db-ja.com

PHPクラスコンストラクターを取得して、親の親のコンストラクターを呼び出す方法

PHPのクラスコンストラクターを使用して、親のコンストラクターを呼び出さずに、その親のparent's(grandparent?)コンストラクターを呼び出す必要があります。

// 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フレンドリーでもありませんが、それは質問が尋ねていたものではありません。

後日この質問に出くわした人のために-別の解決策を見つけてください。クラス構造に大混乱をもたらさない、はるかに優れたアプローチを見つけることができました。あなたもそうすべきです。

185
Paulo

い回避策は、ブールparamを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);
    }
}
135
Corey Ballou

Grandpa::__construct()を使用する必要があります。他にショートカットはありません。また、これはPapaクラスのカプセル化を台無しにします。Papaを読み込んだり、作業するときは、__construct()メソッドが構築中に呼び出されると想定しても安全ですが、Kiddoクラスはこれを行いません。

69
too much php
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();
    }
}
49
Alain57

私は問題を解決する代替ソリューションを思いついた。

  • おじいちゃんを拡張した中間クラスを作成しました。
  • その後、PapaとKiddoの両方がそのクラスを拡張しました。
  • KiddoはPapaの中間機能を必要としましたが、コンストラクターが気に入らなかったため、クラスにはその追加機能があり、両方ともそれを拡張します。

私はい質問に対して有効であるがugい解決策を提供した他の2つの答えを支持しました:)

19
Paulo

フラグを使用せず、状況に応じて機能する可能性がある別のオプション:

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

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

「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();
9
Fishdrowned

これには簡単な解決策がありますが、現在のクラスがどの程度の継承を行ったかを正確に知る必要があります。幸いなことに、get_parent_class()の引数を使用すると、クラス配列のメンバーをインスタンス自体だけでなく文字列としてのクラス名にすることができます。

これはクラスの__construct()メソッドを静的に呼び出すことに本質的に依存していることを忘れないでください。ただし、継承オブジェクトのインスタンス化されたスコープ内では、この特定のケースの違いは無視できます(ah、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
mway

お望みの場所から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();
7
Xorax

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 

したがって、拡張クラス(子)内で使用できます

parent::paFkt(); 

または

Pa::paFkt();

親(またはgrandPa)の(プライベートではない)関数にアクセスします。

クラス外の定義

$test::paFkt();

厳密なエラー(非静的関数)をスローします。

4
Hauke

さて、さらに別のanotherい解決策:

次のような関数をPapaで作成します。

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

次に、Kiddoで次を使用します。

parent::call2Granpa(); // Papaでコンストラクターを呼び出す代わりに。

私はそれがうまくいくと思います...私はそれをテストしていないので、オブジェクトが正しく作成されているかどうかわかりません。

このアプローチを使用しましたが、非コンストラクター関数を使用しました。

2
lepe
<?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の構成内で何もする必要がないことを期待しています。これを実行すると出力されます:

ちょっと私はおじいちゃんですちょっと私は子供です

2
Anand P
// 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」と呼ぶことができます。

1
luchaninov
    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();
    }
}
1
Crazy Alien