PHP Readonly Properties

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



Leave a reply



Submit