无法设置只读属性


Cannot set read-only property

PHP中是否真的存在只读属性,而我对此一无所知?如何将公共属性设置为只读??

我只是在玩ReflectionClass,当我试图覆盖一个属性时收到了这个错误消息:

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

来自反射类的代码:

/* {{{ _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);     
    }
}
/* }}} */

所以基本上,它明确禁止"name"answers"class"属性使用它。不过,我找不到任何迹象表明类属性存在!

ReflectionObject:的PHP手册页面

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

关于他们是如何做到这一点的,目前还没有太多信息,但我的猜测是,它明确地注意了name属性的写入,并阻止了它的发生,因为这会使反射成为谎言。

你自己也可以做类似的事情:

<?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!');
    }
}
?>

PHP文档:

对象类的名称。只读,在尝试写入时抛出ReflectionException。

不过,我在Properties页面上看不到任何关于只读的内容。。。我想可能会在它们前面加上final,但我不知道这是否允许,因为它只在方法上提到过。

来自ReflectionClass:的文档

属性
名称
类的名称。只读,在尝试写入时抛出ReflectionException。

然而,文件也说

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

这里需要注意的是,(即使文档看起来ReflectionClass是在纯PHP中实现的)ReflectionClass是PHP核心的一部分,因此在C中实现!

尽管记录该属性为普通公共属性,但事实并非如此!

我懒得深入研究PHP源代码,但你会发现那里有一个特殊的案例处理,可以保护公共属性,使其只读。编辑:参见Mark Bakers的回答。