14

我有一个 php 脚本,可以说在执行期间脚本会引发异常。我希望我的 PHP 从它停止的地方(它抛出异常的地方)恢复。

我应该将相同的执行代码放在代码的“catch”部分吗?

例如,假设连接到 mySQL 它因连接超时而失败

   function someCode(){
        $pdostmt = $this->prepare($this->sql);
        if($pdostmt->execute($this->bind) !== false) {
            if(preg_match("/^(" . implode("|", array("select", "describe", "pragma")) . ") /i", $this->sql))
                return $pdostmt->fetchAll($this->fetchOption);
            elseif(preg_match("/^(" . implode("|", array("delete", "insert", "update")) . ") /i", $this->sql))
                return $pdostmt->rowCount();
   }
   try {
        someCode();
        }   
    } catch (PDOException $e) {  
        //re-execute same code as within the try clause?
        someCode();
    }
4

4 回答 4

30

首先,应该明确一个异常只有在没有被捕获的情况下才是致命的。捕获异常不会停止脚本执行。它只是停止 try 块中的堆栈帧并将控制权转移到 catch 块。从那里您的脚本将继续正常执行。

通过在这里捕获异常,我们仍然在捕获异常后恢复正常的脚本执行......

try {
  echo "Try...\n";
  throw new Exception("This is an exception");
} catch(Exception $e) {
  echo "Exception caught with message: " . $e->getMessage() . "\n";
}

echo "Script is still running...";

还有另一种处理未捕获异常的方法,使用异常处理程序。但是,如果您不使用 try 和 catch 语句,执行流程仍将停止。这是异常的性质:

function myExceptionHandler($e) {
  echo "Uncaught exception with message: " , $e->getMessage(), "\n";
}

set_exception_handler('myExceptionHandler'); // Registers the exception handler

throw new Exception("This is Exception 1");
echo "Execution never gets past this point";
throw new Exception("This is Exception 2");
throw new Exception("This is Exception 3");

编辑:澄清你的问题后,我认为我应该说明你想要的不是异常处理程序,但你实际上根本不想使用异常。您正在尝试做的事情根本不需要抛出异常。如果您打算做的只是处理这样的错误,请不要将 PDO 置于异常模式。异常应该只用于处理异常错误。例外的全部意义在于确保你信守诺言。例如,如果您的函数承诺它将始终返回一个 PDOStatement 对象,并且在某些情况下它不可能做到这一点,那么抛出异常是有意义的。这让调用者知道我们已经到了无法兑现承诺的地步。

你想要的是基本的错误处理......

function someCode(){
        $pdostmt = $this->prepare($this->sql);
        if($pdostmt->execute($this->bind) !== false) {
            if(preg_match("/^(" . implode("|", array("select", "describe", "pragma")) . ") /i", $this->sql))
                return $pdostmt->fetchAll($this->fetchOption);
            elseif(preg_match("/^(" . implode("|", array("delete", "insert", "update")) . ") /i", $this->sql))
                return $pdostmt->rowCount();
        } else {
           return false;
        }
}

while (someCode() === false) {
  /* Call someCode() until you get what you want */
}
于 2012-12-19T15:31:21.880 回答
3

使用 php 4/5 register_shutdown_function。

文档在这里: http: //php.net/manual/en/function.register-shutdown-function.php

于 2013-08-21T15:39:10.357 回答
3

我将假设您无法处理正在抛出的函数中的异常。如果您想恢复抛出异常的位置,则需要在那里处理异常。其他任何东西都是糟糕的编码,会导致您或从事该项目的任何其他人感到困惑。我们让异常上树,因为由于范围问题,我们无法在它自己的函数中处理它们。

至于你的例子,我将对此进行扩展。您说操作无法继续,因为连接无法发生。实际上,我们不想公然重试该函数,因为我们实际上将创建一个持续尝试连接的挂起点,因此我们使用树上更高的 catch 块,我们可以通知用户并让他们决定我们想要做什么. 这样做我们可以在正确的地方使用 catch 块来保存数据,这样我们就可以恢复数据并在以后执行它。实际上,我们希望在 try 块之前的某个点结束。

这将为您提供更清晰的执行路径。有时您必须重新考虑一个函数/方法,以便它正确地做一件事和一件事。

简单直接地回答你的问题。不,在 catch 块中调用 try(ed) 函数是个坏主意,原因很简单,因为您不再有 try 块来在那里捕获异常。异常带来更有意义的错误处理,然后只是传递 true 和 false 作为返回。但是,这确实意味着您必须绕一圈来处理它们。

现在举一个替代示例...假设我们有多个可以连接的服务器,并且您想运行该列表,您可以将 try/catch 放入循环中,catch 将检查该异常并在之前进行任何清理执行下一个循环。如果发生任何其他异常,我们将(重新)抛出异常。实现您的目标的正确方法是这样的。

function someCode() {
    $pdostmt = $this->prepare($this->sql);

    while($status == false) {
        try {
            $status = $pdostmt->execute($this->bind)

        } catch (PDOException $e) {
            if($e->getMessage("What ever the error message is") {
                //Fix it here
            } else {
                throw $e;
            }
        }
    }
    //Do other stuff
    return $data; //or true/false
}
于 2014-07-20T06:05:47.207 回答
0

如果您在执行过程中不会遇到异常,您也许可以使用 try catch 的 finally 部分。

try {
  // some crashing code
} catch (Exception $e) {
  //some catch code
} finally {
  //code that will run anyways.
}
于 2012-12-19T15:23:37.490 回答