Подтвердить что ты не робот

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

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

4b9b3361

Ответ 1

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

"Общие" данные остаются совместно, причем начальное присваивание просто действует как псевдоним. Это происходит только до тех пор, пока вы не начнете манипулировать массивами с помощью независимых операций, таких как ...[] = ..., которые intepreter начинает рассматривать как расходящиеся списки, и даже тогда общие данные остаются разделенными, поэтому вы можете иметь два массива с общими первыми 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 жил с этим выбором в течение нескольких лет в результате, поэтому он просто "один из тех вещей". К сожалению!