Directly answering your question: No, you cannot mark regular properties as readonly. If you want to set primitive types (except array), that will never change, you should use constants
const QWE = '666';
That doesn't work for objects and arrays. I see two (lets say) "solutions"
Use Getter
private $qwe; public function getQwe() { return $this->qwe; } protected function setQwe($value) { $this->qwe = $value; }I don't like them very much ("Properties define the state, not the behavior, like methods do"). You always get twice as much additional methods as properties and if you have many properties, this will extremely blow up your class. However, it's as far as I can see the only way to implement what you want to achieve.
Trust your users ;) Comment your property and say something like "If you change this value, probably something will break and its your very own fault".
/** * QWE * * This property should be treatened as "readonly". If you change this value * something scary will happen to you. * * @readonly * @var string */ public $qwe = '666';Its not great, but at least you can say "I told you".
Directly answering your question: No, you cannot mark regular properties as readonly. If you want to set primitive types (except array), that will never change, you should use constants
const QWE = '666';
That doesn't work for objects and arrays. I see two (lets say) "solutions"
Use Getter
private $qwe; public function getQwe() { return $this->qwe; } protected function setQwe($value) { $this->qwe = $value; }I don't like them very much ("Properties define the state, not the behavior, like methods do"). You always get twice as much additional methods as properties and if you have many properties, this will extremely blow up your class. However, it's as far as I can see the only way to implement what you want to achieve.
Trust your users ;) Comment your property and say something like "If you change this value, probably something will break and its your very own fault".
/** * QWE * * This property should be treatened as "readonly". If you change this value * something scary will happen to you. * * @readonly * @var string */ public $qwe = '666';Its not great, but at least you can say "I told you".
Readonly properties were introduced in PHP 8.1, but static readonly properties are not supported.
From the RFC:
Readonly static properties are not supported. This is a technical limitation, in that it is not possible to implement readonly static properties non-intrusively. In conjunction with the questionable usefulness of readonly static properties, this is not considered worthwhile at this time.
However you can declare a static function to more or less get the same end result.
public static function getType(): string
{
return 'Duck';
}
After all, the overlap is so big that I struggle to see why they were introduced.
If you want a property to be immutable after assignment, a constant does that, too. That's also why constants being public is fine.
So, I would have found readonly more useful, if I was allowed to always re-assign them from inside the class that defined them. Then they would work like a private property that only has a getter but no setter - which I find convenient. It's the job of the class to manage its state, so I don't see why you shouldn't be allowed to re-assign them from inside when constants already exist.
Care to enlighten me?
You can do it like this:
class Example {
private $__readOnly = 'hello world';
function __get($name) {
if($name === 'readOnly')
return $this->__readOnly;
user_error("Invalid property: " . __CLASS__ . "->$name");
}
function __set($name, $value) {
user_error("Can't set property: " . __CLASS__ . "->$name");
}
}
Only use this when you really need it - it is slower than normal property access. For PHP, it's best to adopt a policy of only using setter methods to change a property from the outside.
Since PHP 8.1 there are implemented native readonly properties
Documentation
You can initialize readonly property only once during the declaration of the property.
class Test {
public readonly string $prop;
public function __construct(string $prop) {
$this->prop = $prop;
}
}
--
class Test {
public function __construct(
public readonly string $prop,
) {}
}
Trying to modify the readonly propety will cause following error:
Error: Cannot modify readonly property Test::$prop
Update PHP 8.2
Since PHP 8.2 you are able to define as readonly a whole class.
readonly class Test {
public string $prop;
public function __construct(string $prop) {
$this->prop = $prop;
}
}