вторник, 21 июня 2016 г.

Отличный образчик "индусского" PHP-кода

Работаю периодически на одном зарубежном проекте, дорабатывая функционал легаси-системы. Вчера обнаружил нечто такое, о чем хочется рассказать (заодно и сам в будущем прочитаю, вспомню и порадуюсь =)

Итак, имеется view-ка с большим объемом лапшекода, который схематически имеет следующую структуру (совпадения имен переменных случайны =):
====
...
for ($i = 0; $i < count($data); ++$i) {
     foreach ($data as $data) {
...
...
...

     }
}
====
Внутри данной конструкции  около 100 строк черт знает чего.  Логично предположить, что $data представляет собой массив. При выполнении этой конструкции я (почему-то) ожидал, что она выполнится ровно N^2 раз, где N - размерность массива $data. Но на удивление массив был обработан ровно 1 раз. И именно такое поведение и было правильным.
Я, конечно, стал искать внутри цикла какие-либо присвоения в переменную $i или выходы из цикла по инструкции break, но ни того, ни другого обнаружено не было. Стало интересно... )
И только через какое-то (весьма продолжительное =) время сообразил, почему код ведет себя именно так. Запускается внешний цикл, затем при первом запуске внутреннего цикла внешняя переменная $data перезаписывается присваиванием в нее внутреннего значения (при этом в самом foreach внешняя переменная корректно замыкается и хранит указатель на первоначальный массив $data).
По выходу из foreach() мы имеем в $data последний элемент внешнего массива, который у нас массивом не является, поэтому при проверке условия перед входом во вторую итерацию цикла внешнего for count() возвращает единицу (я так понял, что это стандартное поведение для переменных, не являющихся массивами). В итоге, вход во вторую итерацию внешнего цикла не выполняется (1 не меньше 1) и происходит выход из внешнего цикла. Просто и красиво.
Разумеется, внешний цикл был сразу мной удален и затем произведен небольшой рефакторинг по переименованию переменных для их мало-мальского различия между собой.
Ну и, конечно, остался легкий осадок в виде риторического вопроса: Зачем было писать _так_, если сразу можно было писать понятно ? )