LINUX.ORG.RU

Странное поведение PHP


0

1
#!/usr/bin/env php
<?php

$items = array();
for ($i = 0; $i < 5; $i++) {
	$items[] = array(
		'id' => $i,
	);
}

foreach ($items as &$item) {}

print_r($items);

foreach ($items as $item) {
	echo "PROCESSING => {$item['id']}\n";
}
$ ./test.php 
Array
(
    [0] => Array
        (
            [id] => 0
        )

    [1] => Array
        (
            [id] => 1
        )

    [2] => Array
        (
            [id] => 2
        )

    [3] => Array
        (
            [id] => 3
        )

    [4] => Array
        (
            [id] => 4
        )

)
PROCESSING => 0
PROCESSING => 1
PROCESSING => 2
PROCESSING => 3
PROCESSING => 3

Что происходит в последней итерации последнего foreach?



Последнее исправление: tazhate (всего исправлений: 1)

А какое назначение у этой строки:

foreach ($items as &$item) {}

Если ее удалить, то все работает верно.

amomymous ★★★
()
Ответ на: комментарий от amomymous

А какое назначение у этой строки

Код сокращён до минимума как и рекомендуется для баг репорта. Если вместо &$item написать просто $item так же проблема снимается. Однако вопрос - что происходит, и почему именно на последней итерации?

tyler19
() автор топика
Ответ на: комментарий от aol

думаю, ответ надо искать тут, тут и тут

Нигде нет прямого ответа. Если знаете напишите тут, а гуглом я также умею пользоваться. Речь по ссылкам вообще идёт о другом.

tyler19
() автор топика
Ответ на: комментарий от tyler19

Режим телепата включен

&$item как я понимаю это присвоение по ссылке. Возможно после завершения строки «foreach ($items as &$item) {}» $item по прежнему указывает на элемент в массиве $items и не происходит очистка памяти. Если мы убираем амперсанд то происходит передача по значению и возможно уже в момент захода, в цикл внутренняя переменная освобождается. Возможно стоит попробовать ручной unset для переменной $item в конце итерации или после завершения цикла

Jaberwock ★★★
()

так работает

$items = array(); for ($i = 0; $i < 5; $i++) { $items[] = array( 'id' => $i, ); }

foreach ($items as &$item) {} unset($item); print_r($items);

foreach ($items as $item) { echo «PROCESSING => {$item['id']}\n»; }

Jaberwock ★★★
()
Ответ на: комментарий от Jaberwock

Да я понимаю что после завершения цикла $item указывает на последний элемент. Но разве же в следующем цикле этой переменной не присваивается другое значение? Это чистой воды БАГ.

tyler19
() автор топика
Ответ на: комментарий от tyler19

Это чистой воды БАГ.

Это чистой воды твоё непонимание, что такое ссылки.

Если ты создал ссылку, то дальнейшие присваивания этой ссылочной переменной будут вести к тому, что ты изменяешь переменную, на которую эта ссылка ссылается.

То, что ты сделал, эквивалентно этому коду:

$item = &$items[4];
foreach ($items as $item) {
	echo "PROCESSING => {$item['id']}\n";
}

Что, в свою очередь, будет эквивалентно

foreach ($items as &$items[4]) {
	echo "PROCESSING => {$items[4]['id']}\n";
}

На каждой итерации цикла значение $items[4] будет переписано текущим элементом. Всё логично.

К слову, C++ будет себя вести так же:

#include <iostream>

static int a[4] = { 0, 1, 2, 3 };

int main(int, char**)
{
        int& item = a[3];

        for (std::size_t i=0; i<4; ++i) {
                item = a[i];
                std::cout << i << " => " << item << "\n";
        }

        return 0;
}

sjinks ★★★
()

это ж надо так любить язык! (я об имени скрипта)

comp00 ★★★★
()
Ответ на: комментарий от tyler19

Было бы логично переменные-ссылки выделить в отдельное пространство имён что бы избежать такой путаницы где всё выглядит не очевидно. Например использовать другой префикс для таких переменных.

tyler19
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.