PHP:例外与错误?

也许我在PHP手册的某处丢失了它,但是错误和exception究竟有什么区别呢? 我可以看到的唯一区别是错误和exception处理方式不同。 但是什么导致了一个exception,并导致错误?

抛出exception – 他们打算被抓住。 错误通常是不可恢复的。 比方说,例如 – 你有一个代码块将插入一个数据库的行。 这个调用有可能失败(重复的ID) – 你会希望有一个“错误”,在这种情况下是“exception”。 当你插入这些行时,你可以做这样的事情

try { $row->insert(); $inserted = true; } catch (Exception $e) { echo "There was an error inserting the row - ".$e->getMessage(); $inserted = false; } echo "Some more stuff"; 

程序执行将继续 – 因为你“抓住”了exception。 除非被捕获,否则exception将被视为错误。 它将允许您在失败之后继续执行程序。

我通常set_error_handler函数接受错误,并抛出一个exception,所以无论发生什么,我只是有例外处理。 没有更多@file_get_contents只是很好,整齐的try / catch。

在debugging的情况下,我也有一个exception处理程序,输出一个asp.net页面。 我在路上张贴这个,但如果要求,我会稍后张贴示例源。

编辑:

除了承诺之外,我已经将一些代码剪切粘贴在一起来制作一个样本。 我把下面的文件保存在我的工作站上, 你可以在这里看到结果 。

 <?php define( 'DEBUG', true ); class ErrorOrWarningException extends Exception { protected $_Context = null; public function getContext() { return $this->_Context; } public function setContext( $value ) { $this->_Context = $value; } public function __construct( $code, $message, $file, $line, $context ) { parent::__construct( $message, $code ); $this->file = $file; $this->line = $line; $this->setContext( $context ); } } /** * Inspire to write perfect code. everything is an exception, even minor warnings. **/ function error_to_exception( $code, $message, $file, $line, $context ) { throw new ErrorOrWarningException( $code, $message, $file, $line, $context ); } set_error_handler( 'error_to_exception' ); function global_exception_handler( $ex ) { ob_start(); dump_exception( $ex ); $dump = ob_get_clean(); // send email of dump to administrator?... // if we are in debug mode we are allowed to dump exceptions to the browser. if ( defined( 'DEBUG' ) && DEBUG == true ) { echo $dump; } else // if we are in production we give our visitor a nice message without all the details. { echo file_get_contents( 'static/errors/fatalexception.html' ); } exit; } function dump_exception( Exception $ex ) { $file = $ex->getFile(); $line = $ex->getLine(); if ( file_exists( $file ) ) { $lines = file( $file ); } ?><html> <head> <title><?= $ex->getMessage(); ?></title> <style type="text/css"> body { width : 800px; margin : auto; } ul.code { border : inset 1px; } ul.code li { white-space: pre ; list-style-type : none; font-family : monospace; } ul.code li.line { color : red; } table.trace { width : 100%; border-collapse : collapse; border : solid 1px black; } table.thead tr { background : rgb(240,240,240); } table.trace tr.odd { background : white; } table.trace tr.even { background : rgb(250,250,250); } table.trace td { padding : 2px 4px 2px 4px; } </style> </head> <body> <h1>Uncaught <?= get_class( $ex ); ?></h1> <h2><?= $ex->getMessage(); ?></h2> <p> An uncaught <?= get_class( $ex ); ?> was thrown on line <?= $line; ?> of file <?= basename( $file ); ?> that prevented further execution of this request. </p> <h2>Where it happened:</h2> <? if ( isset($lines) ) : ?> <code><?= $file; ?></code> <ul class="code"> <? for( $i = $line - 3; $i < $line + 3; $i ++ ) : ?> <? if ( $i > 0 && $i < count( $lines ) ) : ?> <? if ( $i == $line-1 ) : ?> <li class="line"><?= str_replace( "\n", "", $lines[$i] ); ?></li> <? else : ?> <li><?= str_replace( "\n", "", $lines[$i] ); ?></li> <? endif; ?> <? endif; ?> <? endfor; ?> </ul> <? endif; ?> <? if ( is_array( $ex->getTrace() ) ) : ?> <h2>Stack trace:</h2> <table class="trace"> <thead> <tr> <td>File</td> <td>Line</td> <td>Class</td> <td>Function</td> <td>Arguments</td> </tr> </thead> <tbody> <? foreach ( $ex->getTrace() as $i => $trace ) : ?> <tr class="<?= $i % 2 == 0 ? 'even' : 'odd'; ?>"> <td><?= isset($trace[ 'file' ]) ? basename($trace[ 'file' ]) : ''; ?></td> <td><?= isset($trace[ 'line' ]) ? $trace[ 'line' ] : ''; ?></td> <td><?= isset($trace[ 'class' ]) ? $trace[ 'class' ] : ''; ?></td> <td><?= isset($trace[ 'function' ]) ? $trace[ 'function' ] : ''; ?></td> <td> <? if( isset($trace[ 'args' ]) ) : ?> <? foreach ( $trace[ 'args' ] as $i => $arg ) : ?> <span title="<?= var_export( $arg, true ); ?>"><?= gettype( $arg ); ?></span> <?= $i < count( $trace['args'] ) -1 ? ',' : ''; ?> <? endforeach; ?> <? else : ?> NULL <? endif; ?> </td> </tr> <? endforeach;?> </tbody> </table> <? else : ?> <pre><?= $ex->getTraceAsString(); ?></pre> <? endif; ?> </body> </html><? // back in php } set_exception_handler( 'global_exception_handler' ); class X { function __construct() { trigger_error( 'Whoops!', E_USER_NOTICE ); } } $x = new X(); throw new Exception( 'Execution will never get here' ); ?> 

在这里添加的一件事是处理exception和错误。 对于应用程序开发人员来说,错误和exception都是您想要logging的“坏事”,以了解您的应用程序存在的问题 – 从而使您的客户从长远angular度获得更好的体验。

所以编写一个error handling程序是非常有意义的,这个error handling程序和你对exception做的事情是一样的。

答案值得在房间里谈论大象

错误是在运行时处理错误条件的旧方法。 通常,代码会在执行某些代码之前调用set_error_handler东西。 遵循汇编语言中断的传统。 下面是一些BASIC代码的外观。

 on error :divide_error print 1/0 print "this won't print" :divide_error if errcode = X print "divide by zero error" 

很难确保set_error_handler将被调用正确的值。 更糟糕的是,可能会调用一个单独的过程来更改error handling程序。 再加上很多次调用穿插set_error_handler调用和处理程序。 代码很容易很快失去控制。 exception处理通过forms化好的代码真正在做的语法和语义来解决。

 try { print 1/0; print "this won't print"; } catch (DivideByZeroException $e) { print "divide by zero error"; } 

没有单独的函数或调用error handling程序的风险。 现在的代码保证在同一个地方。 另外我们得到更好的错误信息。

PHP曾经只有error handling,当许多其他语言已经发展到更好的exception处理模型。 最终PHP的制造者实现了exception处理。 但可能支持旧代码,他们保持error handling,并提供了一种使error handling看起来像exception处理。 除此之外,不能保证某些代码不会重置error handling程序,这正是exception处理的意图。

最终答案

在执行exception处理之前编码的错误可能仍然是错误。 新的错误可能是例外。 但是没有任何devise或逻辑是错误的,哪些是例外。 它只是基于编码时的可用性以及编程人员的偏好。

回复:“但是错误和exception究竟有什么区别呢?”

关于这里的差异有很多很好的答案。 我只会添加一些尚未讨论过的内容 – 性能。 具体来说,这是抛出/处理exception和处理返回码(成功或错误)之间的区别。 通常,在PHP中,这意味着返回falsenull ,但他们可以更详细,如file upload: http : //php.net/manual/en/features.file-upload.errors.php你甚至可以返回exception对象!

我用不同的语言/系统做了几次性能testing。 一般来说,exception处理比检查错误返回码慢大约10,000倍。

所以,如果是绝对的话,在开始之前肯定需要完成执行 – 嗯,因为时间旅行不存在,所以你倒霉了。 没有时间旅行,返回代码是最快的select。

编辑:

PHP针对exception处理进行了高度优化。 真实世界的testing表明,抛出一个exception只比返回一个值慢2-10倍。

正如其他答案所述,将error handling程序设置为exceptionthrower是在PHP中处理错误的最佳方法。 我使用一个更简单的设置:

 set_error_handler(function ($errno, $errstr, $errfile, $errline ) { if (error_reporting()) { throw new \ErrorException($errstr, 0, $errno, $errfile, $errline); } }); 

请注意error_reporting()检查以保持@操作员工作。 另外,没有必要定义自定义exception,PHP有一个很好的类。

抛出exception的好处在于,exception具有与它们相关的堆栈跟踪,所以很容易find问题所在。

我想你要找的那个东西就是那个;

错误是你习惯的标准东西,比如回显一个不存在的$variables。
exception只是从PHP 5开始,并在处理对象时才会出现。

保持简单:

例外是处理对象时出现的错误。 try / catch语句可以让你做一些关于它们的事情,而且很像if / else语句。 尝试做到这一点,如果问题,没关系,做到这一点。

如果你不“捕捉”一个exception,那么它会变成一个标准错误。

错误是通常停止脚本的php fundemental错误。

Try / catch通常用于build立像PDO这样的数据库连接,如果你想redirect脚本或者在连接不起作用的时候做一些其他的事情,那就好了。 但是,如果你只是想显示错误信息,并停止脚本,那么你不需要它,未捕获的exception变成了一个致命的错误。 或者您也可以使用站点范围的error handling设置。

希望有所帮助

抛出exception是由代码抛出,错误…没有那么多。

错误是由于某些通常不被处理的结果而产生的。 (IO错误,TCP / IP错误,空引用错误)

我打算给你一个关于错误控制的最不寻常的讨论。

几年前,我在一种语言中build立了一个非常好的error handling程序,虽然其中一些名称已经改变,但error handling的原理今天是一样的。 我有一个定制的多任务操作系统,必须能够从各个层面的数据错误中恢复,没有内存泄漏,堆栈增长或崩溃。 所以接下来是我的理解错误和例外必须如何运作,以及它们如何不同。 我只是说我不了解try catch的内部是如何工作的,所以我猜测是有些措施的。

发生error handling的第一件事是从一个程序状态跳转到另一个程序状态。 这是怎么做的? 我会做到的。

从历史上看,错误年龄更大,更简单,例外情况更新,更复杂,更有能力。 错误工作正常,直到你需要把它们吹起来,这相当于把一个困难的问题交给你的主pipe。

错误可以是数字,如错误号码,有时也可以是一个或多个关联的string。 例如,如果发生文件读取错误,您可能会报告它是什么,可能会正常失败。 (干草,就像过去一样,刚刚崩溃了一步。)

关于exception的常见情况是exception是在特殊exception堆栈上分层的对象。 这就像程序stream程的返回栈,但是它只是为了错误捕获和捕获而保存返回状态。 (我曾经称他们为ePush和ePop,而Abort是一个有条件的投掷,将ePop和恢复到这个水平,而Abort是一个完整的死亡或退出。)

在堆栈的底部是关于初始调用者的信息,该对象知道外部尝试启动时的状态,这通常是程序启动时的状态。 在最上面,或者是堆栈中的下一层,是子节点,是父节点,是下一个内部try / catch块的exception对象。

如果你尝试一下,试一试,你会在外面试一试。 当内部尝试发生错误,并且内部catch不能处理它或错误被引发到外部try时,则控制传递给外部catch块(object)以查看它是否可以处理错误,即你的主pipe。

所以这个错误堆栈真正做的是能够标记和恢复程序stream和系统状态,换句话说,它允许程序不会在返回堆栈时崩溃,并在事情出错时将其他事物(数据)弄糟。 因此,它还可以节省内存分配池等任何其他资源的状态,因此可以在捕获完成时清除它们。 一般来说,这可能是一个非常复杂的事情,这就是为什么exception处理通常很慢的原因。 总的来说,相当多的状态需要进入这些exception块。

所以try / catch块的sorting设置一个状态,如果所有其他事情都搞砸了,就可以返回。 这就像一个家长。 当我们的生活变得混乱起来的时候,我们可以回到我们的父母的圈子里,他们将会一切顺利。

希望我没有让你失望。

一旦定义了set_error_handler(),error handling程序就类似于Exception's。 见下面的代码:

  <?php function handleErrors( $e_code ) { echo "error code: " . $e_code . "<br>"; } set_error_handler( "handleErrors" ); trigger_error( "trigger a fatal error", E_USER_ERROR); echo "after error."; //it would run if set_error_handler is defined, otherwise, it wouldn't show ?>