There is currently no way to make a property readable to everyone and writeable only to the containing object, with PHP's visibility specifiers allowing all or nothing: a scope can either both read and write, or do neither. While _
_get
and _
_set
exist, these do not actually allow control of the same property, merely only exposing a separate property, and they are only usable for undeclared properties, which cannot be reflected and are not performant.
Because of this, getter and setter functions to control the ability to write to properties are common. This requires developers to write boilerplate code, even if assisted by IDEs, and is not as performant as a raw property.
To deal with this, a new modifier keyword is introduced for properties, readonly
. It allows the property to be read from the normal scope of its visibility, so a public readonly
property is readable from the public scope, i.e. anywhere. However, it can only being written to from the next most restrictive scope, so a public readonly
property is writeable from the protected scope, and a protected readonly
property only from the private scope.
Due to implementation difficulties, this doesn't support for static properties for now. This may yet change, however. Properties cannot be both private
and readonly
, since there is no more restrictive scope than private
.
This keyword's behaviour should not be confused with that of C#'s readonly
specifier, which makes a property writeable only once, from a class's constructor. While the possible confusion this could produce is unfortunate, I could not think of a better name after much discussion. I don't think this precludes inclusion of a feature similar to that of C# under another name as there are other possible names for that feature, such as immutable
or final
. It's also worth noting that readonly
is already used for some classes (such as the DOM) in the PHP manual.
Let's take this class:
class Stack { public readonly $size = 0; private $elements = []; public function push($elem) { $this->size++; $this->elements[] = $elem; } public function pop() { $this->size--; return array_pop($this->elements); } }
If we were to create an instance of this class and try to change size
we would get an error, as we cannot write to the public readonly
property from the public scope:
Fatal error: Cannot write to readonly public property Stack::$size in example.php on line 1
However, calling push
would not error, as it changes $size
from inside the class, which falls within the protected scope.
readonly
is now a reserved word, so it can't be used as a class, function, method or constant name.
It is possible that this could be changed so class, constant and function names are unaffected, but due to syntactical ambiguity, this couldn't be allowed for methods.
This is proposed for the next major version of PHP, currently PHP 7.
Properties in interfaces are currently not supported. If they were later to be supported (perhaps with getters/setters being added), readonly
could be used to avoid compelling implementing classes from making a property writeable, but not preventing them from expanding the interface to do so, e.g.:
interface Point { readonly $x, $y; } class ImmutablePoint implements Point { public readonly $x, $y; ... } class MutablePoint implements Point { public $x, $y; ... }
Reflection has been updated, with the method ReflectionProperty::isReadonly()
being added.
The RFC's compatibility with opcache is yet to be verified. It merely adds a new ZEND_ACC_*
flag so support shouldn't be a problem, however.
This does not affect methods or static properties.
As this is a language change, a 2/3 majority is required.
A pull request against master is here: https://github.com/php/php-src/pull/879
It contains a full set of twelve different tests. There are no known issues at present.
A pull request for the language specification is here: https://github.com/php/php-langspec/pull/86
It currently lacks tests.
After the project is implemented, this section should contain
Keep this updated with features that were discussed on the mail lists.
* v0.1.1 - Added Future Scope * v0.1 - Creatd