2010-08-30 5 views
10

C'è un modo per rendere una proprietà di sola lettura di un oggetto in PHP? Ho un oggetto con un paio di matrici in esso. Voglio accedere loro come ho normalmente una matriceproprietà di sola lettura in PHP?

echo $objObject->arrArray[0]; 

Ma io non voglio essere in grado di scrivere a quei array dopo che sono stati costruiti. Ci si sente come una valle di lacrime per la costruzione di una variabile locale:

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

E comunque, mentre mantiene la matrice nell'oggetto incontaminata, non mi impedisce di ri-scrittura della variabile di matrice locale.

risposta

25

Bene, la domanda è: da dove vuoi impedire di scrivere?

Il primo passo è fare la matrice protetto o privato impedisce la scrittura al di fuori del campo di applicazione oggetto:

protected $arrArray = array(); 

Se da "fuori" della matrice, un getter ti farà bene. O:

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

E accedervi come

$array = $obj->getArray(); 

o

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

E accedervi piace:

$array = $obj->arrArray; 

Si noti che non restituiscono i riferimenti. Quindi non è possibile modificare la matrice originale al di fuori dell'ambito dell'oggetto. È possibile modificare la matrice stessa ...

Se è davvero necessario un array completamente immutabile, è possibile utilizzare un oggetto utilizzando ArrayAccess ...

Oppure, si potrebbe semplicemente estendere ArrayObject e sovrascrivere tutti i metodi di scrittura:

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'); 
    } 
} 

Quindi, è sufficiente fare $this->arrArray un'istanza dell'oggetto:

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

Sostiene ancora più serie come usi:

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

Ma se si tenta di scrive ad esso, si otterrà una LogicException ...

Oh, ma rendersi conto che, se avete bisogno di scrivere ad esso, tutto quello che dovete fare (all'interno dell'oggetto) è fare:

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

Se voglio avere la mia matrice immutabile caricare se stesso con i dati sulla creazione sovrascriverei la funzione __construct, chiamare il costruttore genitore, ma come posso impostare cosa contiene l'oggetto? –

+0

Ottima risposta! Ma si noti che un array può contenere oggetti: Ogni oggetto viene restituito come riferimento e può essere cambiato, anche con la classe immutabile: '$ a = new ImmutableArrayObject ((oggetto) [ 'foo' => 'bar']); $ b = $ a [0]; $ b-> foo = 'changed'; ' – Philipp

3

Se si utilizza PHP 5+, è possibile farlo con i metodi __set() e __get().

Devi definire come funzionano, ma dovrebbe fare proprio questo.

Modificare un esempio sarebbe come questo.

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

Questo potrebbe non essere il modo "migliore" di farlo ma sarà funzionare a seconda di cosa avete bisogno

+3

Boss: "mi avevi detto che finito il tuo algoritmo" Cliente: "Ho fatto capo, qual è il problema" Boss: "non funziona" Cliente: "funziona a seconda di ciò che è necessario" – Chris

+1

@ Chris perché è il cliente prendere ordini dal capo? Lol. –

4

Se definito, le funzioni magiche __get() e __set() sarà chiamato ogni volta che un non-esistente o si accede a una proprietà privata. Questo può essere usato per creare metodi "get" e "set" per proprietà private, e per esempio renderli di sola lettura o manipolare i dati quando vengono memorizzati o recuperati in esso.

Per esempio:

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 

Vedere anche il manual page for overloading in PHP.

+3

Suggerirei di lanciare un'eccezione in 'set' se non si consente di impostare una determinata variabile. La ragione è che altrimenti può essere abbastanza confuso quando qualcuno ha bisogno di fare qualcosa, e non funziona. "Ma ho impostato quell'array per includere questa variabile.Il compito ha esito positivo, quindi perché * # @ $ non funziona?" ... – ircmaxell

+0

@ircmaxell: buon punto ... – Frxstrem

0

nella classe, fare questo:

private $array; 

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

poi basta impostare come questo:

$obj->set_array($new_array);