whatwg spec php programming-languages

spec - ¿Propiedades de PHP Readonly?



html5 whatwg (6)

Al usar las clases DOM de PHP (DOMNode, DOMEElement, etc.) me he dado cuenta de que poseen propiedades verdaderamente de solo lectura. Por ejemplo, puedo leer la propiedad $ nodeName de un DOMNode, pero no puedo escribir en él (si lo hago, PHP arroja un error fatal).

¿Cómo puedo crear propiedades de solo lectura en PHP?


Puedes hacerlo así:

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

Solo use esto cuando realmente lo necesite; es más lento que el acceso normal a la propiedad. Para PHP, lo mejor es adoptar una política de usar solo métodos setter para cambiar una propiedad desde el exterior.


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

Así es como me ocupo de obtener / configurar mis propiedades, si quieres hacer que Value () sea solo de lectura ... entonces simplemente tienes que hacer lo siguiente en su lugar:

return $this->m_value;

Donde como la función Valor () en este momento se obtendría o establecería.


Veo que ya tienes tu respuesta, pero para los que todavía están buscando:

Simplemente declare todas las variables de "solo lectura" como privadas o protegidas y use el método mágico __get () como este:

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

Como puede ver, también he protegido la variable de instancia $ this->, ya que este método permitirá a los usuarios leer todas las variables declaradas. Para bloquear varias variables utiliza una matriz con in_array ().


Pero las propiedades privadas expuestas solo con __get () no son visibles para las funciones que enumeran los miembros de un objeto - json_encode () por ejemplo.

Regularmente paso objetos PHP a Javascript usando json_encode () ya que parece ser una buena forma de pasar estructuras complejas con muchos datos poblados de una base de datos. Tengo que usar propiedades públicas en estos objetos para que estos datos se lleven al Javascript que los usa, pero esto significa que esas propiedades tienen que ser públicas (y por lo tanto corren el riesgo de que otro programador no esté en la misma longitud de onda (o probablemente) yo mismo después de una mala noche) podría modificarlos directamente). Si los hago privados y uso __get () y __set (), entonces json_encode () no los ve.

¿No sería bueno tener una palabra clave de accesibilidad de "solo lectura"?


Para aquellos que buscan una manera de exponer sus propiedades privadas / protegidas para la serialización, si eligen utilizar un método getter para hacerlas de solo lectura, aquí hay una forma de hacerlo (@Matt: para json como ejemplo):

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();


Aquí hay una manera de mostrar todas las propiedades de su clase read_only desde el exterior, class heredado tiene acceso de escritura ;-).

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

probado en php7