PHP只读属性?

在使用PHP的DOM类(DOMNode,DOMEElement等)时,我注意到它们拥有真正的只读属性。 例如,我可以读取DOMNode的$ nodeName属性,但是我不能写入它(如果我做PHP会引发致命错误)。

我如何在PHP中创build自己的只读属性?

你可以这样做:

 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"); } } 

只有在真正需要时才使用它 – 比普通的属性访问慢。 对于PHP,最好采用只使用setter方法从外部改变属性的策略。

但是仅使用__get()公开的私有属性对枚举对象的成员的函数不可见 – 例如,json_encode()。

我经常使用json_encode()将PHP对象传递给Javascript,因为它似乎是一个很好的方法,可以通过从数据库填充大量数据来传递复杂结构。 我必须在这些对象中使​​用公有属性,以便将这些数据填充到使用它的Javascript中,但是这意味着这些属性必须是公共的(因此存在另一个程序员不在相同波长上的风险自己在一个糟糕的夜晚之后)可能会直接修改它们)。 如果我把它们设置为private并且使用__get()和__set(),那么json_encode()就不会看到它们。

拥有“只读”辅助function关键字不是很好吗?

我看到你已经得到了你的答案,但对于那些仍在寻找的人来说:

只需将所有“只读”variables声明为private或protected,并使用如下所示的魔术方法__get():

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

正如你所看到的,我也保护了$ this-> instancevariables,因为这个方法将允许用户读取所有声明的variables。 要阻塞多个variables,请使用带有in_array()的数组。

这里有一种方法可以从外部渲染你的类的所有属性read_only,inheritance类有写入权限;-)。

 class Test { protected $foo; protected $bar; public function __construct($foo, $bar) { $this->foo = $foo; $this->bar = $bar; } /** * All property accessible from outside but readonly * if property does not exist return null * * @param string $name * * @return mixed|null */ public function __get ($name) { return $this->$name ?? null; } /** * __set trap, property not writeable * * @param string $name * @param mixed $value * * @return mixed */ function __set ($name, $value) { return $value; } } 

在php7中testing

对于那些寻找一种暴露你的私有/受保护的属性序列化的方法,如果你select使用getter方法使它们只读,这里是一个这样做的方法(@Matt:为json作为例子):

 interface json_serialize { public function json_encode( $asJson = true ); public function json_decode( $value ); } class test implements json_serialize { public $obj = null; protected $num = 123; protected $string = 'string'; protected $vars = array( 'array', 'array' ); // getter public function __get( $name ) { return( $this->$name ); } // json_decode public function json_encode( $asJson = true ) { $result = array(); foreach( $this as $key => $value ) if( is_object( $value ) ) { if( $value instanceof json_serialize ) $result[$key] = $value->json_encode( false ); else trigger_error( 'Object not encoded: ' . get_class( $this ).'::'.$key, E_USER_WARNING ); } else $result[$key] = $value; return( $asJson ? json_encode( $result ) : $result ); } // json_encode public function json_decode( $value ) { $json = json_decode( $value, true ); foreach( $json as $key => $value ) { // recursively loop through each variable reset them } } } $test = new test(); $test->obj = new test(); echo $test->string; echo $test->json_encode(); 
 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'); } } } 

这是我如何处理获取/设置我的属性,如果你想使Value()只读…那么你只需要它做下面的代替:

  return $this->m_value; 

现在函数Value()现在可以获取或设置。