在PHP中,为什么"或die()"工作,但"或返回"不工作?

Sos*_*umi 21 php error-handling return internals parse-error

在PHP中,您可以通过or die在遇到某些错误时调用exit 来处理错误,如下所示:

$handle = fopen($location, "r") or die("Couldn't get handle");
Run Code Online (Sandbox Code Playgroud)

使用die()不是处理错误的好方法.我宁愿返回一个错误代码,以便父函数可以决定做什么,而不是只是不正确地结束脚本并向用户显示错误.

然而,PHP显示错误,当我尝试更换or die使用or return,这样的:

$handle = fopen($location, "r") or return 0;
Run Code Online (Sandbox Code Playgroud)

为什么or die()工作,但不是or return 0?

Age*_*rum 27

我想感谢你提出这个问题,因为我不知道你不能or return在PHP中执行.当我测试时,我和你一样惊讶.这个问题给了我一个很好的借口,可以在PHP的内部进行一些研究和游戏,这实际上非常有趣.但是,我不是PHP内部的专家,所以以下是外行人对PHP内部的看法,尽管我认为它相当准确.


or return不起作用,因为return语言解析器不认为它是"表达式" - 就这么简单.

该关键字or在PHP语言中被定义为一个被调用的标记T_LOGICAL_OR,并且它似乎被定义的唯一表达式如下所示:

 expr T_LOGICAL_OR { zend_do_boolean_or_begin(&$1, &$2 TSRMLS_CC); } expr { zend_do_boolean_or_end(&$$, &$1, &$4, &$2 TSRMLS_CC); }
Run Code Online (Sandbox Code Playgroud)

不要担心大括号中的位 - 它只是定义了如何处理实际的"或"逻辑.你留下的是expr T_LOGICAL_OR expr,它只是说它是一个有效的表达式,有一个表达式,后跟T_LOGICAL_OR令牌,后跟另一个表达式.

expr正如您所期望的那样,An 也由解析器定义.它可以是a r_variable,这只是意味着它是一个你可以读取的变量,或者expr_without_variable是一个奇特的方式来表达表达式可以由其他表达式组成.

您可以这样做,or die()因为语言构造die(不是函数!)及其别名exit都由令牌表示T_EXIT,并且T_EXIT被认为是有效的expr_without_variable,而return语句 - 令牌T_RETURN- 则不是.

现在,为什么被T_EXIT认为是表达但T_RETURN不是?老实说,我不知道.也许这只是一个设计选择,只是为了允许or die()你所询问的结构.以前它被广泛使用的事实 - 至少在教程之类的东西,因为我不能说大量的生产代码 - 似乎暗示这可能是一个有意的选择.您必须要求语言开发人员确切知道.


尽管如此,这应该不重要.虽然这个or die()构造在几年前的教程(见上文)中似乎无处不在,但它并不是真正推荐的,因为它是"聪明代码"的一个例子.or die()它不是一个自己的结构,而是一个使用 - 有些人可能会说滥用 - 的一个技巧 - or运营商的两个副作用:

  • 它在运算符优先级列表中非常低,这意味着实际上每个其他表达式都会在它之前进行求值
  • 它是一个短路运算符,这意味着or如果第一个操作数返回TRUE,则不执行第二个操作数(后面的位),因为如果一个操作数TRUE在or表达式中,那么它们都是.

有些人认为这种技巧是不利的,因为程序员更难阅读但只能在源代码中保存一些空格字符.由于程序员时间很长,并且磁盘空间很便宜,你可以看出为什么人们不喜欢这样.

相反,您应该通过将代码扩展为完整的if语句来明确您的意图:

$handle = fopen($location, "r");
if ($handle) {
  // process the file
} else {
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

您甚至可以在if语句中执行变量赋值.有些人仍然认为这是不可读的,但大多数人(包括我自己)不同意:

if ($handle = fopen($location, "r")) {
  // process the file
} else {
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

最后一件事:按照惯例,返回0状态代码表示成功,因此您可能希望返回不同的值以指示您无法打开该文件.