在 PHP 中,为啥“or die()”有效,而“or return”无效?

Posted

技术标签:

【中文标题】在 PHP 中,为啥“or die()”有效,而“or return”无效?【英文标题】:In PHP, why does "or die()" work, but "or return" doesn't?在 PHP 中,为什么“or die()”有效,而“or return”无效? 【发布时间】:2013-01-01 19:46:30 【问题描述】:

php中,当遇到某些错误时,您可以通过调用or die退出来处理错误,如下所示:

$handle = fopen($location, "r") or die("Couldn't get handle");

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

但是,当我尝试将or die 替换为or return 时,PHP 显示错误,如下所示:

$handle = fopen($location, "r") or return 0;

为什么or die() 有效,而or return 0 无效?

【问题讨论】:

【参考方案1】:

感谢您提出这个问题,因为我不知道您不能在 PHP 中执行 or return。当我测试它时,我和你一样感到惊讶。这个问题给了我一个很好的借口,让我在 PHP 的内部进行一些研究和玩耍,这实际上很有趣。不过我不是PHP内部的专家,所以下面是外行对PHP内部的看法,虽然我觉得还算准确。


or return 不起作用,因为return 不被语言解析器视为“表达式”——就这么简单。

关键字 or 在 PHP 语言中被定义为一个名为 T_LOGICAL_OR 的标记,而似乎定义它的唯一表达式看起来像 this:

 expr T_LOGICAL_OR  zend_do_boolean_or_begin(&$1, &$2 TSRMLS_CC);  expr  zend_do_boolean_or_end(&$$, &$1, &$4, &$2 TSRMLS_CC); 

不要担心大括号中的位——它只是定义了实际的“或”逻辑是如何处理的。你剩下的是expr T_LOGICAL_OR expr,它只是说有一个表达式是一个有效的表达式,然后是T_LOGICAL_OR 标记,然后是另一个表达式。

如您所料,解析器也定义了expr。它可以是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 运算符的两个副作用的技巧:

它在运算符优先级列表中非常低,这意味着几乎所有其他表达式都会在它被评估之前被评估 它是一个短路运算符,这意味着如果第一个操作数返回TRUE,则不会执行第二个操作数(or 之后的位),因为如果一个操作数在@987654353 中是TRUE @ 表达式,那么它们都是。

有些人认为这种诡计是不利的,因为程序员更难阅读,但只在源代码中节省了几个字符的空间。由于程序员的时间很昂贵,而磁盘空间又很便宜,你可以理解为什么人们不喜欢这样。

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

$handle = fopen($location, "r");
if ($handle) 
  // process the file
 else 
  return 0;

您甚至可以在if 语句中进行变量赋值。有些人仍然觉得这不可读,但大多数人(包括我自己)不同意:

if ($handle = fopen($location, "r")) 
  // process the file
 else 
  return 0;

最后一件事:按照惯例,将0 作为状态码返回表示成功,因此您可能希望返回一个不同的值来表示您无法打开文件。

【讨论】:

这就是它的有趣之处...Return 是一种语言结构,不能以 OP 所需的方式使用。而die 也是一种语言结构,但仍可用于上述所需方法。而 die 是 exit 的别名,可以使用另一种语言结构。 Return 是这一组中的奇数。 @MarkTomlin 我不认为return 是一个奇怪的人。 return 是一个语句,并且与ifforeach 等其他语句一起定义为这样(特别是unticked_statement)。它显然适合那个群体。我不确定为什么exit 会被视为表达式,因为将其分配给变量会调用函数并终止脚本。 exit 也是一个 void 函数,因此您只需将 NULL 分配给变量,这没有帮助。我真的认为它只是一个允许or die() 构造工作的表达式。很奇怪。【参考方案2】:

Return 相当特殊 - 它不能像函数一样,因为它是退出函数的工具。想象一下:

if(1==1) return();  // say what??

如果是这样,return 必须是一个执行“双重退出”的函数,不仅留下自己的作用域,还留下调用者的作用域。因此 return 与表达式完全不同,它根本不能那样工作。

现在理论上,return 可以是一个计算结果为(比如说)false 并且 然后 退出函数的表达式;也许以后的 php 版本会实现这个。

同样的事情也适用于 goto 这将是一个作为后备工作的魅力;是的,回退是必要的,并且通常使代码可读,所以如果有人抱怨“聪明的代码”(这当然是一个好点),也许 php 应该有一些“官方”的方式来做这样的事情:

connectMyDB() fallback return false;

类似于 try...catch,更重要的是。就个人而言,我对“或”做这项工作会更满意,因为它与英语语法配合得很好:“连接或报告失败”。

TLDR:您说的完全正确:return、goto、break - 它们都不起作用。原因很容易理解,但仍然很烦人。

【讨论】:

【参考方案3】:

我也偶然发现过一次。我能找到的只有这个:

https://bugs.php.net/bug.php?id=40712

看看下面的评论:

这不是错误

我在文档中进行了搜索,我认为这是因为return 0 是一个语句,而die() 本质上是一个表达式。您无法运行 $handle = return 0;,但 $handle = fun(); 是有效代码。

关于错误处理,我建议使用自定义代码或使用自定义处理程序和触发器。后者例如是described here。

【讨论】:

以上是关于在 PHP 中,为啥“or die()”有效,而“or return”无效?的主要内容,如果未能解决你的问题,请参考以下文章

and die() 和 or die() 的关系

PHP 和 MYSQL:为啥 A 有效而 B 无效?

CF55C Pie or die

mysqli or die,它必须死吗?

CF-55 C.Pie or die

查询在 mysql 工作台中有效,但在 php 中无效,不知道为啥