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

时间:2022-04-05 12:57:41

In PHP, you can handle errors by calling or die to exit when you encounter certain errors, like this:

在PHP中,您可以通过调用或死亡来处理错误,当您遇到某些错误时退出,如下所示:

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

Using die() isn't a great way to handle errors. I'd rather return an error code so the parent function can decide what to do, instead of just ending the script ungracefully and displaying the error to the user.

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

However, PHP shows an error when I try to replace or die with or return, like this:

但是,当我尝试替换或死亡或返回时,PHP显示错误,如下所示:

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

Why does or die() work, but not or return 0?

为什么或死()工作,但没有或返回0?

3 个解决方案

#1


23  

I want to thank you for asking this question, since I had no idea that you couldn't perform an or return in PHP. I was as surprised as you when I tested it. This question gave me a good excuse to do some research and play around in PHP's internals, which was actually quite fun. However, I'm not an expert on PHP's internals, so the following is a layman's view of the PHP internals, although I think it's fairly accurate.

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


or return doesn't work because return isn't considered an "expression" by the language parser - simple as that.

或者返回不起作用,因为语言解析器不将返回视为“表达式” - 这很简单。

The keyword or is defined in the PHP language as a token called T_LOGICAL_OR, and the only expression where it seems to be defined looks like this:

关键字或在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); }

Don't worry about the bits in the braces - that just defines how the actual "or" logic is handled. What you're left with is expr T_LOGICAL_OR expr, which just says that it's a valid expression to have an expression, followed by the T_LOGICAL_OR token, followed by another expression.

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

An expr is also defined by the parser, as you would expect. It can either be a r_variable, which just means that it's a variable that you're allowed to read, or an expr_without_variable, which is a fancy way of saying that an expression can be made of other expressions.

正如您所期望的那样,解析器也定义了expr。它可以是一个r_variable,它只是意味着它是一个你可以读取的变量,或者是一个expr_without_variable,这是一种说法,表达式可以由其他表达式构成。

You can do or die() because the language construct die (not a function!) and its alias exit are both represented by the token T_EXIT, and T_EXIT is considered a valid expr_without_variable, whereas the return statement - token T_RETURN - is not.

你可以做或死()因为语言构造死(不是函数!)和它的别名出口都由令牌T_EXIT表示,而T_EXIT被认为是有效的expr_without_variable,而return语句 - 令牌T_RETURN - 则不是。

Now, why is T_EXIT considered an expression but T_RETURN is not? Honestly, I have no clue. Maybe it was just a design choice made just to allow the or die() construct that you're asking about. The fact that it used to be so widely used - at least in things like tutorials, since I can't speak to a large volume of production code - seems to imply that this may have been an intentional choice. You would have to ask the language developers to know for sure.

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


With all of that said, this shouldn't matter. While the or die() construct seemed ubiquitous in tutorials (see above) a few years ago, it's not really recommended, since it's an example of "clever code". or die() isn't a construct of its own, but rather it's a trick which uses - some might say abuses - two side-effects of the or operator:

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

  • it is very low in the operator precedence list, which means practically every other expression will be evaluated before it is
  • 它在运算符优先级列表中非常低,这意味着实际上每个其他表达式都会在它之前进行求值
  • it is a short-circuiting operator, which means that the second operand (the bit after the or) is not executed if the first operand returns TRUE, since if one operand is TRUE in an or expression, then they both are.
  • 它是一个短路运算符,这意味着如果第一个操作数返回TRUE,则不执行第二个操作数(or之后的位),因为如果一个操作数在一个或表达式中为TRUE,那么它们都是。

Some people consider this sort of trickery to be unfavourable, since it is harder for a programmer to read yet only saves a few characters of space in the source code. Since programmer time is expensive, and disk space is cheap, you can see why people don't like this.

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

Instead, you should be explicit with your intent by expanding your code into a full-fledged if statement:

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

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

You can even do the variable assignment right in the if statement. Some people still find this unreadable, but most people (myself included) disagree:

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

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

