Свойства только для чтения в PHP?

Есть ли способ сделать свойство только для чтения объекта в PHP? У меня есть объект с парой массивов. Я хочу получить к ним доступ, как обычно, массив

echo $objObject->arrArray[0];

Но я не хочу иметь возможность писать в эти массивы после их создания. Это похоже на PITA для создания локальной переменной:

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

И в любом случае, хотя он сохраняет массив в первозданном виде, он не мешает мне переписать переменную локального массива.

5 ответов

Решение

Ну, вопрос в том, где вы хотите запретить писать?

Первый шаг - сделать массив защищенным или закрытым для предотвращения записи вне области объекта:

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...

Или вы можете просто продлить 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);

Если вы используете PHP 5+, вы можете сделать это с помощью методов __set() и __get().

Вы должны определить, как они работают, но должны сделать именно это.

Редактировать пример будет так:

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

Это может быть не самый лучший способ сделать это, но это будет работать в зависимости от того, что вам нужно

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

Смотрите также страницу руководства по перегрузке в PHP.

Для 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

В классе сделайте это:

private $array;

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

тогда вы просто установите так:

$obj->set_array($new_array);
Другие вопросы по тегам