Знак собаки @ і придушення помилок в php несподіваний результат для array_walk

Якось зіткнувся з цікавою проблемою: при обробці масивів функцією викликаної командою array_walk. замість того, щоб перевіряти наявність масиву, вирішив придушити повідомлення помилки, якщо масиву немає. Як то кажуть, на нема й суду нема. Масив ні обов'язковою частиною даних, він міг бути створений в результаті дії попереднього коду, а міг і не бути, в залежності від різних умов. При наявності, масив оброблявся, при відсутності видавалося повідомлення про помилку. Ось я і вирішив не перевіряти існування масиву, а поставити в array_walk собаку, щоб спростити код.

Я був сильно здивований, коли виявив, що масив перестав оброблятися.

Пропоную подивитися цей тестовий код:

Спочатку я пишу error_reporting (E_ALL). щоб незалежно від налаштувань сервера, бачити помилки PHP. Далі я створюю функцію, приєднується слово до елементу масиву. При чому, оскільки масив передається по посиланню, функція повинна змінювати цей масив, а не передали їй копію. Але, про всяк випадок (краще перебдеть, ніж недобдеть), роблю з функції перевірки висновок на екран.

Далі я створюю 3 тестових масиву з набором слів і для кожного з них викликаю функцію обробки командою array_walk. Але в першому випадку я використовую array_walk в чистому вигляді, а в двох наступних використовую придушення повідомлення про помилку, якщо зазначеного масиву не існує. При цьому в одному варіанті я ставлю собаку перед викликом функції, а в іншому перед ім'ям масиву. Спочатку мені здалося, що це дає однаковий результат. Для перевірки я вивів вміст масивів після обробки всередині блоку

.

А потім, тим же чином, яким викликав обробку існуючих масивів, викликав обробку неіснуючих, щоб подивитися, чи дійсно повідомлення про помилку пригнічується.

І я отримав такий результат:

Усередині функції drink все йшло за планом. PHP готовий був пити і чай, і молоко, і навіть пиво. По крайней мере, висновок на екран всередині функції відповідав очікуваному. Але на ділі виявилося, що він Філон і потайки виливає віскі під стіл, бо при перевірці масиву через print_r. слово "пити» не підписували, ні до пива, ні до віскі.

Чому так відбувається, мені абсолютно незрозуміло. Адже всередині функції все виглядало чудово незалежно від положення собаки при виклику.

Далі послідувала перевірка придушення помилки. Виклик обробки неіснуючого масиву без собаки цілком очікувано видав повідомлення про помилку "аргумент повинен бути масивом". Виклик обробки, попереджання собакою, очікувано промовчав про помилку. А ось що буде при виклику з собакою перед масивом, заздалегідь не було відомо. Чи то PHP буде ньому, як риба, тому що про масиві йому говорити заборонено, то почне скаржитися, що аргумент повинен бути масивом. Виявилося, скаржиться. Скаржиться, якщо масиву немає. Симулює обробку, якщо масив є. Тобто, приміщення собаки перед масивом не тільки не відключає повідомлення про помилку, а й саме викликає помилку при обробці даних.

Тільки приміщення собаки перед викликом функції дає бажаний результат: якщо масив є, він обробляється, якщо його немає, PHP мовчки проходить повз.

На останок хочу додати, що замість array_walk в більшості випадків краще використовувати array_walk_recursive. який обробить не тільки прості масиви, а й багатовимірні з усіма їх рівнями укладення. Краще використовувати array_walk_recursive відразу, ніж потім, в разі зміни масиву, перевіряти, обробляється чи він рекурсивно.