One last thing: it is convention that returning 0 as a status code indicates success, so you would probably want to return a different value to indicate that you couldn't open the file.

最后一件事:通常会返回0作为状态代码表示成功,因此您可能希望返回不同的值以指示您无法打开该文件。

#2


0  

I've also stumbled upon that once. All I could find was this:

我曾经偶然发现了一次。我能找到的就是:

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

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

Look at the comment down below:

看下面的评论:

this is not a bug

这不是一个bug

I've searched in the documentation and I think it's due to the fact that return 0 is a statement whereas die() is essentially an expression. You can't run $handle = return 0; but $handle = fun(); is valid code.

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

Regarding error handling I would recommend custom codes or using custom handlers and triggers. The latter are described here for example.

关于错误处理,我建议使用自定义代码或使用自定义处理程序和触发器。这里例如描述了后者。

#3


0  

Return is fairly special - it cannot be anything like a function since it's a tool to exit functions. Imagine this:

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

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

If it was like this, return would have to be a function that does a "double exit", leaving not just its own scope but the caller's, too. Therefore return is nothing like an expression, it simply can't work that way.

如果是这样的话,return必须是一个执行“双重退出”的函数,不仅留下自己的范围,还留下调用者的范围。因此,返回并不像表达式,它根本无法以这种方式工作。

Now in theory, return could be an expression that evaluates to (say) false and then quits the function; maybe a later php version will implement this.

现在理论上,return可以是一个表达式,它会评估为(假设)false然后退出函数;也许后来的php版本会实现这个。

The same thing applies to goto which would be a charm to work as a fallback; and yes, fallbacks are necessary and often make the code readable, so if someone complains about "clever code" (which certainly is a good point) maybe php should have some "official" way to do such a thing:

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

connectMyDB() fallback return false;

Something like try...catch, just more to the point. And personally, I'd be a lot happier with "or" doing this job since it's working well with English grammar: "connect or report failure".

有点像尝试......抓住,更重要的是。就个人而言,我对“或”做这项工作感到高兴,因为它与英语语法很好地配合:“连接或报告失败”。

TLDR: you're absolutely right: return, goto, break - none of them works. Easy to understand why but still annoying.

TLDR:你说得对:返回,转到,打破 - 它们都不起作用。容易理解为什么但仍然很烦人。

#1


23  

I want to thank you for asking this question, since I had no idea that you couldn't perform an or return in PHP. I was as surprised as you when I tested it. This question gave me a good excuse to do some research and play around in PHP's internals, which was actually quite fun. However, I'm not an expert on PHP's internals, so the following is a layman's view of the PHP internals, although I think it's fairly accurate.

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


or return doesn't work because return isn't considered an "expression" by the language parser - simple as that.

或者返回不起作用,因为语言解析器不将返回视为“表达式” - 这很简单。

The keyword or is defined in the PHP language as a token called T_LOGICAL_OR, and the only expression where it seems to be defined looks like this:

关键字或在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); }

Don't worry about the bits in the braces - that just defines how the actual "or" logic is handled. What you're left with is expr T_LOGICAL_OR expr, which just says that it's a valid expression to have an expression, followed by the T_LOGICAL_OR token, followed by another expression.

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

An expr is also defined by the parser, as you would expect. It can either be a r_variable, which just means that it's a variable that you're allowed to read, or an expr_without_variable, which is a fancy way of saying that an expression can be made of other expressions.

正如您所期望的那样,解析器也定义了expr。它可以是一个r_variable,它只是意味着它是一个你可以读取的变量,或者是一个expr_without_variable,这是一种说法,表达式可以由其他表达式构成。

You can do or die() because the language construct die (not a function!) and its alias exit are both represented by the token T_EXIT, and T_EXIT is considered a valid expr_without_variable, whereas the return statement - token T_RETURN - is not.

你可以做或死()因为语言构造死(不是函数!)和它的别名出口都由令牌T_EXIT表示,而T_EXIT被认为是有效的expr_without_variable,而return语句 - 令牌T_RETURN - 则不是。

