2014-09-28 2 views
17

Я столкнулся с этим, казалось бы, очень простым вопросом на днях How to changing value in $array2 without referring $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 и повторите его.

Даже работая через коды операций, я не знаю, где это происходит. У меня есть ощущение отсутствия документации по кодам операций, и моя неопытность в работе с ними, вероятно, не позволяет мне понять, где это происходит.

EDIT 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.

+4

См. Http://php.net/manual/en/language.types.array.php#104064 для чего. «Общие» данные остаются разделенными. –

+2

Это кажется безумным для меня, поскольку вы на самом деле меняете структуру массивов, когда вы назначаете даже его части по ссылке. Плюс, если вы удалите [1] из строки 2, данные, разделяемые данными, не останутся прежними, так что это не совсем так. – mschuett

+1

Начальное назначение - это просто псевдоним. Нельзя начинать манипулировать ими с помощью независимых операций, таких как '... []', которые они вынуждены расходиться. Это, безусловно, «неожиданно», но я бы не стал так говорить, что это «безумно». Хотя я доволен тем, что это был не очень хороший выбор, когда это было сделано, и PHP с тех пор застрял с ним. –

ответ

10

Это объясняется более в 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 жил с этим выбором, поэтому это просто «одна из тех вещей». К сожалению!

+0

спасибо за это ... эта проблема тоже меня прослушивала (с тех пор, как вы увидели оригинальную публикацию в начале недели). Я настоящий новичок с PHP настолько медленный на поглощении, поэтому изучил это немного больше в моем блоге: http://blog.adamcameron.me/2014/09/php-looking-at-some-interesting.html , Я получу правильный конец палки в моем анализе здесь? –

+0

Это хорошая запись и звуки о праве на меня. Прочтите это в Zend и php_net, и посмотрите, не получилось ли это с помощью retweets =) –

+0

@AdamCameron Я написал твиттер в своем сообщении, чтобы посмотреть, можем ли мы немного двигаться по этому поводу. Я думаю, что это было бы потрясающим изменением для PHP 7. – mschuett