Ответ 1
Внутренне в PHP все хранится внутри контейнера , называемого ZVAL. $data
представлен ZVAL, каждый ключ и каждое значение внутри $data
является ZVAL и т.д.
Итак, после первоначального присваивания, из PHP создал три ZVALs:
/-------------------\ /-------------------\
| ZVAL #1 | /==>| ZVAL #2 |
| type: array | | | type: string |
| data: [ | | | data: "foo" |
| { | | \-------------------/
| key: =======/ /-------------------\
| val: ================================>| ZVAL #3 |
| } | | type: string |
| ] | | data: "bar" |
\-------------------/ \-------------------/
Примечание: внутреннее представление элементов массива не соответствует тому, что показано выше; Я не хотел обременять ответ ненужными подробностями. По той же причине также показано упрощенное представление ZVAL. Если вы хотите узнать больше о внутренних функциях PHP, прочитайте источник и/или this.
Вы можете видеть, что тот факт, что "foo"
и "bar"
используются как пара ключей/значений массива, определить невозможно, посмотрев на их ZVAL: вы должны знать, что на них ссылаются массив.
После назначения $data['baz'] = &$data
произойдет то, что теперь у вас есть циклическая ссылка: где-то внутри ZVAL # 1 появляется указатель на ZVAL # 1:
/-------------------\ /-------------------\
| ZVAL #1 | /==>| ZVAL #2 |
/=>| type: array | | | type: string |
| | data: [ | | | data: "foo" |
| | { | | \-------------------/
| | key: =======/ /-------------------\
| | val: ================================>| ZVAL #3 |
| | }, | | type: string |
| | { | | data: "bar" |
| | key: =========================\ \-------------------/
| | val: =========\ |
| | } | | | /-------------------\
| | ] | | \======>| ZVAL #4 |
| \-------------------/ | | type: string |
| | | data: "baz" |
\===========================/ \-------------------/
Итак, как PHP решает $data['baz']['baz']
? Он знает, что $data
представлен ZVAL # 1, и он видит, что вы пытаетесь проиндексировать его с синтаксисом массива. Он смотрит на ZVAL, видит, что это массив, находит элемент с ключом "baz"
и получает ZVAL, который его представляет. Что ты знаешь? Это ZVAL # 1 еще раз. Это завершает разрешение $data['baz']
.
На следующем шаге он видит, что вы пытаетесь индексировать в $data['baz']
как массив. Он знает, что $data['baz']
представлен ZVAL # 1, поэтому одно и то же происходит снова и т.д.
Вы заметили, что вышеописанный процесс не включает в себя сохранение промежуточных результатов (первый и второй шаги полностью независимы), что означает, что ограничение виртуальной машины PHP не будет ограничено при попытке решить доступ к массиву.