Intereting Posts
С границами слов (\ b) в RegEx мне нужно иметь его до И после слова или раньше? Хорошие библиотеки PHP authorize.net Как передать ввод формы на страницу WordPress? Является ли использование суперглобалов непосредственно хорошим или плохим в PHP? Разбор JSON в PHP «stdClass не удалось преобразовать в строку» Программно создавая новый порядок в Woocommerce MySQL Полный текст поиска, увеличение минимального символа PHP: получение значения флажков, когда имя не имеет массива Присоединить изображение к событию Facebook (php sdk, rest или graph api) как создать класс php, который может быть запущен до логического (быть правдивым или ложным) глобальные переменные равны нулю при использовании PHPUnit Создать файл NACHA с помощью PHP? PHP – изменить специальные символы MS Word (^ l, ^ p, ^ s) на "," Кратчайшая возможная кодированная строка с возможностью декодирования (сокращать URL) с использованием только PHP Что такое Layout и что такое View в ZF? Когда и какие переменные следует использовать и почему?

ArrayAccess многомерный (un) набор?

У меня есть класс, реализующий ArrayAccess и я пытаюсь заставить его работать с многомерным массивом. exists и get работу. set и unset дают мне проблему, хотя.

 class ArrayTest implements ArrayAccess { private $_arr = array( 'test' => array( 'bar' => 1, 'baz' => 2 ) ); public function offsetExists($name) { return isset($this->_arr[$name]); } public function offsetSet($name, $value) { $this->_arr[$name] = $value; } public function offsetGet($name) { return $this->_arr[$name]; } public function offsetUnset($name) { unset($this->_arr[$name]); } } $arrTest = new ArrayTest(); isset($arrTest['test']['bar']); // Returns TRUE echo $arrTest['test']['baz']; // Echo's 2 unset($arrTest['test']['bar']; // Error $arrTest['test']['bar'] = 5; // Error с class ArrayTest implements ArrayAccess { private $_arr = array( 'test' => array( 'bar' => 1, 'baz' => 2 ) ); public function offsetExists($name) { return isset($this->_arr[$name]); } public function offsetSet($name, $value) { $this->_arr[$name] = $value; } public function offsetGet($name) { return $this->_arr[$name]; } public function offsetUnset($name) { unset($this->_arr[$name]); } } $arrTest = new ArrayTest(); isset($arrTest['test']['bar']); // Returns TRUE echo $arrTest['test']['baz']; // Echo's 2 unset($arrTest['test']['bar']; // Error $arrTest['test']['bar'] = 5; // Error 

Я знаю, что $_arr можно просто обнародовать, чтобы вы могли получить доступ к нему напрямую, но для моей реализации это нежелательно и является конфиденциальным.

Последние 2 строки выдают ошибку: Notice: Indirect modification of overloaded element .

Я знаю, что ArrayAccess как правило, не работает с многомерными массивами, но все равно существует эта или какая-то несколько чистая реализация, которая позволит использовать нужные функции?

Лучшей идеей, которую я мог бы придумать, является использование символа в качестве разделителя и тестирование на него в set и unset и действие соответственно. Хотя это становится действительно уродливым очень быстро, если вы имеете дело с переменной глубиной.

Кто-нибудь знает, почему exists и работает, чтобы, возможно, копировать функциональность?

Спасибо за любую помощь, которую любой может предложить.

