Я читаю эту статью о ссылках на переменные PHP: http://derickrethans.nl/talks/phparch-php-variables-article.pdf
и хотел проверить правильность моего понимания относительно того, когда создаются новые переменные контейнеры.
Для не массивов контейнеры переменных создаются каждый раз, когда вы назначаете переменную, которая не указывает на контейнер с установленным is_ref.
Ex 1 (let {..} be a container):
$a = 1; // "a" => {integer, 1, is_ref = 0, ref_count = 1}
$b = $a; // "a", "b" => {integer, 1, is_ref = 0, ref_count = 2}
$b = 2; // "a" => {integer, 1, is_ref = 0, ref_count = 1}
// "b" => {integer, 2, is_ref = 0, ref_count = 1}
Ex 2:
$a = 1; // "a" => {integer, 1, is_ref = 0, ref_count = 1}
$b = &$a; // "a", "b" => {integer, 1, is_ref = 1, ref_count = 2}
$b = 2; // "a", "b" => {integer, 2, is_ref = 1, ref_count = 2}
Как это работает для массивов? Это не похоже на то же самое. Например,
$a = array(1, 2, 3);
$b = $a;
$c = &$b[2];
$c = 4;
print_r($a); // prints (1, 2, 3) instead of (1, 2, 4)
print_r($b); // prints (1, 2, 4)
Мое ожидание:
$ a и $ b указывают на один и тот же контейнер. В этом контейнере у нас есть 3 numeric_keys «0», «1», «2», которые указывают на контейнеры для целых чисел 1, 2 и 3 соответственно.
Когда мы делаем $c = &$b[2]
обновляем контейнер, содержащий целое число 3:
Когда мы делаем $c = 4
обновляем контейнер, содержащий целое число 3:
Однако что-то не так с моим ожиданием, потому что $a[2] != 4
в конце. Я пытаюсь понять, почему. Мое лучшее предположение состоит в том, что когда мы пытаемся ссылаться на элементы массива или свойства объекта, механизм PHP сначала проверяет сам массив / объект, чтобы увидеть, является ли is_ref = 1. Если это так, все работает в соответствии с моими ожиданиями. Если is_ref = 0, то происходит что-то еще, что я и вижу. Может кто-нибудь объяснить мне, что это за «что-то еще»?
РЕДАКТИРОВАТЬ
Похоже, это то, что на самом деле происходит. Этот код должен все прояснить!
$a = array(1, 2, 3);
$b = $a;
$c = &$b[2]; // $b points to a new container where $b[0], $b[1] still point to same container as $a[0], $a[1], but $b[2] points to a new container also pointed to by $c
$d = $b; // $d points to $b's container, this means changing $c will also change $d[2]
$d[0] = 5; // The container pointed to by $d[0] is the same as the one pointed to by $a[0] and $b[0]. Since this container has is_ref = 0, $d[0] will now point to a new container
// At this point $a = (1, 2, 3), $b = (1, 2, 3), $c = 3, $d = (5, 2, 3)
$d[2] = 25; // The container pointed to by $d[2] is the same as the one pointed to by $b[2] and $c. Since this container has is_ref = 1, Changing $d[2] will affect both $b[2] and $c.
// At this point $a = (1, 2, 3), $b = (1, 2, 25), $c = 25, $d = (5, 2, 25)
$e = $d[2]; // Since $d[2]'s container has is_ref = 1, $e will point to its own container
$c = 4; // Same idea as $d[2] = 25; except $e won't get affected
// At this point $a = (1, 2, 3), $b = (1, 2, 4), $c = 4, $d = (5, 2, 4), $e = 25
// only way to have $d[2] be different from $b[2] is to make the container's is_ref = 0
unset($b[2]);
unset($c);
$b[2] = $d[2];
$d[2] = 55;
// At this point $a = (1, 2, 3), $b = (1, 2, 4), $d = (5, 2, 25), $e = 25
Что вы создали $a
это была простая переменная. Но когда вы создали $b
по умолчанию PHP скопировал переменную. Так $b
теперь полностью отделен от $a
Так же, как это было в вашем первом примере.
Затем вы установите $c
равный ссылка в $b[2]
, Таким образом, они оба указывают на то же адрес памяти. Обновите один, и он обновляет другой. Проблема в том, что вы думаете, что $a
следует обновить, но это не должно быть, потому что $b
это его собственная переменная. Посмотрите, что происходит, когда мы меняемся $b
на ссылку на $a
$a = array(1, 2, 3);
$b = &$a;
$c = &$b[2];
$c = 4;
print_r($a); // prints (1, 2, 4)
print_r($b); // prints (1, 2, 4)
Это работает, как вы описываете, потому что $b
а также $a
ссылаться на то же самое (технически $b
теперь символ, указывающий на $a
)
Если вы хотите еще глубже погрузиться в тему, вот отличная статья, которая подробно ее освещает. http://webandphp.com/how-php-manages-variables
Других решений пока нет …