Свойства PHP только для чтения? - PullRequest
58 голосов
/ 31 декабря 2008

При использовании PHP-классов DOM (DOMNode, DOMEElement и т. Д.) Я заметил, что они обладают действительно свойствами только для чтения. Например, я могу прочитать свойство $ nodeName DOMNode, но не могу записать в него (если я это сделаю, PHP выдаст фатальную ошибку).

Как я могу создать свои собственные свойства только для чтения в PHP?

Ответы [ 6 ]

40 голосов
/ 31 декабря 2008

Вы можете сделать это так:

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 лучше всего принять политику использования только методов установки для изменения свойства извне.

12 голосов
/ 04 декабря 2009

Но закрытые свойства, предоставляемые только с помощью __get (), не видны функциям, перечисляющим членов объекта - например, json_encode ().

Я регулярно передаю объекты PHP в Javascript с помощью json_encode (), так как это кажется хорошим способом передачи сложных структур с большим количеством данных, заполняемых из базы данных. Я должен использовать общедоступные свойства в этих объектах, чтобы эти данные заполнялись в Javascript, который их использует, но это означает, что эти свойства должны быть общедоступными (и, следовательно, существует риск того, что другой программист не на той же длине волны (или, возможно, сам после плохой ночи) может изменить их напрямую). Если я сделаю их приватными и использую __get () и __set (), то json_encode () их не увидит.

Не было бы неплохо иметь ключевое слово доступности "только для чтения"?

5 голосов
/ 05 августа 2009

Я вижу, вы уже получили свой ответ, но для тех, кто все еще ищет:

Просто объявите все переменные «только для чтения» как закрытые или защищенные и используйте магический метод __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, поскольку этот метод позволит пользователям читать все объявленные переменныеd. Чтобы заблокировать несколько переменных, используйте массив с in_array ().

2 голосов
/ 20 января 2017

Вот способ визуализировать все свойства вашего класса только для чтения извне, унаследованный класс имеет доступ для записи; -).

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

0 голосов
/ 09 декабря 2011

Для тех, кто ищет способ раскрытия ваших личных / защищенных свойств для сериализации, если вы решите использовать метод 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();
0 голосов
/ 26 апреля 2009
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 () сейчас либо получит, либо установит.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...