Using property hooks in PHP
PHP 8.4's property hooks let you replace simple getter methods with virtual properties, keeping a consistent property-based API. Here's when I reach for them and why.
Property hooks have existed in PHP since 8.4 - 1.5 years ago now - and whilst they're not something I've reached for often, they do have their place.
Consider the following object.
final readonly class EntityReference
{
public function __construct(
public Type $type,
public string $reference
) {}
public function key(): string
{
return "{$this->type->value}:{$this->reference}";
}
}
// And reference the key as expected
$entity = new EntityReference(Type::Business, 'business-1');
$entity->key(); // businesses:business-1
Fairly commonplace pattern in PHP land. We want to have some kind of derived value on a class, surfaced into the public API by way of a getter.
With property hooks, we can do away with the method entirely by defining a virtual property.
final class EntityReference
{
public string $key {
get => "{$this->type->value}:{$this->reference}";
}
public function __construct(
public readonly Type $type,
public readonly string $reference
) {}
}
// Reference the key now as a property
$entity = new EntityReference(Type::Person, 'person-1');
$entity->key; // people:person-1
The subtle difference here is that a class with virtual property hooks is not allowed to be readonly.
By adding the virtual property here, we expose the same data, expose it via a public interface, and keep a consistent property-based access.
I don't reach for these often, but when I have an otherwise property-only data structure, I think it makes more sense to surface computed values as virtual properties rather than methods. I tend to reserve methods for behaviours or complex logic, and defer to virtual properties for simple derived values.
Written by Michael Dyrynda
Principal Engineer, Laravel enthusiast, and open source contributor. I write about web development, PHP, and the problems I solve along the way.