Оценка короткого замыкания PHP (Хорошо/плохо?)


Это своего рода общий вопрос, но для его объяснения я приведу конкретный пример.

У меня есть функция, которая загружает документ. Если этот документ не существует, он создаст его, если он существует, он преобразует его в массив JSON. Я всегда хочу, чтобы эта функция возвращала какой-либо массив, независимо от того, есть ли проблема с json_decode() или если файл не существует. В настоящее время я делаю это так...

function load($file) {
    if( ! file_exists($file)) {
        $handle = fopen($file, 'w');
        fclose($handle);
    }

    $raw = file_get_contents($file);
    $contents = json_decode($raw, TRUE);

    return( ! $contents ? array() : $contents);
    //cant use ternary shorthand "?:" in PHP 5.2, otherwise this would be shorter
}

Теперь в приведенном выше коде нет ничего плохого (в по крайней мере, я не думаю, что есть, и это прекрасно работает). Однако я всегда ищу способы улучшить свой код и сжать его, сохраняя при этом его совершенно разборчивым. И это заявление о возврате всегда беспокоило меня из-за того, насколько неэффективным оно кажется. Так что сегодня я задумался, и мне кое-что пришло в голову. Я помню, что видел учебные пособия по mysql, которые делают что-то с эффектом connect() or die();, поэтому я подумал, почему бы и нет json_decode() or array();? Сработает ли это вообще? Поэтому я переписал свою функцию, чтобы узнать...

function load($file) {
    if( ! file_exists($file)) {
        $handle = fopen($file, 'w');
        fclose($handle);
    }

    $raw = file_get_contents($file);
    return json_decode($raw, TRUE) or array();
}

Похоже, что, и это даже читается достаточно приятно. Итак, перейдем к моей следующей серии вопросов. Это хорошая практика? Я это понимаю, но понял бы кто-нибудь другой? Это действительно работает или это какая-то ошибка со счастливым концом? Я осмотрелся и обнаружил, что то, о чем я спрашиваю, называется оценкой короткого замыкания, а не ошибкой. Это было приятно знать. Я использовал этот новый термин, чтобы уточнить свой поиск, и нашел еще несколько материалов.

Запись в Блоге

Википедия

Там было не так много, и почти все, что я нашел, говорило об использовании короткого замыкания так, как я спрашиваю, всегда относилось к подключениям MySQL. Теперь я знаю, что большинство людей против использования терминологии or die(), но только потому, что это неэлегантный способ борьбы с ошибками. Это не проблема для метода, о котором я спрашиваю, потому что я не стремлюсь использовать or die(). Есть ли какая-либо другая причина не использовать это? Википедия, похоже, так думает, но только в отношении C. Я знаю, что PHP написан на C, так что это определенно относящаяся к делу информация. Но была ли эта проблема устранена в компиляции PHP? Если нет, то так ли это плохо, как это изображает Википедия?

Вот фрагмент из Википедии.

Википедия - "Короткое замыкание может привести к ошибкам в прогнозировании ветвей на современных процессорах и резко снизить производительность (заметным примером является высокооптимизированный луч с кодом пересечения прямоугольников, выровненным по оси, в трассировке лучей) [требуется разъяснение]. Некоторые компиляторы могут обнаруживать такие случаи и выдавать более быстрый код, но это не всегда возможно из-за возможных нарушений стандарта C. Высокооптимизированный код должен использовать для этого другие способы (например, ручное использование ассемблерного кода)"

Что вы все думаете?

РЕДАКТИРОВАТЬ

Я опросил другой форум и получил там хорошие результаты. Общий консенсус, по-видимому, заключается в том, что эта форма присвоения переменных, хотя и действительна, не является предпочтительной и может даже считаться дурным тоном в реальном мир. Я буду продолжать держать ухо востро и обновлю это, если появится что-то новое. Спасибо Корбину и Мэтту за ваш вклад, особенно Корбину за прояснение некоторых вещей. Здесь ссылка на сообщение на форуме, если вам будет интересно.

Author: mseancole, 2012-05-09

3 answers

