PHP Readonly Properties?

Viewed 54611

In using PHP's DOM classes (DOMNode, DOMEElement, etc) I have noticed that they possess truly readonly properties. For example, I can read the $nodeName property of a DOMNode, but I cannot write to it (if I do PHP throws a fatal error).

How can I create readonly properties of my own in PHP?

7 Answers

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

I see you have already got your answer but for the ones who still are looking:

Just declare all "readonly" variables as private or protected and use the magic method __get() like this:

/**
 * This is used to fetch readonly variables, you can not read the registry
 * instance reference through here.
 * 
 * @param string $var
 * @return bool|string|array
 */
public function __get($var)
{
    return ($var != "instance" && isset($this->$var)) ? $this->$var : false;
}

As you can see I have also protected the $this->instance variable as this method will allow users to read all declared variabled. To block several variables use an array with in_array().

Class PropertyExample {

        private $m_value;

        public function Value() {
            $args = func_get_args();
            return $this->getSet($this->m_value, $args);
        }

        protected function _getSet(&$property, $args){
            switch (sizeOf($args)){
                case 0:
                    return $property;
                case 1:
                    $property = $args[0];
                    break;  
                default:
                    $backtrace = debug_backtrace();
                    throw new Exception($backtrace[2]['function'] . ' accepts either 0 or 1 parameters');
            }
        }


}

This is how I deal with getting/setting my properties, if you want to make Value() readonly ... then you simply just have it do the following instead:

    return $this->m_value;

Where as the function Value() right now would either get or set.

Related