PHP 5.6+. Имеется класс.
class PropertyContainer {
protected $_data;
public $somePublicArray = [0];
public function __construct($data = [])
{
$this->_data = $data;
}
public function __get($name)
{
return array_key_exists($name, $this->_data) ? $this->_data[$name] : null;
}
public function __set($name, $value)
{
$this->_data[$name] = $value;
}
public function __unset($name)
{
unset($this->_data[$name]);
}
public function __isset($name)
{
return array_key_exists($name, $this->_data);
}
}
Работа со свойствами класса происходит через магические методы и внутренний массив $_data, если свойство не объявлено в классе - довольно стандартный подход. И всё бы здорово, если бы не странный подход к оператору [] = в PHP: проводим тест
$cont = new PropertyContainer(['a' => 1, 'b' => [0], 'c' => new ArrayObject ([0])]);
$cont->a++; /*$cont->a = 2 OK*/
$cont->b[] = 1; /*$cont->b = [0] FAIL*/
$cont->somePublicArray[] = 1; /*$cont->somePublicArray = [0,1] OK*/
$cont->c[] = 1; /*$cont->c = ArrayObject [0,1] OK*/
var_dump($cont, is_array($cont->c));
die();
То есть массивы, содержащиеся внутри $_data возвращаются не по ссылке.
Вопрос - какие есть способы это обойти, и использовать оператор [] = для заполнения внутренних массивов, кроме как массово использовать ArrayObject вместо array? С такой же проблеммой сталкивались , но эти решения не работают для хранения данных произвольных типов во внутреннем массиве (вроде $_data)- хотелось бы храннить данные в массиве (или ArrayObject) как есть.
В использовании ArrayObject не нравится не срабатывания метода is_array() на нём, может быть можно переопределить поведение is_array ?
Если использовать &__get вместо __get - можно ли вернуть указатель на элемент массива $_data ? Иначе будет просто варнинг Only variable references should be returned by reference .
Ответ
Вариант 1: Если не нужна поддержка не объявляенных свойств:
public function &__get($name)
{
if( array_key_exists($name, $this->_data) )
$val = &$this->_data[$name];
else
$val = null;
return $val;
}
В этом варианте есть баг:
$cont = new PropertyContainer(['a' => 1, 'b' => [0]]);
$cont->d[] = 1; // d не будет добавлено, вообще ничего не произойдёт.
Вариант 2: Баг первого варианта исправлен, но _data будет захламлятся если есть попытки получать необъявляенные свойства.
public function &__get($name)
{
if( ! array_key_exists( $name, $this->_data ) ){
$undefined; //It is possible to set default
// value for every new parameter
//Default is undefined.
$this->_data[ $name ] = $undefined;
}
$val = &$this->_data[$name];
return $val;
}
Комментариев нет:
Отправить комментарий