最近在扩展抓取pdo的时候发现了点问题,发现有的是报异常,有的是不报,
<?php
error_reporting(E_ALL ^ E_DEPRECATED);
try{
$opts = array(PDO::ATTR_AUTOCOMMIT=>0, PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION, PDO::ATTR_AUTOCOMMIT=>0,PDO::ATTR_TIMEOUT => 3,);
$pdo = new PDO("mysql:host=127.0.0.1;port=3306;dbname=test;charset=UTF8","root","root",$opts);
$rs = $pdo -> query("select * from bankaa");
}
catch(exception $e){
print_r($e);exit;
}
在我的底层扩展是能抓到EG(exception)的,但是同事用了个底层php框架类,就抓不到了,最后跟踪断点发现
跟踪到
发现了一个变量
PDO::ERRMODE_SILENT
此为默认模式。 PDO 将只简单地设置错误码,可使用 PDO::errorCode() 和 PDO::errorInfo()方法来检查语句和数据库对象。如果错误是由于对语句对象的调用而产生的,那么可以调用那个对象的 PDOStatement::errorCode() 或 PDOStatement::errorInfo() 方法。如果错误是由于调用数据库对象而产生的,那么可以在数据库对象上调用上述两个方法。
PDO::ERRMODE_WARNING
除设置错误码之外,PDO 还将发出一条传统的 E_WARNING 信息。如果只是想看看发生了什么问题且不中断应用程序的流程,那么此设置在调试/测试期间非常有用。
PDO::ERRMODE_EXCEPTION (注意:它会内部自己抛出异常,终断页面)
这个图就把一个throw抛出异常以及到抓到catch异常的整个流程分析的很清楚。
zend_throw_exception_internal就相当于手动的throw一个异常,如果是php代码的话一般会有见到这样一个ZEND_THROW_SPEC_CV_HANDLER
但最终调用的都是zend_throw_exception_internal
在这个函数过后,会跳到一个ZEND_HANDLE_EXCEPTION_SPEC_HANDLER也就是我们经常发现的会跳到每一个op array的最后一行, 来执行这条ZEND_HANDLE_EXCEPTION,在这个函数中会判断如果是异常则把下一条要执行的op line, 置为第一个catch的op line, 并继续执行.如果不是 则销毁一些不需要的变量, 和opline, 然后直接结束执行过程.
如果有被catch到就会执行ZEND_CATCH_SPEC_CONST_CV_HANDLER,从而把EG(exception)=NULL
如果没有被catch,层层向上抛,最后就会发现最后调用zend_leave_helper_SPEC,离开函数。