PHP Readonly Properties?
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.
What is the benefit of readonly in PHP 8.1?
readonly
properties allow you to create immutable objects, or at the very least immutable properties.
That way you can be sure that a value won't be changed by accident after being initialized, throughout the object's life.
It's a very similar concept to constants (set via const
or define
), albeit with two important differences:
- constants need to be defined on "compilation" time, whereas
readonly
properties will be set during runtime, usually during on object instantiation (so multiple instances will be able to hold different values*) - as opposed to constants, that live in the global scope, and in case of class constants their value is tied to the class and not to the instance.
You could achieve the same with a private property only accessible via a getter. E.g., in "the olden days":
class Foo {
private DateTimeImmutable $createAt;
public function __construct() {
$this->createdAt = new DateTimeImmutable();
}
public function getCreatedAt(): DateTimeImmutable
{
return $this->createdAt;
}
}
$f = new Foo();
echo $f->getCreatedAt()->format('Y-m-d H:i:s');
The only problem with this is that it requires a lot of boilerplate code.
With PHP 8.1. the same could be achieved by doing:
class Foo
{
public function __construct(
public readonly DateTimeImmutable $createdAt = new DateTimeImmutable()
)
{ }
}
$f = new Foo();
echo $f->createdAt->format('Y-m-d H:i:s')
PHP public readonly properties vs private field with getter
One advantage of the "old" way is that you can choose different access levels for the getter and setter, whereas a readonly
field has only a single access level. E.g. when you want your setter to be protected
.
Another advantage of using getters is that it allows you to change the implementation without changing the class interface.
PHP Readonly Properties or Constants?
Difference in write
One big difference is that you can't set class constants dynamically
at runtime, which you can do with readonly properties (from the
constructor).
Difference in read
There's also a big difference in how you access the two. Unless the
property is static, you will need to have an instance (and all
instances can have different values), while constants can always be
access without an instance.
Props to M. Eriksson
read-only properties in PHP?
Well, the question is where do you want to prevent writing from?
The first step is making the array protected or private to prevent writing from outside of the object scope:
protected $arrArray = array();
If from "outside" of the array, a GETTER will do you fine. Either:
public function getArray() { return $this->arrArray; }
And accessing it like
$array = $obj->getArray();
or
public function __get($name) {
return isset($this->$name) ? $this->$name : null;
}
And accessing it like:
$array = $obj->arrArray;
Notice that they don't return references. So you cannot change the original array from outside the scope of the object. You can change the array itself...
If you really need a fully immutable array, you could use a Object using ArrayAccess
...
Or, you could simply extend ArrayObject
and overwrite all of the writing methods:
class ImmutableArrayObject extends ArrayObject {
public function append($value) {
throw new LogicException('Attempting to write to an immutable array');
}
public function exchangeArray($input) {
throw new LogicException('Attempting to write to an immutable array');
}
public function offsetSet($index, $newval) {
throw new LogicException('Attempting to write to an immutable array');
}
public function offsetUnset($index) {
throw new LogicException('Attempting to write to an immutable array');
}
}
Then, simply make $this->arrArray
an instance of the object:
public function __construct(array $input) {
$this->arrArray = new ImmutableArrayObject($input);
}
It still supports most array like usages:
count($this->arrArray);
echo $this->arrArray[0];
foreach ($this->arrArray as $key => $value) {}
But if you try to write to it, you'll get a LogicException
...
Oh, but realize that if you need to write to it, all you need to do (within the object) is do:
$newArray = $this->arrArray->getArrayCopy();
//Edit array here
$this->arrArray = new ImmutableArrayObject($newArray);
How to implement a read-only member variable in PHP?
I suppose a solution, for class properties, would be to :
- not define a property with the name that interests you
- use the magic
__get
method to access that property, using the "fake" name - define the
__set
method so it throws an exception when trying to set that property. - See Overloading, for more informations on magic methods.
For variables, I don't think it's possible to have a read-only variable for which PHP will throw an exception when you're trying to write to it.
For instance, consider this little class :
class MyClass {
protected $_data = array(
'myVar' => 'test'
);
public function __get($name) {
if (isset($this->_data[$name])) {
return $this->_data[$name];
} else {
// non-existant property
// => up to you to decide what to do
}
}
public function __set($name, $value) {
if ($name === 'myVar') {
throw new Exception("not allowed : $name");
} else {
// => up to you to decide what to do
}
}
}
Instanciating the class and trying to read the property :
$a = new MyClass();
echo $a->myVar . '<br />';
Will get you the expected output :
test
While trying to write to the property :
$a->myVar = 10;
Will get you an Exception :
Exception: not allowed : myVar in /.../temp.php on line 19
Related Topics
How to Convert Object into String in PHP
PHP & MySQL: When Exactly to Use HTMLentities
Laravel - How to Get Current User in Appserviceprovider
PHP - Time Remaining Until Specific Time from Current Time of Page Load
How to Set Session Timeout in Laravel
Syntax Error, Unexpected T_Encapsed_And_Whitespace, Expecting T_String or T_Variable or T_Num_String
Setting Post Variable Without Using Form
How to Get Array Key from Corresponding Array Value
How to Take a Photo and Send to Http Post Request with Android
Inserting Now() into Database with Codeigniter's Active Record
Redirecting Wordpress's Login/Register Page to a Custom Login/Registration Page
How to Get Values Inside <![Cdata[Values]] > Using PHP Dom
How to Include File Outside Document Root
What Is a Good Method to Sanitize the Whole $_Post Array in PHP
Is There an Equivalent in C++ of PHP's Explode() Function
How to Convert Array to a String Using Methods Other Than JSON