PHP 8.4 introduces Property Hooks, one of the most significant object-oriented programming features added to PHP in years. Property hooks allow developers to attach logic directly to property reads and writes while preserving the natural property access syntax.
What Are Property Hooks?
Traditionally, PHP properties are simple storage containers:
class User
{
public string $name;
}
Reading or writing the property performs no additional logic:
$user = new User(); $user->name = 'John'; echo $user->name;
Property hooks change this by allowing you to intercept property access:
class User
{
public string $name
{
set => ucfirst(trim($value));
}
}
Whenever a value is assigned to $name, the hook runs automatically.
The syntax feels similar to property accessors found in languages such as C#, Kotlin, and Swift.
Why Were Property Hooks Added?
For years, PHP developers often wrote boilerplate code like this:
class User
{
private string $name;
public function getName(): string
{
return $this->name;
}
public function setName(string $name): void
{
$this->name = ucfirst(trim($name));
}
}
This works, but introduces a lot of repetitive code.
Property hooks reduce that boilerplate:
class User
{
public string $name
{
set => ucfirst(trim($value));
}
}
Usage remains simple:
$user->name = ' john '; echo $user->name; // John
Understanding the set Hook
The most common use case is validating or transforming values before storing them.
Validation Example:
class Product
{
public float $price
{
set {
if ($value < 0) {
throw new InvalidArgumentException( 'Price cannot be negative' );
}
$this->price = $value;
}
}
}
Now invalid assignments are prevented:
$product->price = -10; // Exception
Data Normalization Example:
class User
{
public string $email
{
set => strtolower(trim($value));
}
}
Assignments become automatically normalized:
$user->email = ' John@Example.COM '; echo $user->email; // john@example.com
Â
Understanding the get Hook
A get hook allows a custom behavior whenever a property is read.
class Temperature
{
private float $celsius = 25;
public float $fahrenheit
{
get => ($this->celsius * 9 / 5) + 32;
}
}
Reading the property computes the value dynamically:
$temp = new Temperature(); echo $temp->fahrenheit; // 77
This creates a property-like API while hiding implementation details or what it called computed property.
Full get and set Hooks
You can define both hooks on the same property.
class Person
{
private string $fullNameStorage = '';
public string $fullName
{
get => $this->fullNameStorage;
set => trim($value);
}
}
This gives complete control over reads and writes.
Â
Backed vs Virtual Properties
Property hooks support two different styles.
Backed Properties
A backed property stores data internally.
class User
{
public string $name {
set => ucfirst($value);
}
}
The property still exists physically.
Virtual Properties
A virtual property has no actual storage and computes its value entirely through hooks.
class Rectangle
{
public int $width;
public int $height;
public int $area {
get => $this->width * $this->height;
}
}
There is no separate $area field.
echo $rectangle->area;
The value is generated on demand.
Practical Use Cases:
1.Input Validation
public int $age {
set {
if ($value < 0) {
throw new InvalidArgumentException();
}
$this->age = $value;
}
}
2.Data Sanitization
public string $username {
set => trim($value);
}
3.Computed Values
public float $total {
get => $this->price * $this->quantity;
}
4.Lazy Calculations
public string $slug {
get => strtolower(
str_replace(' ', '-', $this->title)
);
}
5.Domain Rules
public string $status {
set {
$allowed = [
'draft',
'published',
'archived'
];
if (!in_array($value, $allowed)) {
throw new InvalidArgumentException();
}
$this->status = $value;
}
}
Do Property Hooks Replace Getters and Setters?
Sometimes, but not completely.
Property hooks can eliminate many traditional getter and setter methods.
For example, instead of:
$user->setEmail('john@example.com');
you can write:
$user->email = 'john@example.com';
And instead of:
echo $user->getEmail();
you can write:
echo $user->email;
This produces cleaner and more expressive code.
When Property Hooks Are Better
Property hooks shine when:
- Performing validation
- Normalizing data
- Computed values
- Reducing boilerplate.
When Getters and Setters still make sense
Property hooks are not a complete replacement.
Consider this method:
public function publish(): void
{
if (!$this->isApproved()) {
throw new RuntimeException();
}
$this->status = 'published';
}
This is business behavior, not property access.
Similarly:
$order->cancel(); $user->activate(); $post->publish();
represent actions and workflows. These should remain methods.
A good rule of thumb: Property Hooks = property-related logic, Methods = business operations.


