PHP只读属性?

时间:2008-12-31 03:16:49

标签: php programming-languages

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

如何在PHP中创建自己的readonly属性?

7 个答案:

答案 0 :(得分:40)

你可以这样做:

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方法从外部更改属性的策略。

答案 1 :(得分:12)

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

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

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

答案 2 :(得分:5)

我知道你已经得到了答案,但对于那些仍然在寻找的人:

只需将所有“readonly”变量声明为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->实例变量,因为此方法将允许用户读取所有声明的变量。要阻止多个变量,请使用带有in_array()的数组。

答案 3 :(得分:2)

这是一种从外部呈现类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中测试

答案 4 :(得分:2)

自 PHP 8.1 起,实现了原生只读属性

RFC:https://wiki.php.net/rfc/readonly_properties_v2

只读属性在声明时只能初始化一次。

class Test {
    public readonly string $prop;

    public function __construct(string $prop) {
        $this->prop = $prop;
    }
}

--

class Test {
    public function __construct(
        public readonly string $prop,
    ) {}
}

尝试修改只读属性会导致如下错误:

Error: Cannot modify readonly property Test::$prop

答案 5 :(得分:0)

对于那些寻找暴露私有/受保护属性以进行序列化的方法的人来说,如果你选择使用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();

答案 6 :(得分:-1)

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()可以获取或设置。