从try/catch块中跳出

17

在PHP中是否可能实现这个功能?

try {

  $obj = new Clas();

  if ($obj->foo) {
    // how to exit from this try block?
  }

  // do other stuff here

} catch(Exception $e) {

}

我知道可以把其他东西放在{}之间,但那会增加更多的缩进并且我不喜欢 :P


3
throw('Get me out of here!')会跳出程序,但这样做不太友好。 - Marc B
3
你能不能在if之后直接使用else? - user1247034
我看不出这有任何合理的用途?是只有我吗? - bestprogrammerintheworld
如果(!isset($obj->foo)){ 做其他的事情 },你知道可以使用isset(),如果你只是查看对象属性是否设置,就不需要丑陋的try/catch块。 - adeneo
2
@bestprogrammerintheworld - 这不是朝鲜,你可以随时和我一样自由地思考! - adeneo
显示剩余3条评论
8个回答

24

当然,用goto语句!

try {

  $obj = new Clas();

  if ($obj->foo) {
    goto break_free_of_try;
  }

  // do other stuff here

} catch(Exception $e) {

}
break_free_of_try:

19
这个回答让我既感到恐惧又感觉自己很有力量。 - jchook
4
它只是强大的。 “goto”没有问题-这是一个古老的神话。我们许多程序员都在等待行业认识到Dijkstra辩论已经结束,如果你知道你在做什么,直接跳转没有任何问题。 - dkellner
1
汇编实现了goto BTW,这意味着它是低级、本地化的,因此如果你知道自己在做什么,使用它是完全合法的。 - Fabien Haddadi
1
在高级语言中使用goto来控制流程会导致代码混乱、出现错误,并给未来维护代码的人带来巨大的麻烦(即使是编写了goto的同一个人),如果你在小函数中使用一次,那么在大函数中就会多次使用。永远不要使用goto,即使在C语言中也没有必要使用goto。在汇编语言中没有goto,主要有jmp指令,当然这就是goto在底层所做的事情,这就是汇编和机器码的工作方式,使用跳转和调用。 - Christos Lytras
4
Christos,你似乎基于错误的假设在操作,认为我的代码还不是已经很混乱了。 - Skylar Ittner
黑暗面是一条通往许多被认为是不自然的能力的道路... - Captain Hypertext

13

其实并没有必要这样做,但你可以在try块中强制产生一个异常来停止函数的执行,体验一下这种乐趣。

try {
   if ($you_dont_like_something){
     throw new Exception();
     //No code will be executed after the exception has been thrown.
   }
} catch (Exception $e){
    echo "Something went wrong";
}

1
考虑抛出特定的 Exception 子类,而不是顶层 Exception 对象。然后,为各种可能性添加 catch 块。与 Dan 的评论类似。 - aaronbauman
如果您经常这样做,这将导致性能损失。 - jor

7

我也遇到了这种情况,和你一样,不希望有无数的if/else if/else if/else语句,因为这样会使代码难以阅读。

最终我扩展了Exception类来实现我的需求。下面是一个示例类,用于处理验证问题,如果触发,则会产生较轻微的“日志通知”。

class ValidationEx extends Exception
{
    public function __construct($message, $code = 0, Exception $previous = null)
    {
        parent::__construct($message, $code, $previous);
    }

    public function __toString()
    {
        return __CLASS__ . ": [{$this->code}]: {$this->message}\n";
    }
}

在我的主代码中,我调用它;

throw new ValidationEx('You maniac!');

在 Try 语句的结尾处,我有以下代码:
        catch(ValidationEx $e) { echo $e->getMessage(); }
        catch(Exception $e){ echo $e->getMessage(); }

欢迎提出意见和批评,我们在这里都是为了学习!


但是在这里使用两个catch块没有任何意义吧?只需要一个catch(Exception $e){ echo $e->getMessage(); }就可以达到同样的效果了。 - Your Common Sense

4
你能不能像这样做呢?
try{

  $obj = new Clas();

  if(!$obj->foo){
  // do other stuff here
  }


}catch(Exception $e){

}

4
try
{
    $object = new Something();
    if ($object->value)
    {
        // do stuff
    }
    else
    {
        // do other stuff
    }
}
catch (Exception $e)
{
     // handle exceptions
}

3
在php 5.3+中,使用try catch块处理异常的好处是,你可以自定义异常并在需要时进行处理。参见:扩展异常
class OtherException extends Exception 
{
    //...
}

你可以在捕获异常时使用if ($e instanceof OtherException)来捕获特定的异常,或者在catch \Exception块中决定如何处理异常。
  1. 已处理的示例:http://ideone.com/ggz8fu
  2. 未处理的示例:http://ideone.com/luPQel
try {
    $obj = (object) array('foo' => 'bar');
    if ($obj->foo) {
        throw new OtherException;
    }
    /* do stuff */
} catch (OtherException $e) {
    /* do other stuff here and handle exception */
} catch (Exception $e) {
    if ($e instanceof InvalidArgumentException) {
        throw $e; //don't handle the exception
    }
}

这样做可以使你的代码更易读,更容易排除故障,而不是使用许多其他解决方案。
话虽如此,异常应被视为正常流程之外的意外功能。

0
这是我会这样做的方式:

<?php
echo 'this' . PHP_EOL;
switch(true) {
    default:
        try {
            echo 'is' . PHP_EOL;
            break;
            echo 'not' . PHP_EOL;
        } catch (Exception $e) {
            // error_log($e->getMessage());
        }
}
echo 'fun !';

:-)


-1
个人而言,我喜欢使用一个try/catch语句来退出。
throw new MyException("optional message", MyException::ERROR_SUCCESS);

我显然通过使用这段代码(在catch()语句内部)捕获到了它

catch(MyException $e) {
    switch($e->getCode()) {
       /** other cases make sense here */
       case MyException::ERROR_SQL:
           logThis("A SQL error occurred. Details: " . $e->getMessage());
       break;

       case MyException::ERROR_SUCCESS:
           logThis("Completed with success. Details: " . $e->getMessage());
       break;

       case MyException::ERROR_UNDEFINED:
       default:
       logThis("Undefined error. Details: " . $e->getMessage());
       break;
    }
}

MyException只是Exception的一个扩展,它还定义了类常量。


相反,这个回答的内在价值是无效的。使用代码来区分异常没有意义,因为PHP可以使用多个catch块来区分不同的异常。这个例子太做作了,在现实生活中没有意义,因为这三个分支本质上都是一样的——记录错误。而且只要$e->getMessage()已经包含了一些关于错误性质的信息,它就可以很容易地简化为一个分支。最重要的是,你似乎在使用异常来控制流程,这是一个反模式。 - Your Common Sense
谢谢你表达你的想法。这只是一个例子,一个模板。没有人要求你发送带有“Your Name here”作为标题的简历。你可以从中获得灵感,并进行修改。这个例子真的很好,它展示了如何扩展std Exception类,并创建一个一致的错误处理程序,其中包含臭名昭著的代码“0”错误(即ERROR_SUCCESS),表示“成功”。欢迎来到一个其他人与你有不同想法的世界。我也可以写博客关于模式和反模式。在IT领域,有多种做事情的方式(好的方式)。欢迎来到民主的IT世界。 - Fabien Haddadi
使用过多的错误异常类扩展并不是一个好的模式,如果你在考虑使用级联的try/catch块来实现这个。这反而是一种不清晰的反模式。没有必要让人类感到困惑,即使计算机也能毫无问题地执行。 - Fabien Haddadi

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