๐ŸŽ“ A1Learner
๐Ÿ”
0 of 27 lessons completed

Reflection in Depth

Reflection can also act on a class, not only describe it. It can call methods, build objects and read private properties.

A method called through reflection

The hello method of the Greeter class is fetched as a reflection method. The invoke call runs it on the object with one argument, and the greeting prints.

<?php
class Greeter {
  public function hello($name) {
    return "Hello, " . $name;
  }
}
$g = new Greeter();
$ref = new ReflectionClass(Greeter::class);
$method = $ref->getMethod("hello");
echo $method->invoke($g, "Ana") . "\n";

An object built with newInstance

The newInstance call on the ReflectionClass builds a Book and passes two constructor arguments. A method on the built object prints its line.

<?php
class Book {
  public function __construct(
    public string $title,
    public string $author
  ) {
  }
  public function line() {
    return $this->title . " by " . $this->author;
  }
}
$ref = new ReflectionClass(Book::class);
$book = $ref->newInstance("Dune", "Herbert");
echo $book->line() . "\n";

A private property read from outside

The secret property of the Vault class is private. A ReflectionProperty reads its value from outside the class, and the secret prints.

<?php
class Vault {
  private string $secret = "open-sesame";
}
$v = new Vault();
$prop = new ReflectionProperty(Vault::class, "secret");
echo $prop->getValue($v) . "\n";

Parent and subclass verdicts

The Dog class extends the Animal class. The subclass verdict prints as a bool, and the parent name comes from the reflection of the child.

<?php
class Animal {
}
class Dog extends Animal {
}
var_dump(is_subclass_of(Dog::class, Animal::class));
$ref = new ReflectionClass(Dog::class);
echo $ref->getParentClass()->getName() . "\n";

Example

<?php
class Shape {
  public function kind() {
    return "shape";
  }
}
class Circle extends Shape {
  public function kind() {
    return "circle";
  }
}
function inspect($obj) {
  $ref = new ReflectionClass($obj);
  echo $ref->getName() . "\n";
  echo $ref->getParentClass()->getName() . "\n";
  $method = $ref->getMethod("kind");
  echo $method->invoke($obj) . "\n";
}
inspect(new Circle());

Key points

  • The getMethod method returns one method ready to be called.
  • The invoke method calls that method on a given object.
  • The newInstance method on a ReflectionClass builds an object with given constructor arguments.
  • A ReflectionProperty object can read a private property from outside the class.
  • The getParentClass method returns the parent class of a child class.

In this example, the inspect function takes one object and reports on it. Reflection prints the class name first and the parent class name next. The kind method is then called through reflection, and its result prints last.

Note

Private state stays private for normal code, and reflection is the deliberate exception to that rule.

Try it Yourself

Edit the code, then press Run.

Running is simulated

Exercise

How can code outside a class read a private property of an object?