Now, why is T_EXIT considered an expression but T_RETURN is not? Honestly, I have no clue. Maybe it was just a design choice made just to allow the or die() construct that you're asking about. The fact that it used to be so widely used - at least in things like tutorials, since I can't speak to a large volume of production code - seems to imply that this may have been an intentional choice. You would have to ask the language developers to know for sure.

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


With all of that said, this shouldn't matter. While the or die() construct seemed ubiquitous in tutorials (see above) a few years ago, it's not really recommended, since it's an example of "clever code". or die() isn't a construct of its own, but rather it's a trick which uses - some might say abuses - two side-effects of the or operator:

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

  • it is very low in the operator precedence list, which means practically every other expression will be evaluated before it is
  • 它在运算符优先级列表中非常低,这意味着实际上每个其他表达式都会在它之前进行求值
  • it is a short-circuiting operator, which means that the second operand (the bit after the or) is not executed if the first operand returns TRUE, since if one operand is TRUE in an or expression, then they both are.
  • 它是一个短路运算符,这意味着如果第一个操作数返回TRUE,则不执行第二个操作数(or之后的位),因为如果一个操作数在一个或表达式中为TRUE,那么它们都是。

Some people consider this sort of trickery to be unfavourable, since it is harder for a programmer to read yet only saves a few characters of space in the source code. Since programmer time is expensive, and disk space is cheap, you can see why people don't like this.

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

Instead, you should be explicit with your intent by expanding your code into a full-fledged if statement:

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

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

You can even do the variable assignment right in the if statement. Some people still find this unreadable, but most people (myself included) disagree:

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

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

One last thing: it is convention that returning 0 as a status code indicates success, so you would probably want to return a different value to indicate that you couldn't open the file.

最后一件事:通常会返回0作为状态代码表示成功,因此您可能希望返回不同的值以指示您无法打开该文件。

#2


0  

I've also stumbled upon that once. All I could find was this:

我曾经偶然发现了一次。我能找到的就是:

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

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

Look at the comment down below:

看下面的评论:

this is not a bug

这不是一个bug

I've searched in the documentation and I think it's due to the fact that return 0 is a statement whereas die() is essentially an expression. You can't run $handle = return 0; but $handle = fun(); is valid code.

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

Regarding error handling I would recommend custom codes or using custom handlers and triggers. The latter are described here for example.

关于错误处理,我建议使用自定义代码或使用自定义处理程序和触发器。这里例如描述了后者。

#3


0  

Return is fairly special - it cannot be anything like a function since it's a tool to exit functions. Imagine this:

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

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

If it was like this, return would have to be a function that does a "double exit", leaving not just its own scope but the caller's, too. Therefore return is nothing like an expression, it simply can't work that way.

如果是这样的话,return必须是一个执行“双重退出”的函数,不仅留下自己的范围,还留下调用者的范围。因此,返回并不像表达式,它根本无法以这种方式工作。

Now in theory, return could be an expression that evaluates to (say) false and then quits the function; maybe a later php version will implement this.

现在理论上,return可以是一个表达式,它会评估为(假设)false然后退出函数;也许后来的php版本会实现这个。

The same thing applies to goto which would be a charm to work as a fallback; and yes, fallbacks are necessary and often make the code readable, so if someone complains about "clever code" (which certainly is a good point) maybe php should have some "official" way to do such a thing:

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

connectMyDB() fallback return false;

Something like try...catch, just more to the point. And personally, I'd be a lot happier with "or" doing this job since it's working well with English grammar: "connect or report failure".

有点像尝试......抓住,更重要的是。就个人而言,我对“或”做这项工作感到高兴,因为它与英语语法很好地配合:“连接或报告失败”。

TLDR: you're absolutely right: return, goto, break - none of them works. Easy to understand why but still annoying.

TLDR:你说得对:返回,转到,打破 - 它们都不起作用。容易理解为什么但仍然很烦人。