2010-08-30 89 views
10

有沒有辦法在PHP中創建對象的只讀屬性?我有一個對象,裏面有一對數組。我想訪問他們,因爲我通常會陣列PHP中的只讀屬性?

echo $objObject->arrArray[0]; 

但我不希望能夠寫入這些數組後,他們構建。這感覺就像一個PITA構建一個局部變量:

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

而且不管怎麼說,雖然它一直在數組中的對象質樸,它並不能阻止我重新寫本地數組變量。

回答

25

那麼,問題是你想防止寫作從哪裏?

的第一步是使陣列保護或私人爲防止寫入從對象範圍之外:

protected $arrArray = array(); 

如果從陣列的「外部」的吸氣將你的罰款。或者:

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

和訪問它像

$array = $obj->getArray(); 

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

和訪問它想:

$array = $obj->arrArray; 

注意,它們不返回引用。所以你不能從對象範圍之外改變原始數組。你可以改變陣列本身...

如果你真的需要一個完全不可改變的數組,你可以使用一個對象使用ArrayAccess ...

或者,你可以簡單地擴展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); 
+0

如果我想讓我的不可變陣列用創建數據加載本身我會覆蓋__construct函數,調用父構造函數,但是如何設置對象包含的內容? – 2012-06-29 18:39:52

+0

非常好的答案!但是請注意,一個數組可以包含對象:每個對象都作爲引用返回,並且可以更改,即使使用不可變的類:'$ a = new ImmutableArrayObject((object)['foo'=>'bar']); $ b = $ a [0]; $ b-> foo ='改變';' – Philipp 2017-04-23 18:44:45

3

如果您使用PHP 5 +,可以使用__set()和__get()方法執行此操作。

你必須定義它們如何工作,但應該這樣做。

編輯一個例子就是這樣。

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

這可能不是這樣做的「最好」的方式,但它會根據你的需要

+3

老闆:「我還以爲你說你完成了你的算法」客戶: 「我做老闆,有什麼問題」老闆:「它不起作用」客戶:「它取決於你需要什麼」 – Chris 2010-08-30 13:36:55

+1

@Chris客戶爲什麼要接受老闆的命令?大聲笑。 – 2017-05-09 21:32:32

4

如果定義的工作,神奇的功能__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

+3

如果你不允許設置特定的變量,我會推薦在'set'中引發一個異常。原因是,否則當有人需要做某件事情時,它可能會相當混亂,而且它不起作用。 「但是我把這個數組設置爲包含這個變量,賦值成功了,爲什麼*#@ $不工作?」... – ircmaxell 2010-08-30 13:54:26

+0

@ircmaxell:好點... – Frxstrem 2010-08-30 14:17:22

0

在課堂上,這樣做:

private $array; 

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

那麼你只需要設置是這樣的:

$obj->set_array($new_array);