offsetSet не вызывается в ArrayObject
Пример php кода:
class TestArrayObject extends ArrayObject {
function offsetSet($index,$val){
echo $index.':'.$val.PHP_EOL;
}
}
$s = new TestArrayObject();
//test 1
$s['a'] = 'value';//calls offsetSet
//test 2
$s['b']['c'] = 'value';//does not call offsetSet, why?
var_dump($s);
почему тест 2 не вызывает метод offsetSet?
3 ответа
ArrayObject
это большой кусок магии, и поэтому я бы не рекомендовал использовать его или, что еще хуже, расширить его.
Но ваша настоящая проблема не имеет отношения к ArrayObject
само собой. То, что вы сталкиваетесь с тем, что $s['b']['c'] = ...;
это так называемая косвенная модификация 'b'
смещение. Код, который выполняет PHP, выглядит примерно так:
$offset =& $s['b'];
$offset['c'] = ...;
Как вы можете видеть смещение 'b'
никогда не пишется напрямую. Вместо этого он выбирается по ссылке, а ссылка изменяется. Вот почему offsetGet
будет называться, а не offsetSet
,
Это своего рода "уловка", так как я думаю, что ожидаемое поведение будет таким, как заявленный ОП в этом вопросе.
кроме того, поведение не согласовано при доступе к ArrayObject как к объекту или к массиву.
Пример:
$foo['b']['c'] = 'value'; // no warning
var_dump($foo);
$bar->b->c = 'value'; // triggers warning
var_dump($bar);
У меня были те же проблемы с моим собственным классом, который расширяет ArrayObject. Я не смог исправить проблему, но мне удалось обойти ее, реализовав новый метод, который я использую для создания цепочки свойств.
class Arraylist extends ArrayObject
{
public function set($key, $value = null)
{
if (!is_null($value)) {
$val = new ArrayList((array) $value);
} else {
$val = new ArrayList();
}
$this->offsetSet($key, $val);
return $this->offsetGet($key);
}
public function offsetSet($index,$val){
echo $index.':'.$val.PHP_EOL;
parent::offsetSet($index, $val);
}
}
Используя пример OP:
Код:
$s = new ArrayList();
$s->set('a', 'value');
$s->set('b')->set('c', 'another value');
var_dump($s);
Выходы:
0:value
a:ArrayList
0:value
b:ArrayList
0:another value
c:ArrayList
0:another value
class ArrayList#5 (2) {
public $a =>
class ArrayList#7 (1) {
string(5) "value"
}
public $b =>
class ArrayList#8 (1) {
public $c =>
class ArrayList#9 (1) {
string(13) "another value"
}
}
}
Для многомерных массивов смотрите примечания пользователя здесь