PHP中,如果在语句执行失败时使用'or'语句,该如何抛出新的异常?

21

每个人都应该知道“or”语句,通常与die()命令相关联:

$foo = bar() or die('Error: bar function return false.');
大多数时候我们会看到这样的内容:

mysql_query('SELECT ...') or die('Error in during the query');

然而,我不太理解那个 'or' 语句的确切作用。

我想抛出一个新的异常代替 die(),但是:

try{
    $foo = bar() or throw new Exception('We have a problem here');

不起作用,也不是这样

$foo = bar() or function(){ throw new Exception('We have a problem here'); }

我发现唯一的方法是这个可怕的想法:

function ThrowMe($mess, $code){
    throw new Exception($mess, $code);
}
try{
    $foo = bar() or ThrowMe('We have a problem in here', 666);
}catch(Exception $e){
    echo $e->getMessage();
}

在 'or' 语句之后直接抛出新的异常有办法吗?

还是必须使用这种结构(我一点也不喜欢 ThrowMe 函数):

try{
    $foo = bar();
    if(!$foo){
        throw new Exception('We have a problem in here');
    }
}catch(Exception $e){
    echo $e->getMessage();
}

编辑:我真正想做的是避免在进行任何潜在危险操作时使用if()检查,例如:

#The echo $e->getMessage(); is just an example, in real life this have no sense!
try{
    $foo = bar();
    if(!$foo){
        throw new Exception('Problems with bar()');
    }
    $aa = bb($foo);
    if(!$aa){
        throw new Exception('Problems with bb()');
    }
    //...and so on!
}catch(Exception $e){
    echo $e->getMessage();
}

#But i relly prefer to use something like:

try{
    $foo = bar() or throw new Exception('Problems with bar()');
    $aa = bb($foo) or throw new Exception('Problems with bb()');
    //...and so on!
}catch(Exception $e){
    echo $e->getMessage();
}

#Actually, the only way i figured out is:

try{
    $foo = bar() or throw new ThrowMe('Problems with bar()', 1);
    $aa = bb($foo) or throw new ThrowMe('Problems with bb()', 2);
    //...and so on!
}catch(Exception $e){
    echo $e->getMessage();
}

#But i'll love to thro the exception directly instead of trick it with ThrowMe function.

你的最后一段代码中是不是想写 !$foo - Dominic Rodger
7个回答

36

or只是一个逻辑运算符,它类似于||

常见的技巧是

mysql_query() or die();

可以说得一样好
mysql_query() || die();

这里发生的是“逻辑或”运算符(无论您选择哪个)试图确定两个操作数中是否有一个评估为TRUE。这意味着操作数必须是可以转换为布尔值的表达式。
因此,原因是
bar() or throw new Exception();

是非法的,是因为
(boolean)throw new Exception();

抛出异常也是非法的。实质上,抛出异常的过程不会生成一个返回值供运算符检查。
但是调用一个函数会生成一个返回值供运算符检查(如果没有显式的返回值,函数将返回NULL,它被转换为FALSE),这就是为什么当你将异常抛出包装在一个函数中时它能够工作的原因。

4
“or”与“||”并不类似。前者的优先级低于赋值和比较,而后者则高于它们。这是一个非常重要的区别,因为$f = one() or two()$f = one() || two()的工作方式非常不同。有关详细信息,请参阅http://us3.php.net/manual/en/language.operators.precedence.php。 - Explosion Pills
3
是的。"类似的"并不意味着"相同的"。话虽如此,欢迎您的澄清:D - Peter Bailey
1
错误的语法会引发“解析错误:语法错误,意外的T_THROW”错误。 - Jeff Clemens

3

我只是为此定义了函数toss

function toss(Exception $exception): void
{
    throw $exception;
}

因为异常在构造new)时就捕获了文件/行/堆栈信息,而不是抛出时(throw),这不会干扰调用堆栈。

因此,你可以直接这样做。

something() or toss(new Exception('something failed'));

