it-swarm.com.de

Wie bekomme ich einen PHP Klassenkonstruktor, um den Konstruktor seines Elternteils aufzurufen

Ich brauche einen Klassenkonstruktor in PHP, der den parent's (grandparent?) Konstruktor seiner Eltern aufruft, ohne den übergeordneten Konstruktor aufzurufen.

// 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
    }
}

Ich weiß, dass dies eine bizarre Sache ist und ich versuche, ein Mittel zu finden, das nicht schlecht riecht, aber trotzdem bin ich neugierig, ob es möglich ist.

EDIT

Ich dachte, ich sollte die Begründung für die gewählte Antwort posten. Der Grund ist; Es ist die eleganteste Lösung für das Problem, den Konstruktor der "Großeltern" aufrufen zu wollen und dabei alle Werte beizubehalten. Es ist sicherlich nicht der beste Ansatz, noch ist es OOP freundlich, aber das ist nicht, was die Frage gestellt hat.

Für alle, die zu einem späteren Zeitpunkt auf diese Frage stoßen - Bitte suchen Sie eine andere Lösung . Ich konnte einen viel besseren Ansatz finden, der die Klassenstruktur nicht verwüstete. Das solltest du auch.

189
Paulo

Die hässliche Lösung wäre, Papa einen booleschen Parameter zu übergeben, der angibt, dass Sie den im Konstruktor enthaltenen Code nicht analysieren möchten. d.h.

// 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);
    }
}
141
Corey Ballou

Sie müssen Grandpa::__construct() verwenden, es gibt keine andere Verknüpfung dafür. Dies ruiniert auch die Kapselung der Klasse Papa. Wenn Sie Papa lesen oder bearbeiten, sollten Sie davon ausgehen, dass die Methode __construct() während der Erstellung aufgerufen wird. Aber die Klasse Kiddo tut dies nicht.

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

Am Ende fand ich eine alternative Lösung, die das Problem löste.

  • Ich schuf eine Zwischenklasse, die Opa verlängerte.
  • Dann erweiterten Papa und Kiddo diese Klasse.
  • Kiddo benötigte einige Zwischenfunktionen von Papa, mochte den Konstruktor jedoch nicht, so dass die Klasse diese zusätzlichen Funktionen hat und beide diese erweitern.

Ich habe die beiden anderen Antworten, die gültige, aber hässliche Lösungen für eine hässlichere Frage lieferten, positiv bewertet :)

19
Paulo

Schöne Lösung mit 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();
18

Eine weitere Option, bei der keine Flagge verwendet wird und die in Ihrer Situation möglicherweise funktioniert:

<?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

Ich bin mit "too much php" einverstanden, versuche dies:

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;

Ich habe das Ergebnis wie erwartet erhalten:

Kiddo

Opa

Dies ist eine Funktion, die kein Fehler ist. Überprüfen Sie dies als Referenz:

https://bugs.php.net/bug.php?id=42016

Es ist genau so, wie es funktioniert. Wenn es sieht, dass es aus dem richtigen Kontext stammt, erzwingt diese Aufrufversion keinen statischen Aufruf.

Stattdessen wird es einfach $ dies behalten und damit zufrieden sein.

parent :: method () funktioniert auf die gleiche Weise, Sie müssen die Methode nicht als statisch definieren, sondern können sie im selben Kontext aufrufen. Probieren Sie dies aus, um mehr zu erfahren:

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;

Es funktioniert auch wie erwartet:

Kiddo

Opa

Hallo

Wenn Sie jedoch versuchen, einen neuen Papa zu initialisieren, erhalten Sie einen E_STRICT-Fehler:

$papa = new Papa;

Strenge Standards: Nicht statische Methode Kiddo :: hello () sollte nicht statisch aufgerufen werden, vorausgesetzt, dies ist aus inkompatiblem Kontext möglich

Sie können instanceof verwenden, um zu bestimmen, ob Sie eine Children :: -Methode () in einer übergeordneten Methode aufrufen können:

if ($this instanceof Kiddo) Kiddo::hello();
9
Fishdrowned

Hierfür gibt es eine einfachere Lösung, aber Sie müssen genau wissen, wie viel Vererbung Ihre aktuelle Klasse durchlaufen hat. Glücklicherweise ermöglichen die Argumente von get_parent_class (), dass Ihr Klassenarraymitglied der Klassenname als Zeichenfolge sowie als Instanz selbst ist.

Bedenken Sie, dass dies auch inhärent auf dem statischen Aufruf einer Klasse '__construct () - Methode beruht, obwohl der Unterschied in diesem speziellen Fall im instanziierten Bereich eines erbenden Objekts vernachlässigbar ist (ah, PHP).

Folgendes berücksichtigen:

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!'

Auch dies ist keine praktikable Lösung für eine Situation, in der Sie aufgrund der Einschränkungen von debug_backtrace () keine Ahnung haben, wie viel Vererbung stattgefunden hat, aber unter kontrollierten Umständen wie beabsichtigt funktioniert.

8
mway

Sie können Opa :: __ Konstrukt aufrufen, von wo aus Sie möchten, und das Schlüsselwort $ this verweist auf Ihre aktuelle Klasseninstanz. Mit dieser Methode können Sie jedoch nicht auf geschützte Eigenschaften und Methoden der aktuellen Instanz zugreifen, sondern nur auf öffentliche Elemente. => Alle Arbeiten und offiziell unterstützt .

Beispiel

// 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

Witzige Details zu PHP: Erweiterte Klassen können nicht-statische Funktionen einer übergeordneten Klasse in einer statischen Angelegenheit verwenden. Außerhalb erhalten Sie einen strengen Fehler.

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 

Also in einer erweiterten Klasse (Child) können Sie verwenden

parent::paFkt(); 

oder

Pa::paFkt();

um auf die (nicht private) Funktion eines Elternteils (oder Großvaters) zuzugreifen.

Außerhalb der Klasse def

$test::paFkt();

wird strengen Fehler auslösen (nicht statische Funktion).

4
Hauke

Ok, noch eine hässliche Lösung:

Erstellen Sie eine Funktion in Papa wie:

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

Dann verwenden Sie in Kiddo:

parent::call2Granpa(); // statt Konstruktor in Papa aufzurufen.

Ich denke, es könnte funktionieren ... Ich habe es nicht getestet, daher bin ich mir nicht sicher, ob die Objekte korrekt erstellt wurden.

Ich habe diesen Ansatz verwendet, jedoch mit Funktionen, die keine Konstruktoren sind.

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

Dies setzt natürlich voraus, dass Sie im Konstrukt von pa_pa nichts tun müssen. Wenn Sie dies ausführen, wird Folgendes ausgegeben:

Hey, ich bin Großvater Hey, ich bin ein Kind

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

beachte, dass "___construct" kein magischer Name ist, du kannst ihn "doGrandpaStuff" nennen.

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