На днях я столкнулся с этим, казалось бы, очень простым вопросом Как изменить значение в $array2 без ссылки $array1? Тем не менее, чем больше я смотрел на него, тем более странным казалось, что это действительно работает по назначению. После этого я начал изучать коды операций, которые генерируются из вывода следующего.
$array1 = array(2, 10);
$x = &$array1[1];
$array2 = $array1;
$array2[1] = 22;
echo $array1[1]; // Outputs 22
Это кажется сумасшедшим для меня, поскольку array2 должен быть только копией array1, и все, что происходит с одним массивом, не должно влиять на содержимое другого. Конечно, если вы закомментируете вторую строчку, финальная строка будет эхо от 10, как ожидалось.
Глядя дальше, я мог бы создать классный сайт, который показывает мне коды операций, которые PHP создает с помощью Vulcan Logic Dumper. Вот коды операций, генерируемые указанным выше кодом.
Finding entry points
Branch analysis from position: 0
Return found
filename: /in/qO86H
function name: (null)
number of ops: 11
compiled vars: !0 = $array1, !1 = $x, !2 = $array2
line # * op fetch ext return operands
---------------------------------------------------------------------------------
3 0 > INIT_ARRAY ~0 2
1 ADD_ARRAY_ELEMENT ~0 10
2 ASSIGN !0, ~0
4 3 FETCH_DIM_W $2 !0, 1
4 ASSIGN_REF !1, $2
5 5 ASSIGN !2, !0
6 6 ASSIGN_DIM !2, 1
7 OP_DATA 22, $6
8 8 FETCH_DIM_R $7 !0, 1
9 ECHO $7
10 > RETURN 1
Эти коды операций не документированы здесь отлично http://php.net/manual/en/internals2.opcodes.php, но я верю, что на английском языке коды операций делают следующее. По линии... может быть больше для меня, чем для кого-либо еще.
- Строка 3: Мы инициализируем массив с его первым значением, а затем добавляем 10 к нему, прежде чем назначать его в $array1.
- Строка 4: Получить только запись? значение из массива и назначить его ссылкой на $x.
- Строка 5: установите $array1 в $array2.
- Строка 6: Получить индекс массива 1. od_data Я предполагаю, что он устанавливает значение 22, хотя $6 никогда не возвращается. OD_DATA не имеет абсолютно никакой документации и не указана в качестве кода операции где бы я ни выглядела.
- Строка 8: выберите значение только для чтения из индекса 1 из массива $array1 и выполните эхо-код.
Даже работая через коды операций, я не знаю, где это происходит. У меня есть ощущение отсутствия документации по кодам операций, и моя неопытность в работе с ними, вероятно, не позволяет мне понять, где это происходит.
ИЗМЕНИТЬ 1:
Как указывал Майк в первых массивах комментариев, статус ссылки сохраняется при копировании. Здесь можно увидеть документацию вместе с местом в статье массива, которую она ссылается на http://php.net/manual/en/language.types.array.php#104064. Это довольно смешно не считается предупреждением. Что удивительно для меня, если это так, ссылочный статус не сохраняется для этого кода, как и следовало ожидать.
$array1 = array(2, 10);
$x = &$array1;
$array2 = $array1;
$array2[1] = 22;
echo $array1[1]; // Output is 10
Так кажется, что это происходит только тогда, когда вы пытаетесь назначить отдельные элементы по ссылке, делая эту функцию еще более запутанной.
Почему php только сохраняет статус индексов массивов при их индивидуальном назначении?
ИЗМЕНИТЬ 2:
Я провел некоторое тестирование с использованием HHVM сегодня, и HHVM обрабатывает первый снип-код кода, как вы думаете. Мне нравится PHP, но HHVM выглядит лучше и лучше по сравнению с Zend Engine.