PHP ArrayAccess множество многомерных

EDIT: Я понял, что количество текста может быть пугающим. Суть этого вопроса:
Как реализовать ArrayAccess таким образом, чтобы сделать возможным установку многомерных значений?


Я знаю, что это уже обсуждалось здесь, но я, похоже, не в состоянии правильно реализовать интерфейс ArrayAccess.

В принципе, у меня есть класс для обработки конфигурации приложения с помощью массива и реализации ArrayAccess . Извлечение значений отлично, даже значения из вложенных ключей ( $port = $config['app']['port']; ). Задание значений работает только для одномерных массивов: хотя я пытаюсь (un) установить значение (например, порт в предыдущем примере), я получаю следующее сообщение об ошибке:

 Notice: Indirect modification of overloaded element <object name> has no effect in <file> on <line> 

Теперь общее мнение похоже, что метод offsetGet() должен возвращаться по ссылке ( &offsetGet() ). Это, однако, не решает проблему, и я боюсь, что не знаю, как правильно реализовать этот метод – почему метод getter используется для установки значения? Php doc здесь тоже не очень полезен.

Чтобы напрямую воспроизвести это (PHP 5.4-5.6), найдите пример кода, приведенного ниже:

 <?php class Config implements \ArrayAccess { private $data = array(); public function __construct($data) { $this->data = $data; } /** * ArrayAccess Interface * */ public function offsetSet($offset, $value) { if (is_null($offset)) { $this->data[] = $value; } else { $this->data[$offset] = $value; } } public function &offsetGet($offset) { return isset($this->data[$offset]) ? $this->data[$offset] : null; } public function offsetExists($offset) { return isset($this->data[$offset]); } public function offsetUnset($offset) { unset($this->data[$offset]); } } $conf = new Config(array('a' => 'foo', 'b' => 'bar', 'c' => array('sub' => 'baz'))); $conf['c']['sub'] = 'notbaz'; не <?php class Config implements \ArrayAccess { private $data = array(); public function __construct($data) { $this->data = $data; } /** * ArrayAccess Interface * */ public function offsetSet($offset, $value) { if (is_null($offset)) { $this->data[] = $value; } else { $this->data[$offset] = $value; } } public function &offsetGet($offset) { return isset($this->data[$offset]) ? $this->data[$offset] : null; } public function offsetExists($offset) { return isset($this->data[$offset]); } public function offsetUnset($offset) { unset($this->data[$offset]); } } $conf = new Config(array('a' => 'foo', 'b' => 'bar', 'c' => array('sub' => 'baz'))); $conf['c']['sub'] = 'notbaz'; 

EDIT 2: решение, как отметил Райан, состояло в том, чтобы вместо этого использовать ArrayObject (который уже реализует ArrayAccess , ArrayAccess и IteratorAggregate ).
Чтобы применить его к классу, содержащему массив, создайте его так:

 <?php class Config extends \ArrayObject { private $data = array(); public function __construct($data) { $this->data = $data; parent::__construct($this->data); } /** * Iterator Interface * */ public function getIterator() { return new \ArrayIterator($this->data); } /** * Count Interface * */ public function count() { return count($this->data); } } 

Я использовал это для моей библиотеки библиотек libconfig которая доступна в Github под лицензией MIT.

Я не уверен, что это будет полезно. Я заметил, что класс ArrayObject является «интересным» …

Я не уверен, что это даже «ответ». Это больше наблюдение за этим классом.

Он корректно обрабатывает материал «многомерного массива».

Возможно, вы сможете добавлять методы, чтобы сделать больше того, что вы пожелаете?

 <?php // class Config extends \ArrayObject { // private $data = array(); public function __construct(array $data = array()) { parent::__construct($data); } } $conf = new Config(array('a' => 'foo', 'b' => 'bar', 'c' => array('sub' => 'baz'))); $conf['c']['sub'] = 'notbaz'; $conf['c']['sub2'] = 'notbaz2'; var_dump($conf, $conf['c'], $conf['c']['sub']); unset($conf['c']['sub']); var_dump('isset?: ', isset($conf['c']['sub'])); var_dump($conf, $conf['c'], $conf['c']['sub2']); с <?php // class Config extends \ArrayObject { // private $data = array(); public function __construct(array $data = array()) { parent::__construct($data); } } $conf = new Config(array('a' => 'foo', 'b' => 'bar', 'c' => array('sub' => 'baz'))); $conf['c']['sub'] = 'notbaz'; $conf['c']['sub2'] = 'notbaz2'; var_dump($conf, $conf['c'], $conf['c']['sub']); unset($conf['c']['sub']); var_dump('isset?: ', isset($conf['c']['sub'])); var_dump($conf, $conf['c'], $conf['c']['sub2']); 

Вывод:

 object(Config)[1] public 'a' => string 'foo' (length=3) public 'b' => string 'bar' (length=3) public 'c' => array 'sub' => string 'notbaz' (length=6) 'sub2' => string 'notbaz2' (length=7) array 'sub' => string 'notbaz' (length=6) 'sub2' => string 'notbaz2' (length=7) string 'notbaz' (length=6) string 'isset?: ' (length=8) boolean false object(Config)[1] public 'a' => string 'foo' (length=3) public 'b' => string 'bar' (length=3) public 'c' => array 'sub2' => string 'notbaz2' (length=7) array 'sub2' => string 'notbaz2' (length=7) string 'notbaz2' (length=7)