2010-08-30 2 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, вызвал родительский конструктор, но как установить, что содержит этот объект? –

+0

Очень хороший ответ! Но заметьте, что массив может содержать объекты: каждый объект возвращается как ссылка и может быть изменен даже с вашим неизменяемым классом: '$ a = new ImmutableArrayObject ((object) ['foo' => 'bar']); $ b = $ a [0]; $ b-> foo = 'changed'; ' – Philipp

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

+1

@ Крис, почему клиент принимает заказы от босса? Лол. –

4

Если определено, магические функции __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

+0

@ircmaxell: хорошая точка ... – Frxstrem

0

в классе, сделайте следующее:

private $array; 

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

тогда вы просто установить, как это:

$obj->set_array($new_array); 
Смежные вопросы