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的回答。