8

当我偶然发现类似这样的构造时,我正在重构一些旧代码:

// 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,如果你真的想缩短它,这就是三元运算符的用途”那么简单?

编辑:请记住,上面的代码是从原始代码快速派生出来的,只是一个使用“短路”代码的例子。如果可以,请不要建议代码改进,因为这不是问题的预期结果。

示例 2

userCheckedTheBox($user) && displayAppropriateInfo();
4

5 回答 5

6

虽然$foo && bar();代码行数较少,但可读性要差得多。使您的代码易于理解通常比减少总 LoC 更重要。即使你没有在一个有多个程序员的环境中工作,你也必须在未来的某个时候回来阅读你的代码,你可能无法记住每一行代码背后的基本原理是什么代码(伊格森定律)。

通常,您应该将此类语句的使用限制在程序员意图绝对清楚的情况下。在我看来,让测试条件的代码和在同一条语句上主动修改程序当前状态的代码是非常糟糕的做法。

这是这种代码的一个可接受的用途:

$isValidUser = $userName && usernameIsValid();

在这里,运算符的两边都在&&测试一个条件,右边正在调用一个函数来做这件事并不会损害代码的可读性。

于 2013-03-24T21:49:02.983 回答
3

有一种古老的技术,我相信它在被破解的 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
}

对于空检查:

var bar = foo && foo.property;

我发现一旦你习惯了它,它就非常易读,而且通常比if/else或更直观?:。但是你应该只在有意义的时候使用它。在任何地方使用它都会变得非常混乱。例如,在您的示例中,您不应该使用它。我个人将它用于简单的错误检查和一些默认值。在大型项目中,您几乎总是希望在发生错误时做更多事情,因此在这些情况下您不应该使用它。

你也应该小心;这仅适用于具有短路评估的语言(http://en.wikipedia.org/wiki/Short-circuit_evaluation)。有时andandor是短路的,while &&and ||are not。

myfunction() or die("I'm melting!");写起来也挺满意的。

最后,空else块通常是我以前从未见过或听过任何人推荐的东西。这对我来说似乎毫无意义。您的示例最易读的选项很简单:

if( $foo ) {
    bar( );
}
于 2013-03-24T22:23:37.320 回答
1

无论该代码在做什么,返回的实例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. 使用短路来减少字符的数量(因此导致解析时间),同时在所有其他级别上浪费资源与在超级铣削课程中出现在 V8 野马中一样愚蠢。

于 2013-03-24T21:57:07.347 回答
1

对于错误,您应该使用真正的异常:

try {
  $foo = bar();
} catch(FooException $e) {
  exit($e->errorCode);
}
process($foo);

请参阅错误处理文档

于 2013-03-24T21:55:11.723 回答
0

您的问题的另一种可能的解决方案:

$foo = bar();
!checkForException($foo) or exit($foo->errorCode);
process($foo);

但更好!checkForException的改变或类似的isNoException东西。

于 2013-03-24T22:14:55.867 回答