Блог


Практическая кинология или вред/польза собачек.

Я с детства боюсь собак. Меня ребенком одна овчарка сильно куснула, до сих пор при виде пса холодок по спине. 

Поэтому неписаное правило в PHP "собака - зло" я принял с энтузиазмом и всячески старался их избегать. Однако в жизни есть куча примеров, когда собаки приносят пользу. Поводыри, спасатели, следопыты, да и просто позитифф. Значит не нужно отрицательно относиться ко всем скопом. 

С недавнего времени я и в программировании пересмотрел для себя некоторые моменты кинологии. Все ли собаки "злые"? Всегда ли их нужно избегать?

Давайте сначала разберемся, от чего программисты их так боятся. Две основополагающие декларации:

1. Подавление ошибок ведет к затруднению дебаггинга.
2. Собачка тормозит выполнение кода.

Начнем с последнего. Даже не вдаваясь в подробности реализации оператора (а я вдавался) можно провести некоторые тесты и убедиться. Сравним инициализацию переменной из POST массива.

1
 2
 3
 4
 5
 6
 7
 8
 9
<?php


    $i 
10000;
    
    while(
$i--)
    {
        
$a = isset($_POST['dummy']) ? $_POST['dummy'] : NULL;
    }

Время исполнения 0.005с

Теперь с собачкой:

1
 2
 3
 4
 5
 6
 7
 8
 9
<?php


    $i 
10000;
    
    while(
$i--)
    {
        
$a = @$_POST['dummy'];
    }

Время выполнения 0.05с

Разница очевидна - собачка работает в 10 раз медленнее. Именно на этом обычно и ставится жирная точка.

Однако давайте посмотрим на ситуацию глубже. Это сродни экономии на туалетной бумаге. Обычная (из макулатуры) стоит примерно 5 рублей за рулон. Крутая навароченная ZEWA в 10 раз дороже - 50 рублей. Покупатель сравнивает и рассуждает "здраво". Зачем мне переплачивать в 10 раз, можно же сэкономить. И берет ту, что может привести к травматизму.

Берет, и тут же покупает пачку сигарет за те же 50 рублей, которую выкурит за день. Так вот, туалетной бумаги хватает на месяц, а значит экономия не 45 рублей, а 45/30 = 1.5 рубля в день, что на фоне ежедневных затрат на то же курево вообще в рамках погрешности. 

Так и тут. Для того, что бы ощутить хоть какое то значимое замедление скрипта, нужно инициализировать таким образом 10000 (десять тысяч!) переменных. Что есть нонсенс. Не говоря уже о том, что при имеющемся в массиве POST элемента 'dummy' (отсутствии подавляемого нотиса) скорость выполнения с собачкой возрастает в 5 раз, а с isset() остается неизменной.

Так что при более подробном рассмотрении ситуации второй пункт не выдерживает никакой критики.

Теперь дальше. 

Да, действительно, собачка затрудняет дебаггинг. Это так. Дело в том, что этот оператор не подавляет ошибку, как многие думают. Он подавляет её вывод на экран и в логи. А сама ошибка так и остается. И её достаточно трудно идентифицировать и устранить. Бесспорно.

Однако ошибка ошибке рознь. Они бывают совершенно разные. И некоторые из них не зависят от скрипта, а некоторые (особенно нотисы) вообще довольно сложно избежать. Допустим такой пример. Мы динамически создаем массив, не зная заранее сколько в нем будет элементов и какие у них ключи. К примеру мы хотим собрать статистику на текущую дату. Мало того, что нам заранее не известна дата, мы так же не знаем, какие элементы на эту дату в исходном массиве присутствуют. Вот такой код

1
 2
 3
 4
 5
 6
 7
 8
 9
 10
<?php


    $time 
date('Y-m-d');
    
$array = array('one''two''three''one''two');

    foreach(
$array as $v)
    {
        
$arr[$time][$v]++;  
    }


