2010-08-30 18 views
10

¿Hay alguna manera de hacer una propiedad de solo lectura de un objeto en PHP? Tengo un objeto con un par de matrices en él. Quiero tener acceso a ellos como lo haría normalmente un conjuntopropiedades de solo lectura en PHP?

echo $objObject->arrArray[0]; 

Pero yo no quiero ser capaz de escribir en esas matrices después de que se construyen. Se siente como un PITA para construir una variable local:

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

Y de todos modos, al tiempo que mantiene la matriz en el objeto prístina, no me impide volver a escribir la variable de matriz local.

Respuesta

25

Bueno, la pregunta es ¿de dónde quieres evitar que escriba?

El primer paso es hacer la matriz protegida o privada para impedir la grabación desde fuera del alcance del objeto:

protected $arrArray = array(); 

Si desde el "exterior" de la matriz, un captador le hará bien. O bien:

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

y acceder a ella como

$array = $obj->getArray(); 

o

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

Y para acceder a él le gusta:

$array = $obj->arrArray; 

en cuenta que no devuelven referencias. Por lo tanto, no puede cambiar la matriz original fuera del alcance del objeto. Puede cambiar la matriz en sí ...

Si realmente necesita una matriz completamente inmutable, puede usar un objeto usando ArrayAccess ...

O, simplemente puede extender ArrayObject y sobrescribir todos los métodos de escritura:

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

Luego, basta con hacer $this->arrArray una instancia del objeto:

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

Todavía es compatible con la mayoría matriz como Usos:

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

Pero si intentas escribir en él, obtendrá un LogicException ... Oh

, pero se da cuenta de que si tiene que escribir en él, todo lo que tiene que hacer (dentro del objeto) es hacer:

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

Si yo quiero tener mi matriz Inmutable cargarse con datos sobre la creación me sobrescribir la función __construct, llamar al constructor padre, pero ¿cómo puedo establecer lo que el objeto contiene? –

+0

¡Muy buena respuesta! Pero se dio cuenta de que un array puede contener objetos: Cada objeto se devuelve como una referencia y puede ser cambiado, incluso con su clase inmutable: '$ a = new ImmutableArrayObject ((objeto) [ 'foo' => 'bar']); $ b = $ a [0]; $ b-> foo = 'cambiado'; ' – Philipp

3

Si está utilizando PHP 5+ puede hacerlo con los métodos __set() y __get().

Tienes que definir cómo funcionan, pero deberían hacer justamente esto.

Editar un ejemplo sería así.

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

Esto podría no ser el "mejor" forma de hacerlo, pero que va a trabajar en función de lo que necesita

+3

jefe: "pensé que habías dicho que termine el algoritmo de" Cliente: "Hice jefe, ¿cuál es el problema" Jefe: "no funciona" Cliente: "funciona dependiendo de lo que necesita" – Chris

+1

@ Chris ¿por qué el cliente tomando órdenes del jefe? Lol. –

4

Si se define, las funciones mágicas y __get()__set() se llamará cada vez que un no-existente o se accede a la propiedad privada. Esto se puede usar para crear métodos "get" y "set" para propiedades privadas, y por ejemplo hacer que sean de solo lectura o manipular los datos cuando se almacenan o se recuperan en él.

Por ejemplo:

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 

Véase también la manual page for overloading in PHP.

+3

recomendaría lanzar una excepción en 'set' si no estás permitiendo una variable en particular que desea ajustar. La razón es que de lo contrario puede ser muy confuso cuando alguien nuevo tiene que hacer algo, y que no está funcionando. "Pero me puse esa matriz para incluir esta variable La asignación tiene éxito, ¿por qué el * # @ $ ¿no trabajando.?" ... – ircmaxell

+0

@ircmaxell: buen punto ... – Frxstrem

0

en la clase, hacer esto:

private $array; 

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

continuación, que acaba de establecer la siguiente manera:

$obj->set_array($new_array); 
Cuestiones relacionadas