PHP 8: Modern PHP Development · Object-Oriented PHP 8
Classes, Constructor Promotion and readonly
Write compact, immutable classes with promoted constructor properties and readonly.
Constructor property promotion (8.0) declares and assigns properties directly in the constructor signature. readonly properties (8.1) can be initialized once (from inside the class scope) and never changed; readonly classes (8.2) make all properties readonly. Together they make value objects and DTOs short and safe. To "modify" an immutable object, return a modified clone ("wither" methods); 8.3 allows re-initializing readonly properties during __clone, and 8.5 adds clone($obj, [...]) with property overrides.
<?php
final readonly class Money
{
public function __construct(
public int $amount, // minor units (cents)
public string $currency,
) {
if ($amount < 0) {
throw new InvalidArgumentException('Amount cannot be negative');
}
}
public function add(Money $other): self
{
if ($other->currency !== $this->currency) {
throw new LogicException('Currency mismatch');
}
return new self($this->amount + $other->amount, $this->currency);
}
}
$total = (new Money(1000, 'USD'))->add(new Money(250, 'USD'));
// $total->amount = 5; // Error: Cannot modify readonly property
Common pitfalls
- readonly properties must be typed and cannot have default values (except via promotion in the constructor).
- readonly is shallow: a readonly property holding a mutable object can still have that object mutated.
- Storing money in floats — use integers in minor units or a decimal library.
Key points
- Promotion removes boilerplate
- readonly properties/classes enforce immutability
- Return new instances instead of mutating value objects
Further reading: PHP manual: readonly properties
Practice questions
Is a readonly property holding an array of objects deeply immutable?
Answer
No. readonly prevents reassigning the property, but objects inside can still be mutated. Deep immutability requires immutable objects all the way down.
How do you change one field of a readonly value object?
Answer
Create a new instance with the changed value (a withX() method returning new self(...) or a modified clone). PHP 8.5's clone($obj, ['x' => 1]) makes this concise.
Open in the app to mark lessons complete, take notes and track your progress.