Удалит. Но в цикле ты его все равно обработаешь.
У меня была задача такого плана: список структур, которые надо было сгруппировать по некому признаку. Получился вложенный цикл. Во внутреннем цикле я помечал элементы удаленными (сперва я тоже пытался делать unset), чтобы не обработать их повторно. Оказалось, что $list[$k] видит изменение значений, а foreach, в котором сейчас находишься, не видит.
Проблема решается как и в первом посте: использованием ссылок в цикле. И не забываем удалить ссылку после цикла.
Вариант без ссылок:
$list = array(
    array('type' => 1, 'val' => 5),
    array('type' => 2, 'val' => 10),
    array('type' => 1, 'val' => -2),
    array('type' => 3, 'val' => 20),
);
foreach ($list as $key => $item) {
    echo "Fetch: {$item['type']}, {$item['val']}: ";
    if (!empty($list[$key]['deleted'])) {
        echo "skip\n";
        continue;
    }
    echo "continue\n";
    $list[$key]['deleted'] = 1;
    foreach ($list as $key2 => $item2) {
        if (!empty($list[$key2]['deleted']))
            continue;
        if ($item2['type'] != $item['type'])
            continue;
        $list[$key]['val'] += $item2['val'];
        $list[$key2]['deleted'] = 1;
    }
}
foreach ($list as $item)
    printf("%1u %3d %1u\n", $item['type'], $item['val'], !empty($item['deleted']));
/*
Fetch: 1, 5: continue
Fetch: 2, 10: continue
Fetch: 1, -2: skip
Fetch: 3, 20: continue
1   3 1
2  10 1
1  -2 1
3  20 1
*/
Вариант с ссылками:
$list = array(
    array('type' => 1, 'val' => 5),
    array('type' => 2, 'val' => 10),
    array('type' => 1, 'val' => -2),
    array('type' => 3, 'val' => 20),
);
foreach ($list as &$item) {
    echo "Fetch: {$item['type']}, {$item['val']}: ";
    if (!empty($item['deleted'])) {
        echo "skip\n";
        continue;
    }
    echo "continue\n";
    $item['deleted'] = 1;
    foreach ($list as &$item2) {
        if (!empty($item2['deleted']))
            continue;
        if ($item2['type'] != $item['type'])
            continue;
        $item['val'] += $item2['val'];
        $item2['deleted'] = 1;
    }
}
unset($item);
foreach ($list as $item)
    printf("%1u %3d %1u\n", $item['type'], $item['val'], !empty($item['deleted']));
/*
Fetch: 1, 5: continue
Fetch: 2, 10: continue
Fetch: 1, -2: skip
Fetch: 3, 20: continue
1   3 1
2  10 1
1  -2 1
3  20 1
*/
Добавлено через 10 часов, 36 минут и 50 секунд:У меня получилось такое заключение:
Форма "foreach (list as val)" создает временную копию массива с копиями значений.
Форма "foreach (list as &val)" не создает копию массива со ссылками на исходные значения.Но проверка работы лимитов памяти не подтверждает, а еще больше запутывает.
Пример. В настройках memory_limit = 128M. Смысл теста в том, чтобы создать условия, когда на копию объекта не хватит памяти.
$memsize = 128 * 1024 * 1024;
$list = array(
    str_repeat('1', $memsize * 0.4),
    str_repeat('1', $memsize * 0.4)
);
foreach ($list as $v) {
    echo strlen($v), "\n";
}
Как ни странно, тест проходит. А вот этот падает на строке 8.
- $memsize = 128 * 1024 * 1024; 
- $list = array( 
-     str_repeat('1', $memsize * 0.35), 
-     str_repeat('1', $memsize * 0.35) 
- ); 
-   
- foreach ($list as &$v) { 
-     echo strlen($v), "\n"; 
- } 
И вот еще интересный аспект влияния цикла на время жизни объекта.
- class X 
- { 
-     private $name; 
-   
-     public function __construct($name) { 
-         $this->name = $name; 
-         echo "++ $this->name\n"; 
-     } 
-   
-     public function __destruct() { 
-         echo "-- $this->name\n"; 
-     } 
- } 
-   
- $list = array(new X('old_1'), new X('old_2')); 
-   
- foreach ($list as $k => $v) { 
- //    $list[$k] = null; 
-     $list[$k] = new X('new_' . ($k + 1), 0); 
- } 
Строка 18 не влияет на результат: объекты будут уничтожены после цикла, по завершению программы:
++ old_1
++ old_2
++ new_1
++ new_2
-- old_1
-- old_2
-- new_1
-- new_2Скажу более: если обнуление заменить на unset(), то результат также не изменится.
- class X 
- { 
-     private $name; 
-   
-     public function __construct($name) { 
-         $this->name = $name; 
-         echo "++ $this->name\n"; 
-     } 
-   
-     public function __destruct() { 
-         echo "-- $this->name\n"; 
-     } 
- } 
-   
- $list = array(new X('old_1'), new X('old_2')); 
-   
- foreach ($list as $k => &$v) { 
- //    $list[$k] = null; 
-     $list[$k] = new X('new_' . ($k + 1), 0); 
- } 
А здесь влияет. Без "обнуления": создается новый объект, после чего уничтожается старый.
++ old_1
++ old_2
++ new_1
-- old_1
++ new_2
-- old_2
-- new_2
-- new_1С "обнулением": сперва уничтожается старый, потом создается новый.
++ old_1
++ old_2
-- old_1
++ new_1
-- old_2
++ new_2
-- new_1
-- new_2А если тут применить unset(), то присвоение в строке 19 добавляет элемент в массив в конец списка, что приводит к дополнительной итерации цикла, в которой добавляется еще один элемент и т.д. Т.е. с такой формой цикла массив можно использовать как самопополняемую очередь заданий.