Замена IF логическим выражением в PHP
Я рефакторинга некоторые старый код, когда я наткнулся на конструкцию, похожую на эту:
// function bar() returns a value
// if the value is an instance of customException class, terminate with error code
// else process the regular data
$foo = bar();
checkForException($foo) && exit($foo->errorCode());
process($foo);
теперь странно, как это может показаться, это намного короче, чем
$foo=bar();
if(checkForException($foo)) {
exit($foo->errorCode();
}
else {
process($foo);
}
и несколько более читаемый (по крайней мере, после первоначального удивления), то
$foo=bar();
(checkForException($foo)) ? exit($foo->errorCode()) : process($foo);
хотя более короткий код не обязательно означает более читаемый код, я нахожу это где-то в середине двух "стандартных" способов выше.
другими словами, вместо
if($foo) {
bar();
}
else {
// there is no real reason for this to exist, since
// I have nothing to write here, but I want to conform
// to the general coding practices and my coding OCD
}
можно просто писать
$foo && bar();
так что причина в не вижу много пользы? Может ли это быть так же просто, как "не изобретать колесо, писать более читаемый if/else, и если вы действительно хотите его сократить, это то, для чего нужен тернарный оператор"?
EDIT: пожалуйста, имейте в виду, что приведенный выше код был быстро получен из исходного кода и должен был быть просто примером использования кода "короткого замыкания". Если можете, пожалуйста воздержитесь от предложения улучшений кода, поскольку это не было желаемым результатом вопроса.
Пример № 2
userCheckedTheBox($user) && displayAppropriateInfo();
5 ответов
есть старая техника, которая, я считаю, была популярна в взломанных скриптах perl, чтобы показать ошибки. псевдо-код:
myFunction( ) || exitWithError( "Uh-oh" )
при кодировании в срок, и когда пользовательский интерфейс не должен быть звездным, это быстрый способ избежать ошибок.
стиль также популярен в JavaScript для параметров по умолчанию:
function myfunction(foo) {
foo = foo || 0;
// note that a non-zero default won't work so well,
// because the user could call the function with 0
}
и для null-проверки:
var bar = foo && foo.property;
Я нахожу, что как только вы привыкнете к нему, это очень читабельно и часто более интуитивным, чем if
/else
или ?:
. Но вы должны использовать его только тогда, когда это имеет смысл. Использование его везде будет очень запутанным. Например, в вашем примере, вы должны не использовать его. Лично я использую его для простой проверки ошибок и некоторые значения по умолчанию. В больших проектах вы почти всегда хотите сделать намного больше, когда возникает ошибка, поэтому в этих случаях вы не должны использовать это.
также вы должны быть осторожны; это работает только в языки, которые имеют оценку короткого замыкания (http://en.wikipedia.org/wiki/Short-circuit_evaluation). А иногда ... --7--> и or
короткое замыкание, в то время как &&
и ||
нет.
myfunction() or die("I'm melting!");
также вполне удовлетворительно писать.
и, наконец, пустой else
блоки, как правило, это то, что я никогда раньше не видел или не слышал, чтобы кто-то рекомендовал. Мне это кажется бессмысленным. Наиболее читаемый вариант для вашего примера, довольно просто:
if( $foo ) {
bar( );
}
пока $foo && bar();
меньше строк кода, это гораздо менее читаемым. Упрощение понимания кода обычно более важно, чем уменьшение общего LoC. Даже если вы не работаете в среде с несколькими программистами, вам придется вернуться и прочитать свой код в какой-то момент в будущем, и вы, вероятно, не сможете вспомнить, какое обоснование было за каждой строкой кода (Результаты поиска по!--5-->).
как правило, вы должны ограничить использование такого рода утверждения относятся только к тем случаям, когда намерения программиста абсолютно ясны. На мой взгляд, очень плохая практика - иметь код, который проверяет условие и код, который активно изменяет текущее состояние программы на том же операторе.
вот одно приемлемое использование для такого кода:
$isValidUser = $userName && usernameIsValid();
здесь, с обеих сторон &&
оператор тестирует условие, тот факт, что правая сторона вызывает функцию, чтобы сделать это, не вредит читаемость кода.
по ошибки, вы должны использовать реальные исключения:
try {
$foo = bar();
} catch(FooException $e) {
exit($e->errorCode);
}
process($foo);
посмотреть документация для errorhandling.
что делает этот код, возвращая экземпляр CustomException
просто не складывается. Почему бы немного не изменить определение функции:
function bar()
{
$stuff = true;
if ($stuff === true)
{
return 'Value on success';
}
//something went wrong:
throw new CustomException('You messed up');
}
try
{//here's the outlandish try-catch block
$foo = bar();
}
catch (CustomException $e)
{
exit($e->message());//fugly exit call, work on this, too
}
//carry on here, no exception was thrown
кроме того, вызов этой второй функции (checkForException($foo)
) - это просто абсурд. Функциональные вызовы дешевы, но не бесплатны. Вы хотите знать, вернула ли функция экземпляр CustomException
? Не превращайте это в функцию, но используйте instanceof
. Используя короткое замыкание, чтобы сохранить количество символов (ad, таким образом, время разбора) вниз, в то же время тратя ресурсы на всех других уровнях примерно так же глупы, как появление в V8 mustang на курсе hyper-miling.
еще одно возможное решение вашей проблемы:
$foo = bar();
!checkForException($foo) or exit($foo->errorCode);
process($foo);
но лучше изменить !checkForException
на isNoException
или что-то в этом роде.