Назначить по ссылке ошибка

На днях я столкнулся с этим, казалось бы, очень простым вопросом. Как изменить значение в $ 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, но я верю, что на английском языке коды операций делают следующее. По линии … может быть больше для меня, чем для кого-либо еще.

  1. Строка 3: Мы инициализируем массив с его первым значением, а затем добавляем 10 к нему, прежде чем назначать его массиву $ array1.
  2. Строка 4: Получить только для записи? значение из массива и назначить его ссылкой на $ x.
  3. Строка 5: установите массив $ array1 в $ array2.
  4. Строка 6: Получить индекс массива 1. od_data Я предполагаю, что он устанавливает значение 22, хотя $ 6 никогда не возвращается. OD_DATA не имеет абсолютно никакой документации и не указана в качестве кода операции в любом месте, где я смотрел.
  5. Строка 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 только сохраняет статус индексов массивов, когда они индивидуально назначаются?

EDIT 2:

Я провел некоторое тестирование с использованием HHVM сегодня, и HHVM обрабатывает первый снимок кода, как вы думаете. Мне нравится PHP, но HHVM выглядит лучше и лучше по сравнению с Zend Engine.

Это объясняется в руководстве PHP (даже если вам нужно потратить больше времени, чем нужно, чтобы найти его), в частности, по адресу http://php.net/manual/en/language.types.array. PHP # 104064

«Общие» данные остаются разделенными, причем начальное присваивание просто действует как псевдоним. Только после того, как вы начнете манипулировать массивами с помощью независимых операций, таких как ...[] = ... что intrereter начинает рассматривать их как расходящиеся списки, и даже тогда общие данные остаются разделенными, поэтому вы можете иметь два массива с общим первым n элементов, но расходящихся последующих данных.

Для истинной «копии по значению» для одного массива другому, вы в значительной степени в конечном итоге делаете что-то вроде

 $arr2 = array(); foreach($arr1 as $val) { $arr2[] = $val; } 

или

 $arr2 = array(); for($i=count($arr1)-1; $i>-1; $i--) { $arr2[$i] = $arr[$i]; } 

(используя обратный цикл в основном потому, что недостаточно людей помнят, что это то, что вы можете сделать, и более эффективно, чем прямой цикл =)

Вы могли бы предположить, что была бы функция array_copy или что-то, что могло бы помочь справиться с приращением экземпляра массива, но, похоже, это не похоже. Это странно, но одно из таких «состояний PHP». Выбор был сделан в прошлом, поэтому в течение нескольких лет PHP жил с этим выбором, поэтому это просто «одна из тех вещей». К сожалению!