How do I get a PHP class constructor to call its parent's parent's constructor?
Solution 1
The ugly workaround would be to pass a boolean param to Papa indicating that you do not wish to parse the code contained in it's constructor. i.e:
// 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);
}
}
Solution 2
You must use Grandpa::__construct()
, there's no other shortcut for it. Also, this ruins the encapsulation of the Papa
class - when reading or working on Papa
, it should be safe to assume that the __construct()
method will be called during construction, but the Kiddo
class does not do this.
Solution 3
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();
}
}
Solution 4
Beautiful solution using 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();
Solution 5
I ended up coming up with an alternative solution that solved the problem.
- I created an intermediate class that extended Grandpa.
- Then both Papa and Kiddo extended that class.
- Kiddo required some intermediate functionality of Papa but didn't like it's constructor so the class has that additional functionality and both extend it.
I've upvoted the other two answers that provided valid yet ugly solutions for an uglier question:)
Related videos on Youtube
Paulo
I am a LAMP-stack developer with 15 years in the industry. I am one of the two owners of Luscious Orange, a design and development firm based out of Winnipeg Canada.
Updated on September 25, 2020Comments
-
Paulo over 3 years
I need to have a class constructor in PHP call its parent's parent's (grandparent?) constructor without calling the parent constructor.
// 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 } }
I know this is a bizarre thing to do and I'm attempting to find a means that doesn't smell bad but nonetheless, I'm curious if it's possible.
-
Mark over 14 yearsIs there a reason you can't just instantiate Grandpa inside of Kiddo's construct?
-
Paulo over 14 yearsThe Grampa constructor sets properties for itself that are inherited by its children. Papa does some stuff in it's constructor that will mess up Kiddo. So I need the call to Grandpa constructor to set properties for Kiddo during construction.
-
MitMaro over 14 yearsThen shouldn't Kiddo extend from Grandpa and not Papa.
-
Paulo over 14 years@MitMaro. I agree and I actually solved my actual problem by creating an intermediate class that extended Grandpa. Then both Papa and Kiddo extended that class. Kiddo required some intermediate functionality of Papa but didn't like it's constructor so the class has that additional functionality and both extend it.
-
MitMaro over 14 yearsA perfect solution. You should post it as an answer.
-
Paulo over 11 yearsChanged the accepted answer to the one that truly resolves the question being asked.
-
bpoiss about 6 yearswhat if the grandparent class is abstract?
-
-
Mark over 14 yearsCan't understand how. Declaring __construct as static results in the following error for me "Fatal error: Constructor Grandpa::__construct() cannot be static" under PHP5.3
-
Paulo over 14 yearsWhen I tried it, I didn't declare it as static. I created the class structure normally but instead of calling parent::__construct(), I called Grandpa::__construct() and it worked. I doesn't seem right to me either but this whole question got kinda weird.
-
xximjasonxx almost 14 yearsI think the better idea here is to break the functionality you are trying to use out of the constructed and into a protected method. Then you can call that method from a constructor selectively
-
JCC over 12 yearsAgreed. I use this all the time - you can call a class by it's name, not just via the magic names of
parent
orself
. I have been known to go three or four classes deep. In fact, I've started referring to my base class by it's name rather than using parent, that way I'm sure I'm getting the right object, always. -
Iain Collins about 12 yearsPersonally I wouldn't choose to do this as it means Papa's contractor won't get called at all. I'd go with something like cballou's approach (i.e. of passing an argument to Papa's constructor and having it invoke it's parents constructor or not based on that).
-
nalply over 11 yearsThis does not answer the exact question you've phrased. This happens if the real world muddies up something which should be clear and confined. It's a pity for this question.
-
Kostanos almost 11 yearsgood workaround, but it is not acceptable if the parent class comes from some external library wish you with to extend. I like the too much php answer below.
-
mimarcel almost 11 yearsThe situation we are in here is in such a way that we need to skip the parent's logic and in most of the cases we can't change the grandparent or the parent classes. I believe this is the best way to do it as there are changes made only in the child. The only issue is that it might throw an E_STRICT notice link, it didn't for me though when I tested it.
-
llange over 8 yearsJust remember that parent is only a shortcut to whatever first parent that implemented the method… Thus from a descendant calling
AscendantName::method
works and from an ascendant callingstatic::method
will always call the latest generation that implemented the method. And you may check not to call yourself using(get_class($this)==__CLASS__?'Healthy people dont\'t call themself…':'Calling latest')
if you'd like parents to call kid methods (seems strange but might be usefull combined with private function and __call magic function )… -
nicksona over 7 yearsEvilChookie`s solusion is the best. Should be the approved answer. Than you Chookie!
-
SparK over 7 yearsIn php when you call a function using static operator
::
from an object context it will be called using the object context which is completely fkd-up. At least in JS (about thethis
madness) it uses the callee context. -
v010dya over 6 yearsThis is an interesting solution, however, if you really don't need the logic of the parent's constructor, are you sure that you are really making a subsclass of a parent?
-
Travis Weston over 6 years@Wouter0100 lala977 did say "From PHP 7" which your link is using 5.6
-
Wouter0100 over 6 years@TravisWeston please recheck my link. it tests that peace of code against all versions. 5.6 up to 7.2 reproduce the same error, while other runtimes return some different errors.
-
Halfstop about 6 yearsThis is the correct answer. While it may seem silly to inherit Papa but you want to call the GrandPa constructor without Papa, I've found it useful to be do. I want to keep the hierarchy, but I need to do a clean Kiddo constructor that doesn't have anything to do with Papa, but still want the benefits of using what's going on in GrandPa's constructor. Maybe Papa is doing a bunch of junk in the constructor that isn't needed or wanted by Kiddo, but it still has useful components.
-
Pedro over 4 yearsThat's actually quite clever. In my implementation I do
if($bypass) return;
& can position it so some important stuff gets done before the bypass. -
Tranzium over 3 years@SparK If you are using PHP 5.3.0 or later, Late Static Bindings would most likely solve your use case.
-
iKev61 over 2 yearsJust called grandpa like I'm the boss