2
我找到的一个解决方案可以替代所有的 "or die()",就是将 throw 用一个匿名函数包装起来,并立即通过 call_user_func 调用它:
call_user_func(function(){
    throw new Exception("ERROR");
});

您可以通过在虚拟脚本上执行以下操作来查看其是否有效:
false or call_user_func(function(){throw new Exception("ERROR");});

2

为什么bar()bb()没有抛出异常?在PHP中,异常会一直向上冒泡,因此无需在调用bar()/bb()的函数/方法中抛出异常。这些异常可能由bar()/bb()抛出。如果您想抛出另一个异常,可以简单地执行以下操作:

function foo() {
    try {
        $bar = bar();
    } catch (BarException) {
        throw new FooException;
    }
}

是的,你说得对,但是例如数据库函数mysql_query()/pg_query()呢?对于这些函数,我必须使用if()检查或ThrowMe可怕的函数吗?我只想知道是否可能直接完成而不使用ThrowMe()。 - Strae
1
@DaNieL:你可以使用PDO进行数据库访问,它本身可以抛出异常。 - Tom Haigh
1
好吧,这是不可能的。我之前尝试过,但没有机会。PHP是一个有用的工具,但它也拥有世界上最愚蠢的解析器和解释器之一。 - Ionuț G. Stan
无论如何,如果你努力抽象化你的应用程序,你就不应该有那么多对 mysql_query() 或其他函数的调用。你应该在 PHP 之上构建自己的实用工具层,以便可以掩盖所有其特殊性。 - Ionuț G. Stan
@Tom:对不起,我尝试了很多次使用PDO,但是我对它没有好的评价。这是一个关于该技术动机的例子:https://dev59.com/qnRA5IYBdhLWcg3wxA5N 我正在构建我的“轻量、小巧和快速”的PDO解释器 ;) @lonut:那么我们有另一件事情可以加入到php6的心愿清单中了吗? - Strae
@DaNieL,PHP6的愿望清单上会有很多东西,但我并没有看到内部考虑到其中的许多事情。目前在内部邮件列表上正在讨论一项RFC,该RFC建议在内置函数/类中用异常替换错误。但它很可能不会被接受。 - Ionuț G. Stan

1

我认为你想要使用类似于最后一个结构的东西,虽然使用异常没有什么意义:

$foo = bar();
if(!$foo){
    echo 'We have a problem in here';
}

关于评论- 我认为你不能在一行代码中完成这个操作(即没有if(!$foo)检查),我同意抛出异常的方法非常糟糕。就我个人而言,我更喜欢显式地写出:

$foo = bar();
if(!$foo){
    throw new Exception('We have a problem in here');
}

但这是个人偏好。如果你想要单行的东西,我认为你必须选择抛出异常的函数选项。

我猜这个限制可能是由于 PHP 的动态类型转换问题,它可以将函数调用的结果转换为条件语句,但不能将 throw 的结果转换。


不,我不想这样做。回显只是为了举例,在实际生活中永远不要回显错误消息或代码,而是以不同的方式处理它们。我想要的正是避免每次都进行if(!$foo)检查。 - Strae

1

以下是一个不需要额外函数的单行解决方案:

if (!($foo = bar())) throw new Exception('We have a problem here');

1
你可以创建一个自定义的异常类,并使用它的静态构造方法代替throw new Exception()语句。
异常类:
class CustomException extends Exception {
  static public function doThrow($message = "", $code = 0, Exception $previous = null) {
    throw new Exception($message, $code, $previous);
  }
}

使用方法:

try {

  $foo = bar() or CustomException::doThrow('Problems with bar()');
  $aa = bb($foo) or CustomException::doThrow('Problems with bb()');

} catch(Exception $e){
  echo $e->getMessage();
}

注意

如果您正在使用 PHP 7 或更高版本 - 您可以将静态方法 doThrow() 重命名为简单的 throw(),因为在 PHP 7 及更高版本中,允许使用保留关键字作为方法名。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接