thelolcat
thelolcat

Reputation: 11545

Cannot set read-only property

Are there actually read-only properties in PHP and I'm not aware of them? How do I get a public property to be read-only??

I was just playing with ReflectionClass and I got this error message when trying to overwrite a property:

$lol = new ReflectionObject($obj);
$lol->name = 'awawawawa';

Upvotes: 1

Views: 2346

Answers (4)

Kaii
Kaii

Reputation: 20540

From the docs of ReflectionClass:

Properties
name
Name of the class. Read-only, throws ReflectionException in attempt to write.

However, the docs also say

ReflectionClass implements Reflector {
  /* Properties */
  public $ReflectionClass->name;
  ...

It is important to note here, that (even if the documentation looks ReflectionClass is implemented in pure PHP) the ReflectionClass is part of the PHP core, thus implemented in C!

Although the property is documented as being a normal public property, in fact its not!

I'm too lazy to dig into the PHP source code for this, but you will find a special case handling there which protects the public property making it read-only. EDIT: see Mark Bakers answer.

Upvotes: 1

Mark Baker
Mark Baker

Reputation: 212412

From the code of the reflection class:

/* {{{ _reflection_write_property */
static void _reflection_write_property(zval *object, zval *member, zval *value TSRMLS_DC)
{
    if ((Z_TYPE_P(member) == IS_STRING)
        && zend_hash_exists(&Z_OBJCE_P(object)->default_properties, Z_STRVAL_P(member), Z_STRLEN_P(member)+1)
        && ((Z_STRLEN_P(member) == sizeof("name") - 1  && !memcmp(Z_STRVAL_P(member), "name",  sizeof("name")))
            || (Z_STRLEN_P(member) == sizeof("class") - 1 && !memcmp(Z_STRVAL_P(member), "class", sizeof("class")))))
    {
        zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, 
            "Cannot set read-only property %s::$%s", Z_OBJCE_P(object)->name, Z_STRVAL_P(member));
    }
    else
    {
        zend_std_obj_handlers->write_property(object, member, value TSRMLS_CC);     
    }
}
/* }}} */

so basically, it's explicitly forbidding it for the "name" and "class" properties. I can't find any indication that a class property exists though!

Upvotes: 3

phatskat
phatskat

Reputation: 1815

From the PHP Manual Page for ReflectionObject:

Properties

name

    Name of the object's class. Read-only, throws ReflectionException in attempt to write.

http://sk.php.net/manual/en/class.reflectionobject.php

There isn't much on how they do this, but my guess would be that it's explicitly looking out for the writing of the name property and stopping it from happening as it would make the reflection a lie.

You could do something similar yourself:

<?php
class MyReadOnlyJunk
{
    protected // over private, or not defined here at all
        $name = 'My Name';

    public function __set($key, $val)
    {
        if($key == 'name')
            throw new Exception('Cannot has name set!');
    }
}
?>

Upvotes: 1

Niet the Dark Absol
Niet the Dark Absol

Reputation: 324650

PHP docs:

Name of the object's class. Read-only, throws ReflectionException in attempt to write.

I don't see anything in the Properties page about making things read-only, though... I guess possibly prefix them with final, but I don't know if that's allowed since it's only mentioned on methods.

Upvotes: 1

Related Questions