Оценка короткого замыкания 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 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;
}
Сжатие кода в максимально минималистичные строки, которые вы можете получить, не всегда является лучшим методом, так как обычно сжатие кода выглядит довольно круто, однако обычно его трудно читать. Если у вас есть какие-либо сомнения по поводу вашего кода и удобочитаемости, я бы посоветовал вам добавить в свой код несколько стандартных комментариев, чтобы любой человек мог понять код только из ваших комментариев.
С точки зрения наилучшей практики, это вопрос мнения, и если вы довольны этим, то следуйте ему, вы можете всегда возвращайтесь к коду позже в течение жизни проекта, если это необходимо
Мне нравятся объявления короткого замыкания, так как это способ проверки однострочных переменных.
Я предпочитаю:
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 не бросает никаких ошибка, когда $ключ не существует в $данных.