Оценка короткого замыкания 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. Для высокооптимизированного кода необходимо использовать другие способы (например, ручное использование ассемблерного кода)"
Что вы все думаете?
РЕДАКТИРОВАТЬ
Я опросил другой форум и получил там хорошие результаты. По общему мнению, такая форма присвоения переменных, хотя и допустима, не является предпочтительной, и ее даже можно считать плохой формой в реальном мире. Я буду продолжать следить за ситуацией и буду сообщать об этом, если что-нибудь появится. Спасибо Корбину и Мэтту за ваш вклад, особенно Корбину за прояснение некоторых вещей. Вот ссылка на пост на форуме, если вас это заинтересует.
3 ответа
Вы задаете несколько разных вопросов, поэтому я постараюсь ответить на них все.
Пропущенные предсказания ветвлений: если вы не пишете код на C или сборке, не беспокойтесь об этом. В PHP вы настолько далеки от аппаратного обеспечения, что размышления о предсказаниях переходов вам не помогут. В любом случае, это была бы очень микрооптимизация, особенно в функции, которая с самого начала выполняет разбор строк.
Есть ли другая причина не использовать это? Википедия, кажется, так думает, но только в отношении C. Я знаю, что PHP написан на C, так что это определенно важная информация.
PHP, вероятно, анализирует его с другой структурой выполнения. Если вы не планируете запускать эту функцию миллионы раз или не знаете, что это узкое место, я бы об этом не беспокоился. В 2012 году я считаю маловероятным, что использование or
короткое замыкание вызовет даже миллиардную долю секунды.
Что касается форматирования, я нахожу $a or $b
довольно некрасиво Мой разум не понимает короткого замыкания так же, как видит его в предложении if.
if (a() || b())
Мне совершенно ясно, что b() будет выполняться только в том случае, если a() не оценивается как true.
Тем не мение:
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;
}
Конденсируя ваш код в минималистичные строки, вы можете получить его не всегда лучший метод, так как обычно сжатие кода выглядит довольно круто, но обычно его трудно прочитать. Если у вас есть какие-либо сомнения относительно вашего кода и читабельности, я бы посоветовал вам добавить несколько стандартных комментариев в свой код, чтобы любой человек мог понять код только из ваших комментариев.
С точки зрения наилучшей практики, это вопрос мнения, и если вы довольны этим, а затем продолжайте, вы всегда можете вернуться к коду позже, если потребуется
Мне нравятся объявления короткого замыкания, так как это способ проверки однострочных переменных.
Я предпочитаю:
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 не выдает никакой ошибки, когда $key не существует в $data.