неизбежно породит нотис, так как инкрементировать неопределенную переменную по правилам PHP нельзя. Но мы не можем заранее инициализировать массив, так как это в принципе невозможно. Чтобы избежать нотиса, нам придется городить такой огород: 

1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
<?php


    $time 
date('Y-m-d');
    
$array = array('one''two''three''one''two');
    
    foreach(
$array as $v)
    {
        if(!isset(
$arr[$time][$v]))
            
$arr[$time][$v] = 1;
        else
            
$arr[$time][$v]++;  
    } 

 

А можно просто поставить собачку. Это гораздо чище и прозрачнее, легче читается. И абсолютно никак не влияет на дебаггинг.

Или такой пример. Допустим нам нужно узнать наличие и актуальность файла. Это часто используется для кэша. Обычно пишется так:

1
 2
 3
 4
 5
 6
<?php


    
if(!file_exists($file) || filemtime($file) < $time)
    { 
        .....

Всё логично, сначала проверяем наличие файла, потом его актуальность. Но при внимательном изучении кода можно увидеть, что мы два раза обращаемся к файловой системе, что не может не сказаться на оптимальности. А можно воспользоваться собачкой:

1
 2
 3
 4
 5
 6
<?php


    
if($time > @filemtime($file))
    {
        ....

И тут обращение к ФС идет один раз. И нам по сути не важно, недоступен файл или он потерял актуальность. Мы должны принять адекватные меры. А если функция filemtime() вернет false, значит файл недоступен и проверять этого заранее нет смысла - раз, логировать ошибку отсутствия файла в кэше нет смысла - два. А значит собачка тут не только не вредна, но и полезна.

Или еще пример. Нам нужно получить данные из файла на стороннем сервере. Мы не можем проверить или повлиять на его наличие, а значит нет смысла логировать такую ошибку. Мы просто должны адекватно отреагировать - выбросить исключение или иначе этот момент обработать. Тут собачку, что говорится, доктор прописал. 

Кроме того, есть несколько функций, которые ведут себя не совсем адекватно. Допустим mysql_result(). И хотя она уже устарела, для примера пойдет. Она выбрасывает ошибку, если запрос не вернул ни одной строки. По логике она должна вернуть NULL, или false, но никак не варнинг. И тут без собачки как без рук.

Еще похожая ситуация с unlink(). Ну совершенно не обязательно знать, есть ли файл, если мы его все равно собираемся удалять. А она вернет ошибку, если файла нет.

Не буду больше утомлять примерами, их есть и довольно много. Просто знайте, не всякая собака злая, особенно если её погладить. Главное уметь применять их к месту.

Если вы не любите собак, значит вы не умеете их готовить
© Корейская мудрость.

Основные правила, когда нельзя юзать собаку.
1. Когда вы не уверены, какая может быть подавлена ошибка. Из этого второе правило:
2. Нельзя давить ошибки на втором и выше уровнях. Допустим нельзя ставить собачку перед вызовом пользовательских функций или инициализации объектов.
3 Нельзя ставить собаку перед последовательностью операторов, давить можно только локальный участок.
4. Крайне нежелательна собачка в коде, который используется разными приложениями. Допустим в библиотеках. Совершенно неясно, каким образом настроена обработка ошибок там, где либа будет применяться.

И когда можно:
1. Ничего страшного нет в подавлении нотиса при инициализации элементов массива и переменных из элементов суперглобальных массивов.
2. Можно применять этот оператор тогда, когда возможная ошибка не влияет на логику скрипта.
3. Не навредит она, если ошибка обработана собственными средствами. Эксепшенами или своим перехватом.

 Так что любите животных, они не всегда вредны и опасны. Хотя мне больше нравятся коты. 

 

Николай aka twin
Теги: PHP

Комментарии (1)

Vitaly Grakho
28-10-2013
Вот ведь. Витало что-то в моём мозгу, что от собак не только вред, но и польза. Теперь знаю где собака зарыта. Пойду откопаю

 
Наверх