【问题标题】:read-only properties in PHP?PHP中的只读属性?
【发布时间】:2010-08-30 13:28:34
【问题描述】:

有没有办法在 PHP 中创建一个对象的只读属性?我有一个对象,里面有几个数组。我想像通常访问数组一样访问它们

echo $objObject->arrArray[0];

但我不想在它们被构造后写入这些数组。感觉像 PITA 构造一个局部变量:

$arrArray = $objObject->getArray1();
echo $arrArray[0];

无论如何,虽然它使对象中的数组保持原始状态,但并不妨碍我重写本地数组变量。

【问题讨论】:

    标签: php oop readonly


    【解决方案1】:

    如果您使用的是 PHP 5+,您可以使用 __set() 和 __get() 方法。

    您必须定义它们的工作方式,但应该这样做。

    编辑一个例子是这样的。

    class Example {
        private $var;
        public function __get($v) {
            if (is_array($v)) {
                foreach () {
                    // handle it here
                }
            } else {
                return $this->$v;
            }
        }
    }
    

    这可能不是“最好”的方法,但它会根据您的需要起作用

    【讨论】:

    • 老板:“我以为你说你完成了你的算法”客户:“我做了老板,有什么问题”老板:“它不起作用”客户:“它取决于你需要什么"
    • @Chris 客户为什么要听老板的命令?大声笑。
    【解决方案2】:

    好吧,问题是你想从哪里阻止写入?

    第一步是使数组受保护或私有,以防止从对象范围之外写入:

    protected $arrArray = array();
    

    如果来自数组的“外部”,一个 GETTER 就可以了。要么:

    public function getArray() { return $this->arrArray; }
    

    并像访问它一样

    $array = $obj->getArray();
    

    public function __get($name) {
        return isset($this->$name) ? $this->$name : null;
    }
    

    然后像这样访问它:

    $array = $obj->arrArray;
    

    请注意,它们不返回引用。因此,您不能从对象范围之外更改原始数组。您可以更改数组本身...

    如果你真的需要一个完全不可变的数组,你可以使用 ArrayAccess 的 Object ...

    或者,您可以简单地扩展 ArrayObject 并覆盖所有写入方法:

    class ImmutableArrayObject extends ArrayObject {
        public function append($value) {
            throw new LogicException('Attempting to write to an immutable array');
        }
        public function exchangeArray($input) {
            throw new LogicException('Attempting to write to an immutable array');
        }
        public function offsetSet($index, $newval) {
            throw new LogicException('Attempting to write to an immutable array');
        }
        public function offsetUnset($index) {
            throw new LogicException('Attempting to write to an immutable array');
        }
    }
    

    然后,只需将$this->arrArray 设为对象的实例:

    public function __construct(array $input) {
        $this->arrArray = new ImmutableArrayObject($input);
    }
    

    它仍然支持大多数类似数组的用法:

    count($this->arrArray);
    echo $this->arrArray[0];
    foreach ($this->arrArray as $key => $value) {}
    

    但如果你尝试写信给它,你会得到一个LogicException...

    哦,但要意识到,如果你需要写它,你需要做的(在对象内)就是做:

    $newArray = $this->arrArray->getArrayCopy();
    //Edit array here
    $this->arrArray = new ImmutableArrayObject($newArray);
    

    【讨论】:

    • 如果我想让我的不可变数组在创建时加载自己的数据,我会覆盖 __construct 函数,调用父构造函数,但是如何设置对象包含的内容?
    • 很好的答案!但请注意,数组可以包含对象:每个对象都作为引用返回并且可以更改,即使是不可变类:$a = new ImmutableArrayObject( (object) ['foo' => 'bar'] ); $b = $a[0]; $b->foo = 'changed';
    【解决方案3】:

    如果已定义,那么只要访问不存在或私有的属性,就会调用魔术函数 __get()__set()。这可用于为私有属性创建“get”和“set”方法,例如将它们设为只读或在其中存储或检索数据时对其进行操作。

    例如:

    class Foo
    {
      private $bar = 0;
      public $baz = 4; // Public properties will not be affected by __get() or __set()
      public function __get($name)
      {
        if($name == 'bar')
          return $this->bar;
        else
          return null;
      }
      public function __set($name, $value)
      {
        // ignore, since Foo::bar is read-only
      }
    }
    
    $myobj = new Foo();
    echo $foo->bar; // Output is "0"
    $foo->bar = 5;
    echo $foo->bar; // Output is still "0", since the variable is read-only
    

    另请参阅manual page for overloading in PHP

    【讨论】:

    • 如果您不允许设置特定变量,我建议在 set 中抛出异常。原因是,否则当新人需要做某事而它不起作用时,它可能会很混乱。 “但是我将该数组设置为包含此变量。分配成功,那么为什么 *#@$ 不起作用?”...
    【解决方案4】:

    在课堂上,这样做:

    private $array;
    
    function set_array($value) {
        $this->array = $value;
    }
    

    那么你就这样设置:

    $obj->set_array($new_array);
    

    【讨论】:

      【解决方案5】:

      对于 PHP 8.1+,您可以使用只读属性:

      class Test
      {
          public readonly array $arrArray;
      
          public function __construct()
          {
                $this->arrArray = [1, 2, 3];
          } 
      }
      
      $test = new Test();
      var_dump($test->arrArray); // OK
      $test->arrArray = [4, 5, 6]; // Error
      

      【讨论】:

        猜你喜欢
        • 2022-07-12
        • 2010-11-22
        • 1970-01-01
        • 2014-11-20
        • 2023-01-25
        • 2014-08-22
        • 2015-02-01
        • 2011-01-28
        相关资源
        最近更新 更多