Используя PHP-классы DOM (DOMNode, DOMEElement и т. Д.), Я заметил, что они обладают действительно свойствами readonly. Например, я могу прочитать свойство $ nodeName для DOMNode, но я не могу написать ему (если я делаю PHP, генерирует фатальную ошибку).
Как я могу создавать собственные свойства readonly в PHP?
Вы можете сделать это следующим образом:
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 (), например.
Я регулярно передаю объекты PHP в Javascript, используя json_encode (), поскольку это, кажется, хороший способ передать сложные структуры с большим количеством данных, заполненных из базы данных. Я должен использовать общедоступные свойства в этих объектах, чтобы эти данные были заполнены в Javascript, который его использует, но это означает, что эти свойства должны быть общедоступными (и, следовательно, рискует, что другой программист не на той же длине волны (или, возможно, сам после плохой ночи) может изменить их напрямую). Если я сделаю их приватными и использую __get () и __set (), то json_encode () их не видит.
Было бы неплохо иметь ключевое слово доступности «только для чтения»?
Я вижу, вы уже получили свой ответ, но для тех, кто все еще смотрит:
Просто объявляйте все переменные «readonly» частным или защищенным и используйте магический метод __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-> instance, поскольку этот метод позволит пользователям читать все объявленные переменные. Чтобы заблокировать несколько переменных, используйте массив с параметром in_array ().
Вот способ визуализации всего свойства вашего класса read_only извне, унаследованный класс имеет доступ на запись ;-).
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
Для тех, кто ищет способ разоблачения ваших приватных / защищенных свойств для сериализации, если вы решите использовать метод getter, чтобы сделать их readonly, вот как это сделать (@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 () readonly …, тогда вы просто просто выполните следующие действия:
return $this->m_value;
Где, как функция Value () прямо сейчас, будет либо получен, либо задан.