269 votes

Comment faire en sorte que le constructeur d'une classe PHP appelle le constructeur du parent de son parent ?

Je dois faire en sorte que le constructeur d'une classe en PHP appelle le constructeur de son parent. du parent (grand-parent ?) sans appeler le constructeur parent.

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

Je sais que c'est une chose bizarre à faire et j'essaie de trouver un moyen qui ne sente pas mauvais mais néanmoins, je suis curieux de savoir si c'est possible.

0 votes

Y a-t-il une raison pour laquelle vous ne pouvez pas simplement instancier Grand-père à l'intérieur de la construction de Kiddo ?

0 votes

Le constructeur de Grampa définit des propriétés pour lui-même qui sont héritées par ses enfants. Papa fait des choses dans son constructeur qui vont perturber Kiddo. J'ai donc besoin de l'appel au constructeur de Grand-père pour définir les propriétés de Kiddo pendant la construction.

5 votes

Alors, Kiddo ne devrait-il pas s'étendre de Grand-père et non de Papa.

221voto

cballou Points 13804

La solution la plus simple serait de passer un paramètre booléen à Papa pour indiquer que vous ne souhaitez pas analyser le code contenu dans son constructeur :

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

21 votes

C'est une bonne solution de contournement, mais elle n'est pas acceptable si la classe parent provient d'une bibliothèque externe que vous souhaitez étendre. J'aime la réponse too much php ci-dessous.

0 votes

C'est en fait très astucieux. Dans mon implémentation, je fais if($bypass) return; & peut le positionner de façon à ce que certaines choses importantes soient faites avant le contournement.

90voto

too much php Points 27983

Vous devez utiliser Grandpa::__construct() il n'y a pas d'autre raccourci pour cela. De plus, cela détruit l'encapsulation de l'objet Papa classe - lorsque vous lisez ou travaillez sur Papa on peut supposer que le __construct() sera appelée pendant la construction, mais la méthode Kiddo ne le fait pas.

0 votes

Je ne comprends pas comment. En déclarant __construct comme statique, j'obtiens l'erreur suivante "Fatal error : Constructor Grandpa::__construct() cannot be static" sous PHP5.3.

0 votes

Quand je l'ai essayé, je ne l'ai pas déclaré comme statique. J'ai créé la structure de classe normalement, mais au lieu d'appeler parent::__construct(), j'ai appelé grand-père::__construct() et ça a marché. Cela ne me semble pas correct non plus, mais toute cette question est devenue un peu bizarre.

13 votes

Je suis d'accord. Je l'utilise tout le temps - vous pouvez appeler une classe par son nom, et pas seulement via les noms magiques de parent ou self . Il m'est arrivé d'aller jusqu'à trois ou quatre classes. En fait, j'ai commencé à faire référence à ma classe de base par son nom plutôt qu'en utilisant le terme parent, de cette façon je suis sûr d'obtenir le bon objet, toujours.

58voto

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

0 votes

Personnellement, je ne choisirais pas de faire cela car cela signifie que l'entrepreneur de Papa ne sera pas appelé du tout. Je choisirais quelque chose comme l'approche de cballou (c'est-à-dire passer un argument au constructeur de Papa et lui faire invoquer c'est constructeur de parents ou non en fonction de cela).

0 votes

La situation dans laquelle nous nous trouvons ici est telle que nous devons ignorer la logique du parent et, dans la plupart des cas, nous ne pouvons pas modifier les classes du grand-parent ou du parent. Je pense que c'est la meilleure façon de procéder car les changements ne sont effectués que dans l'enfant. Le seul problème est qu'il peut y avoir un avis E_STRICT. lien Ce n'était pas le cas pour moi lorsque je l'ai testé.

1 votes

Il s'agit d'une solution intéressante, cependant, si vous vraiment n'ont pas besoin de la logique du constructeur du parent, êtes-vous sûr que vous créez vraiment une sous-classe d'un parent ?

21voto

Paulo Points 1545

J'ai fini par trouver une solution alternative qui a résolu le problème.

  • J'ai créé une classe intermédiaire qui a prolongé Grand-père.
  • Puis Papa et Kiddo ont prolongé cette classe.
  • Kiddo avait besoin d'une fonctionnalité intermédiaire de Papa mais n'aimait pas son constructeur. La classe a donc cette fonctionnalité supplémentaire et les deux l'étendent.

J'ai upvoted les deux autres réponses qui ont fourni des solutions valables mais laides pour une question encore plus laide :)

4 votes

Je pense que la meilleure idée ici est de casser la fonctionnalité que vous essayez d'utiliser hors de la construction et dans une méthode protégée. Ensuite, vous pouvez appeler cette méthode à partir d'un constructeur de manière sélective.

0 votes

Cela ne répond pas à la question exacte que vous avez formulée. C'est ce qui arrive lorsque le monde réel embrouille quelque chose qui devrait être clair et limité. C'est dommage pour cette question.

16voto

MitMaro Points 2604

Une autre option qui n'utilise pas de drapeau et qui pourrait fonctionner dans votre 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";

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X