在 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
是一个语句,并且与if
和foreach
等其他语句一起定义为这样(特别是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”无效?的主要内容,如果未能解决你的问题,请参考以下文章