---
title: "Calling All Ancestors"
url: https://www.exakat.io/calling-all-ancestors/
date: 2026-03-12
modified: 2026-03-14
author: "dams"
description: "PHP Inheritance Challenge: Calling All Ancestors PHP's object-oriented features are exhaustive and modern, yet sometimes life send you a little challenge: who doesn't like a surprise? Today we'll look at..."
categories:
  - "Code auditing"
tags:
  - "class"
  - "puzzle"
  - "reflection"
  - "tip"
  - "trick"
image: https://www.exakat.io/wp-content/uploads/2026/03/dog.320.jpg
word_count: 1083
---

# Calling All Ancestors

# PHP Inheritance Challenge: Calling All Ancestors

PHP's object-oriented features are exhaustive and modern, yet sometimes life send you a little challenge: who doesn't like a surprise? Today we'll look at a rare inheritance puzzle. In this post, we are calling all ancestors in a class hierarchy.

We start with three classes, extending each other in a hierarchy. Each of them has a distinct eponymous method (eponymous is a fancy word for same name). Each version of the method returns a distinct value, for easy identification.

Now, the goal, if you accept it, is to call all three versions of that method, from the deepest child class.

Sounds easy, right? Let's dive in and see where the trap lies, and how to escape it.

## The 'Calling All Ancestors' Setup

We define three classes: `Grandparents`, `Parents`, which extends `Grandparents`, and `Children`, which extends `Parents`. Each has a non‑static method `foo()` that returns a unique string.

You might note that all the class names are plural: this helps go around a limitation in this illustration, where `parent` cannot be used as a class name. `parent` might be used as a method or a constant name, but not a class. It is used as a relative class name by PHP, to access the parent class. And that might be useful later.

Note also that if PHP has its own exception with using `parent` as a class, British English doesn't use `Childs`, but `Children`. Apparently, exceptions is a common thing in every language, programming or not.

Otherwise, nothing fancy: just classic overriding. Now, our challenge: inside the `Children` class, we want a method that calls **all three** `foo()`implementations and returns an array with the results. Let's call it `callAllFoos()`.

## First Attempts: $this and parent

Inside `Children`, we can easily call its own `foo()` using `$this`:

To call the direct parent’s version, PHP gives us the `parent` keyword. Pay attention, `parent` is a PHP keyword, while `Parents` is the class in the code:

That works perfectly. Now we need the grandparent’s version. What about `Grandparents::foo()`?

First, `grandparent` is not a PHP keyword, so this is wrong. It would be fun, though, as any prolongement of that allegory would give us `greatgrandparent` for the 3rd level, and `greatgreatgrandparent` for the 4th level, and the longest keyword ever for the 128th level (just because 128 levels of inheritance would be a reasonable limit, I guess?)

## The Real Challenge: Accessing the Grandparent Properly

We need a way to call `Grandparent::foo()` on our current object `Children`.

`parent` is a good keyword, but it is not possible to chain it to access another level of PHP. PHP does not interpret the right side of the `::` call as a keyword, but as a constant name. And, indeed, it is possible to call a constant `parent`.

### The Failed Trick: Closure Binding

A possible plan is to use a closure and bind it with the grandparent's scope:

Unfortunately, this **does not work**. The scope parameter in `bindTo` only affects visibility, which make private/protected methods accessible, and static method resolution. For non‑static calls, the method dispatch is still based on the actual class of the object (`Child`). So `$this->foo()` inside the closure will still call `Children::foo()`, not `Grandparents::foo()`.

So we need another approach.

### The Successful Trick: Static Method call

Obviously, this is a static call to a non‑static method. Up to PHP 7, this would trigger a deprecation warning; in PHP 8, it is a fatal error. It is also a bad practice. So technically, this line does not work. And yet...

Just like calling `parent::foo()` looks like a static call, but is, in fact, dependent on the method's actual signature, and `Grandparents::foo()`works here. It is because `Grandparents` is part of the current class's hierarchy.

In fact, not only it is possible to call that non-static method statically, but PHP goes the extra mile, and even assign `$this`, as one would expect in a non-static method. Et voila!

### The Other Successful Trick: Static Method call

[Julio J](https://phpc.social/@j3j5@hachyderm.io) found another way, by using the [forward_static_call ](https://www.php.net/forward_static_call)function: it actually works the same way has the syntax above, using the same parameters. Also, $this is available in the method.

### A Reliable Solution: Reflection

Another possible solution is to use the always reliable PHP's `ReflectionMethod`:

`ReflectionMethod::invoke($object)` calls the method on the given object, using the method's original definition (from `Grandparents`). This bypasses any overriding.

Let's test it:

Output:

```
Array
(
[0] => Children
[1] => Parents
[2] => Grandparents
)
```

`ReflectionMethod` represents the method as defined in a specific class. When we invoke it on an object, it calls that exact method implementation, regardless of whether the object's class overrides it. The object must be an instance of that class or a subclass, which it is, and the method must be accessible (if it's private, we'd need `setAccessible(true)`). In our case, it's public, so it's fine.

## Conclusion

PHP's inheritance model gives you direct access to the current class (`$this`) and the immediate parent (`parent`), but ancestors beyond that are hidden, unless the methods are not overriden by the lower levels. However, with a static call or with reflection, it is possible to reach any level of the hierarchy. This little puzzle shows that even on a beaten path like OOP, there are still hidden corners and a special way for PHP to save the day.

So, now, it is possible to emulate a `::parent`operator, but what about a `::grandparent`operator, like the `::class` one? You might be in luck...