Вы задаете несколько разных вопросов, поэтому я постараюсь ответить на них все.

Пропущенные предсказания ветвей: Если вы не кодируете на C или сборке, не беспокойтесь об этом. В PHP вы так далеки от аппаратного обеспечения, что размышления о предсказаниях ветвей вам не помогут. В любом случае, это была бы очень мелкая оптимизация, особенно в функции, которая для начала выполняет обширный синтаксический анализ строк.

Есть ли какая-либо другая причина не использовать это? Википедия кажется, я так думаю, но только в отношении С. Я знаю, что PHP написан на C, так что это определенно соответствующая информация.

PHP, вероятно, анализирует его в другой структуре выполнения. Если вы не планируете запускать эту функцию миллионы раз, или вы знаете, что это узкое место, я бы не беспокоился об этом. В 2012 году я нахожу очень маловероятным, что использование or для короткого замыкания вызовет даже миллиардную долю секунды разницы.

Что касается форматирования, я нахожу $a or $b скорее уродливый. Мой разум не понимает короткого замыкания так же, как он видит его в предложении if.

if (a() || b())

На мой взгляд, совершенно ясно, что b() будет выполняться только в том случае, если a() не соответствует истине.

Однако:

return a() or b();

Для меня не имеет такой же ясности.

Очевидно, что это всего лишь мнение, но я предложу две альтернативы относительно того, как я мог бы это написать (которые, на мой взгляд, немного понятнее):

function load($file) {
    if (!file_exists($file)) {
        touch($file);
        return array();
    }

    $raw = file_get_contents($file);

    $contents = json_decode($raw, true);

    if (is_array($contents)) {
        return $contents;
    } else {
        return array();
    }

}

Если вам все равно, действительно ли файл получает созданный, вы могли бы сделать еще один шаг вперед:

function load($file) {

    $raw = file_get_contents($file);

    if ($raw !== false) {
        $contents = json_decode($raw, true);
        if ($contents !== null) {
            return $contents;
        }
    }

    return array();

}

Я думаю, что на самом деле эти фрагменты кода сводятся к личным предпочтениям. Второй фрагмент, скорее всего, тот, с которым я бы пошел. Критические пути могли бы быть в нем немного яснее, но я чувствую, что он сохраняет краткость, не жертвуя понятностью.

Изменить: Если вы являетесь человеком с 1 возвратом на функцию, следующее может быть немного предпочтительнее:

function load($file) {

    $contents = array();

    $raw = file_get_contents($file);

    if ($raw !== false) {
        $contents = json_decode($raw, true);
        if ($contents === null) {
            $contents = array();
        }
    }

    return $contents;

}
 2
Author: Corbin, 2012-05-08 22:01:31

Сжатие кода в максимально минималистичные строки, которые вы можете получить, не всегда является лучшим методом, так как обычно сжатие кода выглядит довольно круто, однако обычно его трудно читать. Если у вас есть какие-либо сомнения по поводу вашего кода и удобочитаемости, я бы посоветовал вам добавить в свой код несколько стандартных комментариев, чтобы любой человек мог понять код только из ваших комментариев.

С точки зрения наилучшей практики, это вопрос мнения, и если вы довольны этим, то следуйте ему, вы можете всегда возвращайтесь к коду позже в течение жизни проекта, если это необходимо

 1
Author: Matt, 2012-05-08 21:53:16

Мне нравятся объявления короткого замыкания, так как это способ проверки однострочных переменных.

Я предпочитаю:

isset($value) or $value = 0;

Вместо:

if (!isset($value)) {
  $value = 0;
}

Но я не использовал его напрямую в возвратах, и этот пост вызвал желание попробовать.

И, к сожалению, это не работает должным образом, по крайней мере, для меня:

return $data[$key] or $data[1];

Вернет значение 1 во всех случаях, пока я ожидаю массив.

Следующее работает гладко:

// Make sure $key is valid.
$data[$key] or $key = 1;

return $data[$key];

Но я удивлен, что PHP не бросает никаких ошибка, когда $ключ не существует в $данных.

 0
Author: ErikaW, 2014-09-04 09:19:40