PHP 8.5 Property Hooks: Practical Examples
PHP Code Editor
Execution Result
Ready to execute
Click the "Run Script" button to see the output here
Description
PHP 8.5 introduces property hooks: get and set blocks attached directly to a property declaration. Before hooks, validation and transformation on read/write required either __get/__set magic methods (which apply globally and need extra bookkeeping) or explicit getX()/setX() methods (which are verbose and break direct property access syntax).
A set hook receives the incoming value as $value and can validate or transform it before storing. A get hook runs on read and can compute a derived value. Properties with only a get hook have no backing storage at all. Asymmetric visibility (public private(set)) is a related feature that makes a property publicly readable but writable only from within the class, enforced at the engine level without any hook code needed.
<?php
/**
* PHP 8.5 property hooks: get and set hooks replace
* the verbose getProp() / setProp() pattern.
*
* Requires PHP 8.5+
*/
class Temperature
{
// Hook on set: validate and convert
public float $celsius {
get => $this->celsius;
set {
if ($value < -273.15) {
throw new ValueError("Temperature below absolute zero: $value");
}
$this->celsius = round($value, 2);
}
}
// Computed property via get hook (no backing storage)
public float $fahrenheit {
get => $this->celsius * 9/5 + 32;
}
public float $kelvin {
get => $this->celsius + 273.15;
}
public function __construct(float $celsius)
{
$this->celsius = $celsius;
}
}
$t = new Temperature(100.0);
printf("Celsius: %.2f\n", $t->celsius); // 100.00
printf("Fahrenheit: %.2f\n", $t->fahrenheit); // 212.00
printf("Kelvin: %.2f\n", $t->kelvin); // 373.15
$t->celsius = 0.0;
printf("\nAfter setting to 0C:\n");
printf("Fahrenheit: %.2f\n", $t->fahrenheit); // 32.00
// Validation
try {
$t->celsius = -300.0;
} catch (ValueError $e) {
echo "\nCaught: " . $e->getMessage() . "\n";
}
// Asymmetric visibility (public read, private write from inside)
class BankAccount
{
public private(set) float $balance = 0.0;
public function deposit(float $amount): void
{
if ($amount <= 0) throw new ValueError("Deposit must be positive");
$this->balance += $amount; // allowed: same class
}
public function withdraw(float $amount): void
{
if ($amount > $this->balance) throw new RuntimeException("Insufficient funds");
$this->balance -= $amount;
}
}
$account = new BankAccount();
$account->deposit(1000.0);
$account->withdraw(250.0);
printf("\nBalance: %.2f\n", $account->balance); // 750.00
// Cannot write from outside:
try {
$account->balance = 99999.0;
} catch (Error $e) {
echo "Caught: " . $e->getMessage() . "\n";
}
Comments
No comments yet
Be the first to share your thoughts!