PHP property hooks let a property define code that runs when you read or write it. Introduced in PHP 8.4, hooks reduce repetitive getter and setter methods while keeping property access direct and readable.
A property may define a get hook, a set hook, or both. You can use a backed property to store a value or a virtual property to calculate a value without storing it.
Create a Backed Property with a Set Hook
A backed property keeps its own value. Inside a set hook, assign the validated or normalized value to the property. The assignment targets the backing value and does not repeatedly call the same hook.
Example:
<?php
class Customer
{
public string $email {
set {
// Normalize the address before storing it.
$email = strtolower(trim($value));
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new InvalidArgumentException("Invalid email address.");
}
$this->email = $email;
}
}
}
$customer = new Customer();
$customer->email = " [email protected] ";
echo $customer->email; // [email protected]
The implicit variable $value contains the value supplied by the caller. The declared property type still applies, so a value must also satisfy normal PHP type rules.
Use Short Hook Syntax
When a hook needs one expression, use the arrow form. It keeps small transformations compact without hiding complex logic.
Example:
<?php
class Product
{
public float $price {
// Prevent a negative stored price.
set => max(0, $value);
}
}
$product = new Product();
$product->price = -25;
echo $product->price; // 0
Create a Virtual Computed Property
A property is virtual when neither hook accesses its backing storage. A read-only computed value is a common use. The following fullName property derives its result from two stored properties.
Example:
<?php
class User
{
public function __construct(
public string $firstName,
public string $lastName
) {}
public string $fullName {
// Calculate the value each time it is read.
get => trim($this->firstName . " " . $this->lastName);
}
}
$user = new User("Aarav", "Sharma");
echo $user->fullName; // Aarav Sharma
Because fullName has no set hook and no backing assignment, callers cannot store a separate full name through this property.
Define Both Get and Set Behavior
You can combine hooks when storage and presentation use different forms. This example stores a score within its allowed range and formats the read value.
Example:
<?php
class Review
{
public int $rating {
// Display a readable rating when accessed.
get => $this->rating;
// Store only a value from 1 through 5.
set {
if ($value < 1 || $value > 5) {
throw new ValueError("Rating must be from 1 to 5.");
}
$this->rating = $value;
}
}
}
$review = new Review();
$review->rating = 5;
echo $review->rating;
Specify a Setter Parameter
You may name and type the setter parameter explicitly. Its accepted type can be broader than the property type, as long as the hook stores a value that satisfies the property declaration.
Example:
<?php
class Invoice
{
public DateTimeImmutable $issuedAt {
set(string|DateTimeImmutable $date) {
// Accept a ready object or convert an ISO date string.
$this->issuedAt = $date instanceof DateTimeImmutable
? $date
: new DateTimeImmutable($date);
}
}
}
$invoice = new Invoice();
$invoice->issuedAt = "2026-09-01";
echo $invoice->issuedAt->format("Y-m-d");
Declare Property Requirements in an Interface
An interface can require readable or writable property behavior. An implementing class may satisfy the contract with a normal public property or compatible hooks.
Example:
<?php
interface Named
{
// Implementations must expose a readable name.
public string $name { get; }
}
class Employee implements Named
{
public function __construct(
public string $firstName,
public string $lastName
) {}
public string $name {
get => $this->firstName . " " . $this->lastName;
}
}
Property Hook Restrictions
| Rule | Reason |
|---|---|
| Hooks require PHP 8.4 or later | Earlier PHP versions cannot parse the syntax. |
| Static properties cannot use hooks | Hooks apply to object properties. |
| Readonly properties cannot use hooks | Hook behavior conflicts with readonly storage rules. |
| Hooked properties cannot share one declaration | Declare each hooked property separately. |
| A virtual property has no backing value | Its hooks calculate or route the value elsewhere. |
Tip: Keep hooks focused on property-level rules. Use a method when an operation performs database work, sends messages, or changes several parts of the object.
Conclusion
PHP property hooks place validation, normalization, and computed access beside the property they control. Use backed hooks for stored values, virtual hooks for derived values, and explicit setter parameters when callers may provide more than one input type. Apply hooks to small, predictable property behavior and keep larger business operations in methods.