From PHP 8.1, we've got readonly properties that can not be modified after it has been initialized. What a great addition that helps us to create immutable objects much more easily.
Prior to this, if we wanted to create an immutable object, we had to make class properties private/protected then expose those property with public getter method.
<?php
class Person {
private string $name;
public function __construct(string $name)
{
$this->name = $name;
}
public function getName(): string
{
return $this->name;
}
}
$person = new Person("Alice");
// we can read $name
echo $person->getName();
// but we can't modify $name
$person->name = 'Bob';
// Uncaught Error: Cannot access private property Person::$name
This is very common approach when dealing with value objects or DTO, since they are mostly immutable.
But from PHP 8.1, we can declare properties as readonly.
Readonly properties can only be initialized once, and only from the scope where they have been declared, which means insides the class definition.
<?php
class Person {
public readonly string $name;
public function __construct(string $name)
{
$this->name = $name;
}
}
$person = new Person("Alice");
// we can read $name
echo $person->name;
// but we can't modify $name
$person->name = 'Bob';
// Uncaught Error: Cannot modify readonly property Person::$name
Rules & Restrictions for readonly properties:
class Person {
public readonly string $name;
public function __construct(string $name)
{
$this->name = $name;
$this->name = "Something else"; // this won't work
}
}
class Person {
public readonly string $name;
public readonly $job; // invalid
public readonly mixed $job; // works
}
class Person {
public readonly string $name = "Bob"; // invalid
}
class Person {
public function __construct (
public readonly string $name = "Bob"
) {}
}
$person1 = new Person("Alice");
$person2 = new Person();
echo $person1->name;
// Alice
echo $person2->name;
// Bob
class Person {
public string $name;
}
class Employee extends Person {
// not allowed
public readonly string $name;
}
trait Student {
public string $name;
}
trait Singer {
// not allowed, readonly mismatchpublic readonly string $name;
}
class Performer {
use Student;
use Singer;
}
Write comment about this article: