Lazy Objects

PHP 8.4 added lazy objects: an object that looks fully constructed the moment it is created, but does not actually run its initialization logic until the first time one of its properties is read or written. This suits objects that are expensive to set up in full — a database connection, a large computed value — but are not always needed once created. A lazy ghost is created with ReflectionClass::newLazyGhost($initializer), where $initializer is a callback that receives the new, still-uninitialized object and is responsible for setting its properties directly on it.

<?php
class User {
  public string $name;
  public int $age;
}

$initializerCalls = 0;

$reflector = new ReflectionClass(User::class);

$user = $reflector->newLazyGhost(function (User $user) use (&$initializerCalls) {
  $initializerCalls++;
  echo "Initializer running...\n";
  $user->name = 'Ada';
  $user->age = 36;
});

echo "Object created. Initializer calls so far: $initializerCalls\n";

echo "Accessing name: {$user->name}\n";
echo "Initializer calls after access: $initializerCalls\n";

echo "Accessing age: {$user->age}\n";
echo "Initializer calls after second access: $initializerCalls\n";
?>

Object created. Initializer calls so far: 0 Initializer running... Accessing name: Ada Initializer calls after access: 1 Accessing age: 36 Initializer calls after second access: 1
The initializer runs the first time any property on the object is accessed, and only that once: creating $user does not run it, the first read of ->name triggers it and sets every property inside it, and the following read of ->age simply returns the value that is already there. From the caller's point of view, code using $user cannot tell whether it was handed a lazy object or an ordinary, already-initialized one.