Проблема может быть решена путем изменения public function offsetGet($name) на public function &offsetGet($name) (путем добавления возврата по ссылке), но это приведет к фатальной ошибке (« Объявление из массива»: offsetGet () должно быть совместимо с то из ArrayAccess :: offsetGet () ").

PHP-разработчики придумали этот класс некоторое время назад, и теперь они не изменят его ради обратной совместимости :

Мы выяснили, что это не разрешимо, не взорвав интерфейс и не создавая BC или предоставляя дополнительный интерфейс для поддержки ссылок и тем самым создавая внутренний кошмар – на самом деле я не вижу способа, которым мы можем сделать эту работу когда-либо. Таким образом, мы решили обеспечить первоначальный дизайн и запретить ссылки completeley.

Изменить. Если вам все еще нужна эта функциональность, я бы предложил вместо этого использовать магический метод ( __get() , __set() и т. Д.), Потому что __get() возвращает значение по ссылке. Это изменит синтаксис на что-то вроде этого:

 $arrTest->test['bar'] = 5; 

Конечно, не идеальное решение, но я не могу придумать лучшего.

Обновление: эта проблема была исправлена ​​в PHP 5.3.4, и теперь ArrayAccess работает так, как ожидалось:

Начиная с PHP 5.3.4, проверки прототипов были ослаблены, и реализации этого метода можно вернуть по ссылке. Это делает возможным косвенные изменения в размерах перегруженных массивов объектов ArrayAccess.

Эта проблема действительно разрешима, полностью функциональна, как она должна быть.

Из комментария к документации ArrayAccess здесь :

 <?php // sanity and error checking omitted for brevity // note: it's a good idea to implement arrayaccess + countable + an // iterator interface (like iteratoraggregate) as a triplet class RecursiveArrayAccess implements ArrayAccess { private $data = array(); // necessary for deep copies public function __clone() { foreach ($this->data as $key => $value) if ($value instanceof self) $this[$key] = clone $value; } public function __construct(array $data = array()) { foreach ($data as $key => $value) $this[$key] = $value; } public function offsetSet($offset, $data) { if (is_array($data)) $data = new self($data); if ($offset === null) { // don't forget this! $this->data[] = $data; } else { $this->data[$offset] = $data; } } public function toArray() { $data = $this->data; foreach ($data as $key => $value) if ($value instanceof self) $data[$key] = $value->toArray(); return $data; } // as normal public function offsetGet($offset) { return $this->data[$offset]; } public function offsetExists($offset) { return isset($this->data[$offset]); } public function offsetUnset($offset) { unset($this->data); } } $a = new RecursiveArrayAccess(); $a[0] = array(1=>"foo", 2=>array(3=>"bar", 4=>array(5=>"bz"))); // oops. typo $a[0][2][4][5] = "baz"; //var_dump($a); //var_dump($a->toArray()); // isset and unset work too //var_dump(isset($a[0][2][4][5])); // equivalent to $a[0][2][4]->offsetExists(5) //unset($a[0][2][4][5]); // equivalent to $a[0][2][4]->offsetUnset(5); // if __clone wasn't implemented then cloning would produce a shallow copy, and $b = clone $a; $b[0][2][4][5] = "xyzzy"; // would affect $a's data too //echo $a[0][2][4][5]; // still "baz" ?> с <?php // sanity and error checking omitted for brevity // note: it's a good idea to implement arrayaccess + countable + an // iterator interface (like iteratoraggregate) as a triplet class RecursiveArrayAccess implements ArrayAccess { private $data = array(); // necessary for deep copies public function __clone() { foreach ($this->data as $key => $value) if ($value instanceof self) $this[$key] = clone $value; } public function __construct(array $data = array()) { foreach ($data as $key => $value) $this[$key] = $value; } public function offsetSet($offset, $data) { if (is_array($data)) $data = new self($data); if ($offset === null) { // don't forget this! $this->data[] = $data; } else { $this->data[$offset] = $data; } } public function toArray() { $data = $this->data; foreach ($data as $key => $value) if ($value instanceof self) $data[$key] = $value->toArray(); return $data; } // as normal public function offsetGet($offset) { return $this->data[$offset]; } public function offsetExists($offset) { return isset($this->data[$offset]); } public function offsetUnset($offset) { unset($this->data); } } $a = new RecursiveArrayAccess(); $a[0] = array(1=>"foo", 2=>array(3=>"bar", 4=>array(5=>"bz"))); // oops. typo $a[0][2][4][5] = "baz"; //var_dump($a); //var_dump($a->toArray()); // isset and unset work too //var_dump(isset($a[0][2][4][5])); // equivalent to $a[0][2][4]->offsetExists(5) //unset($a[0][2][4][5]); // equivalent to $a[0][2][4]->offsetUnset(5); // if __clone wasn't implemented then cloning would produce a shallow copy, and $b = clone $a; $b[0][2][4][5] = "xyzzy"; // would affect $a's data too //echo $a[0][2][4][5]; // still "baz" ?> 

Затем вы можете расширить этот класс следующим образом:

 <?php class Example extends RecursiveArrayAccess { function __construct($data = array()) { parent::__construct($data); } } $ex = new Example(array('foo' => array('bar' => 'baz'))); print_r($ex); $ex['foo']['bar'] = 'pong'; print_r($ex); ?> 

Это даст вам объект, который можно рассматривать как массив (в основном, см. Примечание в коде), который поддерживает многомерный массив set / get / unset.

EDIT: см. Ответ Александра Константинова. Я думал о методе __get magic, который аналогичен, но был фактически реализован правильно. Таким образом, вы не можете сделать это без внутренней реализации вашего класса.

EDIT2: Внутренняя реализация:

ПРИМЕЧАНИЕ. Вы можете утверждать, что это чисто мастурбация, но в любом случае здесь:

 static zend_object_handlers object_handlers; static zend_object_value ce_create_object(zend_class_entry *class_type TSRMLS_DC) { zend_object_value zov; zend_object *zobj; zobj = emalloc(sizeof *zobj); zend_object_std_init(zobj, class_type TSRMLS_CC); zend_hash_copy(zobj->properties, &(class_type->default_properties), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval*)); zov.handle = zend_objects_store_put(zobj, (zend_objects_store_dtor_t) zend_objects_destroy_object, (zend_objects_free_object_storage_t) zend_objects_free_object_storage, NULL TSRMLS_CC); zov.handlers = &object_handlers; return zov; } /* modification of zend_std_read_dimension */ zval *read_dimension(zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */ { zend_class_entry *ce = Z_OBJCE_P(object); zval *retval; void *dummy; if (zend_hash_find(&ce->function_table, "offsetgetref", sizeof("offsetgetref"), &dummy) == SUCCESS) { if(offset == NULL) { /* [] construct */ ALLOC_INIT_ZVAL(offset); } else { SEPARATE_ARG_IF_REF(offset); } zend_call_method_with_1_params(&object, ce, NULL, "offsetgetref", &retval, offset); zval_ptr_dtor(&offset); if (!retval) { if (!EG(exception)) { /* ought to use php_error_docref* instead */ zend_error(E_ERROR, "Undefined offset for object of type %s used as array", ce->name); } return 0; } /* Undo PZVAL_LOCK() */ Z_DELREF_P(retval); return retval; } else { zend_error(E_ERROR, "Cannot use object of type %s as array", ce->name); return 0; } } ZEND_MODULE_STARTUP_D(testext) { zend_class_entry ce; zend_class_entry *ce_ptr; memcpy(&object_handlers, zend_get_std_object_handlers(), sizeof object_handlers); object_handlers.read_dimension = read_dimension; INIT_CLASS_ENTRY(ce, "TestClass", NULL); ce_ptr = zend_register_internal_class(&ce TSRMLS_CC); ce_ptr->create_object = ce_create_object; return SUCCESS; } 

теперь этот скрипт:

 <?php class ArrayTest extends TestClass implements ArrayAccess { private $_arr = array( 'test' => array( 'bar' => 1, 'baz' => 2 ) ); public function offsetExists($name) { return isset($this->_arr[$name]); } public function offsetSet($name, $value) { $this->_arr[$name] = $value; } public function offsetGet($name) { throw new RuntimeException("This method should never be called"); } public function &offsetGetRef($name) { return $this->_arr[$name]; } public function offsetUnset($name) { unset($this->_arr[$name]); } } $arrTest = new ArrayTest(); echo (isset($arrTest['test']['bar'])?"test/bar is set":"error") . "\n"; echo $arrTest['test']['baz']; // Echoes 2 echo "\n"; unset($arrTest['test']['baz']); echo (isset($arrTest['test']['baz'])?"error":"test/baz is not set") . "\n"; $arrTest['test']['baz'] = 5; echo $arrTest['test']['baz']; // Echoes 5 с <?php class ArrayTest extends TestClass implements ArrayAccess { private $_arr = array( 'test' => array( 'bar' => 1, 'baz' => 2 ) ); public function offsetExists($name) { return isset($this->_arr[$name]); } public function offsetSet($name, $value) { $this->_arr[$name] = $value; } public function offsetGet($name) { throw new RuntimeException("This method should never be called"); } public function &offsetGetRef($name) { return $this->_arr[$name]; } public function offsetUnset($name) { unset($this->_arr[$name]); } } $arrTest = new ArrayTest(); echo (isset($arrTest['test']['bar'])?"test/bar is set":"error") . "\n"; echo $arrTest['test']['baz']; // Echoes 2 echo "\n"; unset($arrTest['test']['baz']); echo (isset($arrTest['test']['baz'])?"error":"test/baz is not set") . "\n"; $arrTest['test']['baz'] = 5; echo $arrTest['test']['baz']; // Echoes 5 с <?php class ArrayTest extends TestClass implements ArrayAccess { private $_arr = array( 'test' => array( 'bar' => 1, 'baz' => 2 ) ); public function offsetExists($name) { return isset($this->_arr[$name]); } public function offsetSet($name, $value) { $this->_arr[$name] = $value; } public function offsetGet($name) { throw new RuntimeException("This method should never be called"); } public function &offsetGetRef($name) { return $this->_arr[$name]; } public function offsetUnset($name) { unset($this->_arr[$name]); } } $arrTest = new ArrayTest(); echo (isset($arrTest['test']['bar'])?"test/bar is set":"error") . "\n"; echo $arrTest['test']['baz']; // Echoes 2 echo "\n"; unset($arrTest['test']['baz']); echo (isset($arrTest['test']['baz'])?"error":"test/baz is not set") . "\n"; $arrTest['test']['baz'] = 5; echo $arrTest['test']['baz']; // Echoes 5 

дает:

 test/bar is set 2 test/baz is not set 5 

ORIGINAL – это неверно:

Реализация offsetGet должна возвращать ссылку для ее работы.

 public function &offsetGet($name) { return $this->_arr[$name]; } 

Для внутреннего эквивалента см. Здесь .

Так как нет аналогичного get_property_ptr_ptr, вы должны вернуть ссылку (в смысле Z_ISREF) или прокси-объекта (см. Обработчик get) в сценариях записи (типы BP_VAR_W, BP_VAR_RW и BP_VAR_UNSET), хотя это необязательно. Если read_dimension вызывается в контексте, подобном записи, например, в $ val = & $ obj ['prop'], и вы не возвращаете ни ссылку, ни объект, двигатель выдает уведомление. Очевидно, что возвращать ссылку недостаточно для правильной работы этих операций, необходимо, чтобы изменение возвращаемого zval действительно имело некоторый эффект. Обратите внимание, что назначения, такие как $ obj ['key'] = & $ a, по-прежнему невозможны – для этого нужны размеры, которые фактически могут быть сохранены как zvals (что может быть или не быть) и два уровня косвенности.

В целом, операции, которые включают в себя запись или прочтение подразмера смещения субобъекта offsetGet, а не offsetSet, offsetExists или offsetUnset.

Решение:

 <?php /** * Cube PHP Framework * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * @author Dillen / Steffen */ namespace Library; /** * The application * * @package Library */ class ArrayObject implements \ArrayAccess { protected $_storage = array(); // necessary for deep copies public function __clone() { foreach ($this->_storage as $key => $value) { if ($value instanceof self) { $this->_storage[$key] = clone $value; } } } public function __construct(array $_storage = array()) { foreach ($_storage as $key => $value) { $this->_storage[$key] = $value; } } public function offsetSet($offset, $_storage) { if (is_array($_storage)) { $_storage = new self($_storage); } if ($offset === null) { $this->_storage[] = $_storage; } else { $this->_storage[$offset] = $_storage; } } public function toArray() { $_storage = $this -> _storage; foreach ($_storage as $key => $value) { if ($value instanceof self) { $_storage[$key] = $value -> toArray(); } } return $_storage; } // as normal public function offsetGet($offset) { if (isset($this->_storage[$offset])) { return $this->_storage[$offset]; } if (!isset($this->_storage[$offset])) { $this->_storage[$offset] = new self; } return $this->_storage[$offset]; } public function offsetExists($offset) { return isset($this->_storage[$offset]); } public function offsetUnset($offset) { unset($this->_storage); } } с <?php /** * Cube PHP Framework * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * @author Dillen / Steffen */ namespace Library; /** * The application * * @package Library */ class ArrayObject implements \ArrayAccess { protected $_storage = array(); // necessary for deep copies public function __clone() { foreach ($this->_storage as $key => $value) { if ($value instanceof self) { $this->_storage[$key] = clone $value; } } } public function __construct(array $_storage = array()) { foreach ($_storage as $key => $value) { $this->_storage[$key] = $value; } } public function offsetSet($offset, $_storage) { if (is_array($_storage)) { $_storage = new self($_storage); } if ($offset === null) { $this->_storage[] = $_storage; } else { $this->_storage[$offset] = $_storage; } } public function toArray() { $_storage = $this -> _storage; foreach ($_storage as $key => $value) { if ($value instanceof self) { $_storage[$key] = $value -> toArray(); } } return $_storage; } // as normal public function offsetGet($offset) { if (isset($this->_storage[$offset])) { return $this->_storage[$offset]; } if (!isset($this->_storage[$offset])) { $this->_storage[$offset] = new self; } return $this->_storage[$offset]; } public function offsetExists($offset) { return isset($this->_storage[$offset]); } public function offsetUnset($offset) { unset($this->_storage); } } 

Я решил это, используя это:

 class Colunas implements ArrayAccess { public $cols = array(); public function offsetSet($offset, $value) { $coluna = new Coluna($value); if (!is_array($offset)) { $this->cols[$offset] = $coluna; } else { if (!isset($this->cols[$offset[0]])) $this->cols[$offset[0]] = array(); $col = &$this->cols[$offset[0]]; for ($i = 1; $i < sizeof($offset); $i++) { if (!isset($col[$offset[$i]])) $col[$offset[$i]] = array(); $col = &$col[$offset[$i]]; } $col = $coluna; } } public function offsetExists($offset) { if (!is_array($offset)) { return isset($this->cols[$offset]); } else { $key = array_shift($offset); if (!isset($this->cols[$key])) return FALSE; $col = &$this->cols[$key]; while ($key = array_shift($offset)) { if (!isset($col[$key])) return FALSE; $col = &$col[$key]; } return TRUE; } } public function offsetUnset($offset) { if (!is_array($offset)) { unset($this->cols[$offset]); } else { $col = &$this->cols[array_shift($offset)]; while (sizeof($offset) > 1) $col = &$col[array_shift($offset)]; unset($col[array_shift($offset)]); } } public function offsetGet($offset) { if (!is_array($offset)) { return $this->cols[$offset]; } else { $col = &$this->cols[array_shift($offset)]; while (sizeof($offset) > 0) $col = &$col[array_shift($offset)]; return $col; } } } не class Colunas implements ArrayAccess { public $cols = array(); public function offsetSet($offset, $value) { $coluna = new Coluna($value); if (!is_array($offset)) { $this->cols[$offset] = $coluna; } else { if (!isset($this->cols[$offset[0]])) $this->cols[$offset[0]] = array(); $col = &$this->cols[$offset[0]]; for ($i = 1; $i < sizeof($offset); $i++) { if (!isset($col[$offset[$i]])) $col[$offset[$i]] = array(); $col = &$col[$offset[$i]]; } $col = $coluna; } } public function offsetExists($offset) { if (!is_array($offset)) { return isset($this->cols[$offset]); } else { $key = array_shift($offset); if (!isset($this->cols[$key])) return FALSE; $col = &$this->cols[$key]; while ($key = array_shift($offset)) { if (!isset($col[$key])) return FALSE; $col = &$col[$key]; } return TRUE; } } public function offsetUnset($offset) { if (!is_array($offset)) { unset($this->cols[$offset]); } else { $col = &$this->cols[array_shift($offset)]; while (sizeof($offset) > 1) $col = &$col[array_shift($offset)]; unset($col[array_shift($offset)]); } } public function offsetGet($offset) { if (!is_array($offset)) { return $this->cols[$offset]; } else { $col = &$this->cols[array_shift($offset)]; while (sizeof($offset) > 0) $col = &$col[array_shift($offset)]; return $col; } } } с class Colunas implements ArrayAccess { public $cols = array(); public function offsetSet($offset, $value) { $coluna = new Coluna($value); if (!is_array($offset)) { $this->cols[$offset] = $coluna; } else { if (!isset($this->cols[$offset[0]])) $this->cols[$offset[0]] = array(); $col = &$this->cols[$offset[0]]; for ($i = 1; $i < sizeof($offset); $i++) { if (!isset($col[$offset[$i]])) $col[$offset[$i]] = array(); $col = &$col[$offset[$i]]; } $col = $coluna; } } public function offsetExists($offset) { if (!is_array($offset)) { return isset($this->cols[$offset]); } else { $key = array_shift($offset); if (!isset($this->cols[$key])) return FALSE; $col = &$this->cols[$key]; while ($key = array_shift($offset)) { if (!isset($col[$key])) return FALSE; $col = &$col[$key]; } return TRUE; } } public function offsetUnset($offset) { if (!is_array($offset)) { unset($this->cols[$offset]); } else { $col = &$this->cols[array_shift($offset)]; while (sizeof($offset) > 1) $col = &$col[array_shift($offset)]; unset($col[array_shift($offset)]); } } public function offsetGet($offset) { if (!is_array($offset)) { return $this->cols[$offset]; } else { $col = &$this->cols[array_shift($offset)]; while (sizeof($offset) > 0) $col = &$col[array_shift($offset)]; return $col; } } } 

Таким образом, вы можете использовать его с:

 $colunas = new Colunas(); $colunas['foo'] = 'Foo'; $colunas[array('bar', 'a')] = 'Bar A'; $colunas[array('bar', 'b')] = 'Bar B'; echo $colunas[array('bar', 'a')]; unset($colunas[array('bar', 'a')]); isset($colunas[array('bar', 'a')]); unset($colunas['bar']); 

Обратите внимание, что я не проверяю, является ли смещение нулевым, и если это массив, он должен быть размером> 1.

В основном в соответствии с решением Дакоты * Я хочу поделиться своим упрощением.

*) Дакота был для меня наиболее понятным, и результат довольно велик (- другие, похоже, очень похожи).

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

 class DimensionalArrayAccess implements ArrayAccess { private $_arr; public function __construct(array $arr = array()) { foreach ($arr as $key => $value) { $this[$key] = $value; } } public function offsetSet($offset, $val) { if (is_array($val)) $val = new self($val); if ($offset === null) { $this->_arr[] = $val; } else { $this->_arr[$offset] = $val; } } // as normal public function offsetGet($offset) { return $this->_arr[$offset]; } public function offsetExists($offset) { return isset($this->_arr[$offset]); } public function offsetUnset($offset) { unset($this->_arr); } } class Example extends DimensionalArrayAccess { function __construct() { parent::__construct([[["foo"]]]); } } $ex = new Example(); echo $ex[0][0][0]; $ex[0][0][0] = 'bar'; echo $ex[0][0][0]; с class DimensionalArrayAccess implements ArrayAccess { private $_arr; public function __construct(array $arr = array()) { foreach ($arr as $key => $value) { $this[$key] = $value; } } public function offsetSet($offset, $val) { if (is_array($val)) $val = new self($val); if ($offset === null) { $this->_arr[] = $val; } else { $this->_arr[$offset] = $val; } } // as normal public function offsetGet($offset) { return $this->_arr[$offset]; } public function offsetExists($offset) { return isset($this->_arr[$offset]); } public function offsetUnset($offset) { unset($this->_arr); } } class Example extends DimensionalArrayAccess { function __construct() { parent::__construct([[["foo"]]]); } } $ex = new Example(); echo $ex[0][0][0]; $ex[0][0][0] = 'bar'; echo $ex[0][0][0]; 

Я сделал некоторые изменения:

  • удалил функцию toArray, так как она не имеет непосредственной цели, если вы не хотите преобразовывать свой объект в реальный (в ассоциативном массиве событий Dakota).
  • удалил клоновую вещь, так как она не имеет непосредственной цели, если вы не хотите клонировать ваш объект.
  • переименованный в расширенный класс и те же самые вары: кажется мне более понятным. особенно я хочу подчеркнуть, что класс DimensionalArrayAccess предоставляет подобный массиву доступ к вашему объекту даже для трехмерных или многомерных (и, конечно же, неассоциативных) массивов – по крайней мере, до тех пор, пока вы инициируете его с помощью массив, подсчитывающий количество необходимых размеров.
  • последнее, мне кажется важным подчеркнуть, что, поскольку вы можете видеть, что сам класс Example не зависит от переменной конструктора, тогда как класс DimensionalArrayAccess (так как он вызывает себя в функции offsetSet рекурсивно.

Как я представил, этот пост скорее для не столь продвинутых, как я.

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

 class Test implements \ArrayAccess { private $input = []; public function __construct () { $this->input = ['foo' => ['bar' => 'qux']]; } public function offsetExists ($offset) {} public function offsetGet ($offset) {} public function offsetSet ($offset, $value) {} public function offsetUnset ($offset) {} } runkit_method_redefine ('Test', 'offsetGet', '&$offset', 'return $this->input[$offset];'); $ui = new Test; var_dump($ui['foo']['bar']); // string(3) "qux"