Комментарии 145
Сам на это натыкался. Кстати, в мануале прямо указано — делайте unset. Я даже в фреймворке yii нашел участок кода где есть эта бага.
+12
Да, многие разработчики на этом деле подрывались, и описание этой проблемы действительно есть в мануале.
Но, я не встречал (около года назад) нормального описания этой проблемы на русском языке, что могло сильно попортить нервы молодым разработчикам. Поэтому, автору респект за описание проблемы в доступной форме.
Но, я не встречал (около года назад) нормального описания этой проблемы на русском языке, что могло сильно попортить нервы молодым разработчикам. Поэтому, автору респект за описание проблемы в доступной форме.
+2
НЛО прилетело и опубликовало эту надпись здесь
Не всё, скаляры по значению.
+1
Тьфу, в смысле для скаляров присваивание по значению, а иногда нужна ссылка.
+1
Если эти скаляры длинной меньше длинны указателя, то по значению они будут передаваться быстрее!
0
В общем не найти мне статьи где это подробно расписано, вот вам простейший тест:
// Начальная переменная со строкой в 1000 символов
$a0 = str_repeat('*', 1000);
// Создаем 1000 переменных
extract(range(1, 1000), EXTR_OVERWRITE, 'a');
// Исходное потребление памяти
echo memory_get_usage() . '<br />';
// Копируем по значению
for($i = 1; $i < 1000; $i++) {
${'a' . $i} = $a0;
}
// Память остается прежней
echo memory_get_usage() . '<br />';
// Создаем ту-же строку с нуля
for($i = 1; $i < 1000; $i++) {
${'a' . $i} = str_repeat('*', 1000);
}
// Потребление памяти увеличивается в разы
echo memory_get_usage() . '<br />';
+1
Похоже ваша правда, погонял даже на числах, чтоб не было соблазна написать, что строка это массив символов :)
Правда тест ваш у меня чуть-чуть по другому вёл. extract ввобще объём памяти не изменил (добавил строчку с mem_get_usage и перед ним), а там где «память остаётся прежней» объём вырос, судя по всему на размещение памяти на сами переменные.
Правда тест ваш у меня чуть-чуть по другому вёл. extract ввобще объём памяти не изменил (добавил строчку с mem_get_usage и перед ним), а там где «память остаётся прежней» объём вырос, судя по всему на размещение памяти на сами переменные.
0
Да это я с extract'ом напортачил, префикс работает только когда указан один из ключей EXTR_PREFIX_*, ну и после префикса еще подчеркивание, соот-но правильно будет так:
$a_0 = str_repeat('*', 1000);
extract(array_combine(range(1, 1000), array_fill(1, 1000, null)), EXTR_PREFIX_ALL, 'a');
echo memory_get_usage() . '<br />';
for($i = 1; $i < 1000; $i++) {
${'a_' . $i} = $a_0;
}
echo memory_get_usage() . '<br />';
for($i = 1; $i < 1000; $i++) {
${'a_' . $i} = str_repeat('*', 1000);
}
echo memory_get_usage() . '<br />';
0
Какой знакомый код. Вот тут это писал.
0
Всё всегда передаётся по ссылке, но в случае скаляров, при их изменении, PHP делает копию и изменяет именно её.
+1
Эм… ну я даже затрудняюсь ответить… по назначению? :)
0
В представленном случае очевидно, зачем — чтобы модифицировать элементы массива путем записи в $item.
+1
Тоже наталкивался на эту проблему, для себя взял за правило всегда использовать перебор $key => $value, а изменять используя $items[$key] =…
Сравнивать этот способ со ссылками по производительности — это как экономить на спичках.
С точки зрения читаемости — код чуть длиннее, согласен, но не критично. Зато надёжно!
Сравнивать этот способ со ссылками по производительности — это как экономить на спичках.
С точки зрения читаемости — код чуть длиннее, согласен, но не критично. Зато надёжно!
+10
Была, а не есть.
0
Опять 25.
Вообще-то об этой особенности в мануале написано.
Вообще-то об этой особенности в мануале написано.
+20
Никогда такой конструкцией не пользовался, хоть и пишу достаточно сложный проект, я даже не представляю задач где можно пользоваться присвоением по ссылке. И вообще ссылками в управляемых средах не работаем. Обзор интересен.
-14
Придумал. Может быть для оптимизации какой-нибудь?
+2
Как бы проще объяснить… Это тоже самое, что и этот код:
Заменить на
Сделать можно и так, и так. Однако под каждую задачу есть свои, более оптимальные, конструкции.
switch ($var)
{
case 1:
# some code
break;
case 2:
# one more
break;
case 3:
default:
# code block
break;
}
Заменить на
if ($var == 1)
{
# some code
}
elseif ($var == 2)
{
# one more
}
else
{
# code block
}
Сделать можно и так, и так. Однако под каждую задачу есть свои, более оптимальные, конструкции.
0
Да это понятно. И приведенной вами конструкцией я пользуюсь сразу двумя, так как case не всегда позволяет выполнять требуемые задачи. Но вот с этой ситуацией не очевидно.
Пожалуйста объясните сложнее.
Пожалуйста объясните сложнее.
0
Понятно. Для переборки индексных массивов, включая разряженные.
Мне кажется лучше пользоваться кейвалью, будет очевидней код, что бы он был более унифицирован, а то от оного апперсанда зависит как работает то что внутри.
Мне кажется лучше пользоваться кейвалью, будет очевидней код, что бы он был более унифицирован, а то от оного апперсанда зависит как работает то что внутри.
-4
$array = array('string', 1, '4', 8, 'second', 'word', 12, '42');
function valuesToInt(array $array = array())
{
foreach ($array as &$value)
{
if (!is_int($value))
{
$value = (int) $value;
}
}
return $array;
}
$arrayOnlyIntValues = valuesToInt($array);
0
Дай допишу
unset($value);
-2
Если честно, то сейчас такие конструкции можно заменить на более короткие.
Про особенность работы ссылок в внутри foreach я знаю, но не знаю где это действительно можно применить.
Можно более конкретный и полезный пример?
Про особенность работы ссылок в внутри foreach я знаю, но не знаю где это действительно можно применить.
Можно более конкретный и полезный пример?
0
То же самое можно ещё и так:
Или, для этого конкретного случая, так:
Или сразу на месте:
В этих случаях и читается код так же легко как с foreach, и негативных побочных эффектов нет.
$arrayOnlyIntValues = array_map(function($value) {
if (is_int($value)) {
return $value;
} else {
return (int) $value;
}
}, $array);
Или, для этого конкретного случая, так:
$arrayOnlyIntValues = array_map("intval", $array);
Или сразу на месте:
array_walk($array, function(&$value) {
$value = intval($value);
});
// $array === $arrayOnlyIntValues
В этих случаях и читается код так же легко как с foreach, и негативных побочных эффектов нет.
0
А можно и так:
Можно, конечно, по разному, просто я пытался привести пример использования именно по ключам. С самого начала я сказал, что большинство задач можно решить разными путями, и намеряно привёл путь решения через foreach и ссылки.
$arrayOnlyIntValues = array_map(function($value) {
return (int) $value;
}, $array);
Можно, конечно, по разному, просто я пытался привести пример использования именно по ключам. С самого начала я сказал, что большинство задач можно решить разными путями, и намеряно привёл путь решения через foreach и ссылки.
0
Простая задача — экономия памяти. При передачи по ссылке значение переменной не копируется.
-1
А что имеете в виду под управляемыми средами? Не это?
или это?
Причем переменные объектного типа и объекты в Java — совершенно разные сущности. Переменные объектного типа являются ссылками, то есть неявными указателями на динамически создаваемые объекты.
или это?
Кроме того, в C# решено было перенести некоторые возможности C++, отсутствовавшие в Java: ... передача параметров в метод по ссылке... Также в C# оставили ограниченную возможность работы с указателями
0
Конечно давайте будем растить память! Она ведь и так в php не чиститься от мусора, а мы добьем лежачего :)
-3
> не чиститься от мусора
Поясните.
Поясните.
0
я имел ввиду то что до версии 5.3 в php не было как такого сборщика мусора, а используется подсчёт ссылок, что приводит к утечки памяти при «циклических ссылках».
то-есть:
Однако в PHP 5.3 боле умный сборщик мусора, но срабатывает он только при наполнении буфера ссылок ru.php.net/manual/en/features.gc.performance-considerations.php
тем самым частичка памяти все же утекает(
а что касаетсяКонечно давайте будем растить память! это был сарказм.
то-есть:
$a = 10; // выделяем область в памяти, одна ссылка
$b = $a; // две ссылки
$b = 1; // выделяем вторую область в памяти под значение 1, одна ссылка на 1, одна ссылка на 10
Однако в PHP 5.3 боле умный сборщик мусора, но срабатывает он только при наполнении буфера ссылок ru.php.net/manual/en/features.gc.performance-considerations.php
тем самым частичка памяти все же утекает(
а что касается
0
Видимо, правду говорят, что есть две категории людей — которые понимают указатели и которые не понимают указатели.
+25
Это точно, хотя в PHP они в общем-то простые как 2 + 2. Однако конечно умение ими пользоваться иногда позволяет делать вещи намного эффективнее (но не факт, что понятнее).
+2
Очень важна понятность кода, даже в ущерб производительности, ведь почему люди на ассемблере перестали писать? Почему потом поняли, что лучше функциональное, потом ООП, потом сборка мусора, все для удобства. Люди пользуйтесь указателями в исключительных случаях.
-5
У меня была одна ситуация, когда мне пришлось использовать ссылки — обрабатывалась древовидная структура с неограниченной вложенностью и приводилась к двумерному массиву, причём там ещё были какие-то дополнительные условия, которые использование рекурсии делали невозможным. В общем этот кусок кода разросся бы до неприличных размеров, а ссылками уложился в 30-40 строк.
Подробностей не скажу, давно было. Но реально выручило знание ссылок.
Подробностей не скажу, давно было. Но реально выручило знание ссылок.
+5
Понимание указателей не причем. Для любой переменной справедливо, что если мы её что-то присвоили, то она и будет это содержать, не имеет значения, что в ней было до этого и была ли она до этого объявлена. А тут появляется Вася, который выше твоего кода, не посмотрев на всю портянку, дописал одну строчку, используя то же название переменной. В PHP с указателями очень тяжело.
0
:[|||]:
+1
Боян несусветной давности :)
+2
Поэтому мои переменные всегда имеют вид: yazArray, yazVar, yazItem etc. (:
-23
Страхи какие
+16
$yaPeremenko, $yaObyekteg, $yaMassivcheg…
+34
Знал я одного программиста которы на вопрос «почему для всех переменных ты делаешь префикс?» сказал: «Это мой фирменный знак, моя фишка».
+9
Ну если программист хороший — то почему нет, ради действительно хорошего программиста не жалко будет и кодовые соглашения переписать :)
0
Да щас! Если программист хороший, он не будет изобретать подобные бредовые «фирменные знаки», не несущие никакого смысла. В нормальном коде не место школьным понтам.
+5
О такие вещи реально глаза ломаются.
По-настоящему хороший программист напишет нормальные имена функций, переменных и т.д., а «фирменные префиксы» — это фирменные понты. Видел я таких: перед тем как насрать в код затирают копирайты настоящего автора и меняют толковые имена на фирменную ерунду. Пару раз натыкался на такое — у одного «VasylFunction», у другого «OlegFunction». Убил бы обоих. Случаи, когда это можно простить — древние CMS-ки, в которых всё в куче и условие if-else расписано на полторы тысячи строк.
По-настоящему хороший программист напишет нормальные имена функций, переменных и т.д., а «фирменные префиксы» — это фирменные понты. Видел я таких: перед тем как насрать в код затирают копирайты настоящего автора и меняют толковые имена на фирменную ерунду. Пару раз натыкался на такое — у одного «VasylFunction», у другого «OlegFunction». Убил бы обоих. Случаи, когда это можно простить — древние CMS-ки, в которых всё в куче и условие if-else расписано на полторы тысячи строк.
+2
хорошо что не yaaaaazArray, yaaaaaazVar…
+11
В бывшей фирме я встретился с конвенцией поименования переменных:
l (local), p (private), итд… + a (array), s (string), i (integer), итд… + + название…
Ну и потом количество рогов скота выглядело примерно: $pirog.
Очень сильно помогало понимать, что находится в коде и какого типа данные.
l (local), p (private), итд… + a (array), s (string), i (integer), итд… + + название…
Ну и потом количество рогов скота выглядело примерно: $pirog.
Очень сильно помогало понимать, что находится в коде и какого типа данные.
+1
Это называется венгерская нотация.
При наличии современных IDE с code completion смысла в её использовании лично я не вижу.
При наличии современных IDE с code completion смысла в её использовании лично я не вижу.
+2
Уже очень давно пользуюсь такой системой именования переменных. Действительно укоряет понимание кода.
-1
Так давно известно же
+2
Использовать var_dump, вместо print_r, и обращать внимание на амперсанд. Чтобы дампить в файл, а не в браузер, альтернативой print_r($var,true) будет такая конструкция:
Есть функция var_export, делает как раз то что вы хотите
var_export($var,true)
Второй параметр аналогичен параметру в print_r возвращает содержимое а не печатает в буфер.
Единственное отличие, принимает только один параметр, когда var_dump принимает бесконечное кол-во параметров
+2
Функция var_export нужна для преобразования структуры данных в php-код, формирующий эти данные. Она может быть полезна, например, при обработке конфигов. В var_dump же можно увидеть тип данных и тот самый амперсанд, означающий, что данные используются кем-то еще.
+1
В print_r тоже второй необязательный параметр, который указывает возвращать или выводить данные.
0
Как много людей указывают на то, что это давно известно, да еще и не раз обсуждалось. Ну раз еще раз всплыло, значит может быть действительно проблема есть?
В каком еще языке вы не можете знать, что произойдет с переменной, когда вы присвоите ей значение?
В Си во-первых, все переменные нужно объявлять, поэтому вздумай вы использовать переменную item в качестве указателя вы пойдете её объявить и увидите, что такая уже есть. Во-вторых там даже положив в указатель число и проведя арифметические операции, его можно безопасно извлечь, потому что для доступа к тому, куда указывает указатель используется специальный синтаксис.
В питоне и яваскрипте указателей вообще нет.
Php — самый опасный язык для работы с указателями, или я что-то упускаю?
В каком еще языке вы не можете знать, что произойдет с переменной, когда вы присвоите ей значение?
В Си во-первых, все переменные нужно объявлять, поэтому вздумай вы использовать переменную item в качестве указателя вы пойдете её объявить и увидите, что такая уже есть. Во-вторых там даже положив в указатель число и проведя арифметические операции, его можно безопасно извлечь, потому что для доступа к тому, куда указывает указатель используется специальный синтаксис.
В питоне и яваскрипте указателей вообще нет.
Php — самый опасный язык для работы с указателями, или я что-то упускаю?
+3
Не будьте столь категоричным. В любом языке есть свои нюансы, хорошие и плохие стороны, начинающие и опытные разработчики.
-1
Меня реально заколебали ответы «у дргих еще хуже». И в политике и в повседневной жизни. Как вообще может прийти в голову считать это аргументом?
+8
В php любая переменная — это указатель. При присваивании или передаче, новая переменная становится указателем на те же данные, а у данных увеличивается счетчик ссылок на них. При изменении одной из переменных, для нее создается копия данных. Амперсанд относится не к переменной, а к выполняемой операции (прямого или косвенного присваивания). Он означает, что при изменении переменной-приёмника не будет создаваться копия, а данные будут изменяться в источнике. В этом плане php работает хорошо и никому обычно не мешает. Однако, разработчики, вероятнее всего, изучавшие программирование на примере Си, часто не знают об этой особенноси php, и не учитывают её при составлении скриптов. Так возникают баги, подобные описанному.
+2
Что-то изменилось с тех пор как я разбирался с этим и в мане врут?
По умолчанию, переменные всегда присваиваются по значению. То есть, когда вы присваиваете выражение переменной, все значение оригинального выражения копируется в эту переменную.
0
Тут про «copy on write», значение (в нутрях php, в zend engine), копирует только когда это действительно необходимо, иже когда оно изменяется, а так если иметь 10к переменных с одинаковым значением (скопировав их с какого-то одного) — память будет потребляться только на сами структуры переменных. И в мане кстати все ок, в мане про это знают :)
0
Насколько я знаю к скалярным типам это не относится, только массивы и объекты. Нет?
0
Почему, это в первую очередь к скалярным типам и относится, ну и к массивам, а объекты всегда передаются по ссылке, они с copy on write никак не связаны, при наличии двух ссылок на объект и изменении объекта в одной — копия создана не будет.
0
Блин да достали вы со своими скалярами :) Они не просто так по значению передаются. Это тоже оптимизация ;)
0
Отписался по поводу скаляров выше: habrahabr.ru/blogs/php/136835/?reply_to=4554710#comment_4554800
0
На хабре есть хорошая статья про это.
0
Я бы дал ссылку на www.php.net/manual/ru/features.gc.refcounting-basics.php
Там все хорошо написано.
Там все хорошо написано.
0
Как эта особенность проявляется внешне, и как она связана с обсуждаемой проблемой?
0
В .NET есть указатели, но ими я помню очень редко пользовался, в основном, что бы перейти на нативный уровень, блокировав сборщик мусора. И то там были проблемы — например char в .NET 16 разрядный. Не надо пользоваться в управляемых языках указателями.
-3
foreach ($newitems as $key=>$item)
обещали сделать deprecated -1
Что конкретно из этого? Весь foreach? $key=>$item?
+1
Рекомендуется конструкция
foreach ($array => &$item)
0
вместо => as конечно же.
-1
Круто, а как же быдлоконструкция if(!$key) echo 'br';?
0
Это только в планах. Может быть, планы изменились, я плохо следил последнее время. Без $c as $b=>$c ключ нормальными способами не вытащить сейчас.
-1
«ключ нормальными способами не вытащить сейчас»
Иногда, когда мне нужны только ключи и обход по ним, делаю foreach (array_keys($items) as $key) {}
Чем этот способ плох?
Иногда, когда мне нужны только ключи и обход по ним, делаю foreach (array_keys($items) as $key) {}
Чем этот способ плох?
0
А если и то и то?
// Думаю конструкция выше может быть deprecated только в пользу ArrayIterator.
// Думаю конструкция выше может быть deprecated только в пользу ArrayIterator.
+1
То есть ключи не рекомендуются? В манах что-то ничего не нашёл.
0
Предпочитаю всё unset'ить как только отпала надобность, чтоб не переживать.
0
Мне бы было лень, я тупо не юзаю переменные из-за скобок (только для «передачи» параметров беру из-за скобки), а если надо то практически всегда это отдельная сущность, которая выносится в метод.
0
Когда пишешь unset для каждой переменной, консольный демон практически не течет, так что очень рекомендую. Тем более в СИ программист сам следит за памятью, что в PHP и подразумевается, но почему то, никто этого не делает.
0
1. Это не баг, а вполне разумное и ожидаемое поведение.
2. Всегда надо чистить пространство имён с помощью unset, особенно тогда, когда используете передачу по ссылке. Не заботиться о чистке можно только тогда, когда у вас сразу после этого заканчивается область видимости, но и тогда лучше поставить unset на случай последующих доработок.
2. Всегда надо чистить пространство имён с помощью unset, особенно тогда, когда используете передачу по ссылке. Не заботиться о чистке можно только тогда, когда у вас сразу после этого заканчивается область видимости, но и тогда лучше поставить unset на случай последующих доработок.
+1
На самом деле беда в том, что у PHP слишком долгая память переменных… по уму — за блоком foreach $item уже не должна быть определена (что и делается в других, более строгих языках). Хочешь сохранять — делай это явно, вот и вся история ;-)
+14
Только это не долгая память переменных называется, а область видимости %) А так да, в пхп как всегда отличились.
+2
В С++ разве не аналогично? Переменная объявленная в цикле for имеет область видимости до конца функции?
0
В C вроде как каждый блок {} имеет свою область видимости, то есть если объявить переменную прямо внутри цикла — то она заменит собой переменную объявленную извне, но только внутри цикла.
+2
Вот вот. И это очень правильно! Поэтому в таких языках не нужны костыли в виде unset.
+1
Ну php проектировался с одной главной идеей — он должен быть простым языком, понятным всем, а блочные области видимости это довольно таки сложно для понимания новичка.
P.S. не удивлюсь если лет через 100 на нём разговаривать начнут, вместо теперешнего эсперанто :)
P.S. не удивлюсь если лет через 100 на нём разговаривать начнут, вместо теперешнего эсперанто :)
+1
В C вроде вообще переменные объявляются только в контексте программы или функции, да ещё в самом начале функции. А вот в C++ допустимо, например, for(int i=0; i<10; i++) {… } и тут переменная объявлена вне {} цикла.
0
В C можно объявлять переменные в начале любого блока, а не только функции. А в С99 их можно объявлять в любом месте, так же как и в C++, в т.ч. и условиях.
Далее, конструкция for(int i=0; i<10; i++) {… } все же объявляет i только в пределах цикла.
Далее, конструкция for(int i=0; i<10; i++) {… } все же объявляет i только в пределах цикла.
+1
В C переменные можно объявлять в начале абсолютно любого блока, будь то тело функции, тело цикла или просто блок внутри другого блока (очень удобный лайфхак, когда нужна временная переменная, однако не хочется выносить ее в начало функции)…
+1
В С++ не силен, но в том же компиляторе от microsoft есть возможность выбора поведения. А по этой ссылке: docs.freebsd.org/info/g++FAQ/g++FAQ.info.for_scope.html написано что в gcc теперь имеет область до конца цикла.
0
+27
Поэтому надо делать всегда так
foreach ($items as $key=>$item) {
$items[$key] += 2;
}
foreach ($items as $key=>$item) {
$items[$key] += 2;
}
+6
На больших значениях в массиве рискуете серьезно потратится на память, как минимум на объем самой структуры массива.
0
А разве $items[$key] это не та же ссылка?
+2
Нет.
0
Ну в таком случае вероятность ниже написать $item[$key] =… намного ниже чем просто $item
0
Вы не поняли. После цикла за скобками останется в силе последние значения $items и $key. Соответственно если написать $items[$key] = «12» то вы перепишете последний элемент массива
0
Полагаю что всё же наоброт.
Я не говорю про то, как и где можно что-то перезаписать. Как я сказал в этом комментарии, при использовании подхода:
foreach ($items as $key=>$item) {
$items[$key] += 2;
}
увеличивается потребление памяти.
Еще раз: ничего про присвоение переменных за скобками цикла я не говорил.
А то что написали вы — очевидно, правда с уточнением, что остается только переменная $key, которая была записана в последней итерации. Массив $items уже был. Ничего «багнутого» тут нет.
Я не говорю про то, как и где можно что-то перезаписать. Как я сказал в этом комментарии, при использовании подхода:
foreach ($items as $key=>$item) {
$items[$key] += 2;
}
увеличивается потребление памяти.
Еще раз: ничего про присвоение переменных за скобками цикла я не говорил.
А то что написали вы — очевидно, правда с уточнением, что остается только переменная $key, которая была записана в последней итерации. Массив $items уже был. Ничего «багнутого» тут нет.
0
array_walk($arr, function(&$value){
$value+=2;
});
Или так :)
$value+=2;
});
Или так :)
0
НЛО прилетело и опубликовало эту надпись здесь
Когда-то сталкивались в реальных условиях, конечно был бы функциональный тест, проблему бы заметили, а так проморгали. Вообще "&" где его можно не использовать, лучше не использовать.
0
даже в Smarty есть этот баг.
{foreach item=param from=$params}
{$param}
{/foreach}
а после завершения {foreach} переменная {$param} остаётся. Если уже раньшще была определена {$param} — она изменяется.
{foreach item=param from=$params}
{$param}
{/foreach}
а после завершения {foreach} переменная {$param} остаётся. Если уже раньшще была определена {$param} — она изменяется.
-5
foreach($new as $key => $value)
$new[$key] = $value+2;
Так делал с первого дня, не так красиво — зато без багов.
+1
Используйте чаще array_map
+2
Вот при работе с встроенными функциями array_map действительно хорош, а при вызове пользовательских идут расходы на смену контекста выполнения, для задачи вроде $a += 2 — это имхо неоправданные траты.
0
Я вам больше скажу. При работе с кастомными массивами (Traversable) вам такой перебор вообще не поможет изменять данные. Надо всегда быть готовым вместо любого массива использовать Traversable, поэтому стоит ограничивать функционалом, который поддерживается как настоящими массивами, так и кастомными. До тех пор, пока команда разработчиков PHP не доведет поддержку кастомных массивов до того же уровня, что и нативных.
0
в любом случае, спасибо огромное!
0
Спасибо за статью! Только сейчас столкнулся на аналогичный баг, вспомнил про статью и нашел решение проблемы :)
0
!!! Важно, данная бага вылезает не на всех версиях ПХП. Недавно при переносе класса с девелоп на продакшн — вылезла эта бага! Причем на девелопе все работало стабильно без нареканий, на продакшне был крайне удивлен. Огромное спасибо за статью, хорошо, что я ее читал и сразу вспомнил про нее, низко кланяюсь. На девелопе и продакшене стоит 5ка.
+1
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Подводный камень в foreach($items as &$item)