J'ai besoin d'un constructeur de classe dans PHP appeler le constructeur parent (grand-parent?) De son 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 sent pas mauvais mais qui reste néanmoins curieux de savoir si c'est possible.
EDIT
Je pensais que je devrais publier la justification de la réponse choisie. La raison étant; C’est la solution la plus élégante au problème de vouloir appeler le constructeur du "grand-parent" tout en conservant toutes les valeurs. Ce n’est certainement pas la meilleure approche ni OOP amicale, mais ce n’est pas ce que la question demandait.
Pour toute personne rencontrant cette question à une date ultérieure - Veuillez trouver une autre solution . J'ai pu trouver une bien meilleure approche qui n'a pas bouleversé la structure de classe. Alors devriez-vous.
La solution de contournement laide serait de passer un paramètre booléen à Papa indiquant que vous ne souhaitez pas analyser le code contenu dans son constructeur. c'est à dire:
// 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);
}
}
Vous devez utiliser Grandpa::__construct()
, il n'y a pas d'autre raccourci pour cela. En outre, cela ruine l'encapsulation de la classe Papa
- lors de la lecture ou du travail sur Papa
, il est prudent de supposer que la méthode __construct()
sera appelée lors de la construction, mais le Kiddo
class ne fait pas cela.
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();
}
}
J'ai fini par proposer une solution alternative qui résolve le problème.
J'ai voté pour les deux autres réponses qui fournissaient des solutions valables mais laides pour une question plus laide :)
Belle solution en utilisant 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();
Une autre option qui n’utilise pas d’indicateur et qui pourrait fonctionner dans votre cas:
<?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";
Je suis d'accord avec "too php too", essayez ceci:
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;
J'ai eu le résultat attendu:
Gamin
Grand-père
Ceci est une fonctionnalité et non un bug, vérifiez ceci pour votre référence:
https://bugs.php.net/bug.php?id=42016
C'est juste la façon dont cela fonctionne. S'il voit qu'il vient du bon contexte, cette version de l'appel n'impose pas un appel statique.
Au lieu de cela, il va simplement garder cela et en être heureux.
parent :: method () fonctionne de la même manière, vous n'avez pas à définir la méthode comme statique, mais vous pouvez l'appeler dans le même contexte. Essayez ceci pour plus intéressant:
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;
Cela fonctionne aussi comme prévu:
Gamin
Grand-père
Salut
Mais si vous essayez d’initialiser un nouveau Papa, vous obtiendrez une erreur E_STRICT:
$papa = new Papa;
Normes strictes: La méthode non statique Kiddo :: hello () ne devrait pas être appelée de manière statique, en supposant que $ this provient d'un contexte incompatible
Vous pouvez utiliser instanceof pour déterminer si vous pouvez appeler un Children :: method () dans une méthode parent:
if ($this instanceof Kiddo) Kiddo::hello();
Il existe une solution plus simple pour cela, mais cela nécessite que vous sachiez exactement combien d'héritage votre classe actuelle a subi. Heureusement, les arguments de get_parent_class () permettent à votre membre du tableau de classe d’être le nom de la classe en tant que chaîne, ainsi que l’instance elle-même.
Gardez à l'esprit que cela implique également d'appeler de manière statique la méthode __construct () d'une classe, bien que, dans la portée instanced d'un objet héritant, la différence dans ce cas particulier soit négligeable (ah, PHP).
Considérer ce qui suit:
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!'
Encore une fois, ce n'est pas une solution viable pour une situation dans laquelle vous n'avez aucune idée du montant de l'héritage, en raison des limitations de debug_backtrace (), mais dans des circonstances contrôlées, cela fonctionne comme prévu.
Vous pouvez appeler Grandpa :: __ construct à partir de votre choix et le mot-clé $ this fera référence à votre instance de classe actuelle. Mais attention, avec cette méthode, vous ne pouvez pas accéder aux propriétés protégées et aux méthodes d'instance en cours à partir de cet autre contexte, uniquement aux éléments publics. => Tout travail et officiellement supporté .
Exemple
// 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();
Détail amusant sur php: les classes étendues peuvent utiliser des fonctions non statiques d'une classe parente dans une matière statique. Dehors, vous aurez une erreur stricte.
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
Donc, dans une classe étendue (Enfant), vous pouvez utiliser
parent::paFkt();
ou
Pa::paFkt();
pour accéder à une fonction parent (ou grandpa) (non privée).
En dehors de la classe
$test::paFkt();
va trow erreur stricte (fonction non statique).
Ok, encore une autre solution laide:
Créez une fonction dans Papa comme:
protected function call2Granpa() {
return parent::__construct();
}
Ensuite, dans Kiddo, vous utilisez:
parent::call2Granpa();
// au lieu d'appeler le constructeur dans Papa.
Je pense que cela pourrait fonctionner ... Je ne l'ai pas testé, je ne suis donc pas sûr que les objets soient créés correctement.
J'ai utilisé cette approche mais avec des fonctions non constructeurs.
<?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();
?>
Bien entendu, cela n'implique pas que vous ayez besoin de faire quoi que ce soit dans le concept du pa_pa. En cours d'exécution, cela affichera:
Hey je suis grand papa Hey je suis un enfant
// 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();
}
}
notez que "___construct" n'est pas un nom magique, vous pouvez l'appeler "doGrandpaStuff".
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();
}
}