不灭的焱

革命尚未成功,同志仍须努力下载JDK17

作者:Albert.Wen  添加时间:2015-07-08 23:20:48  修改时间:2024-04-26 22:58:02  分类:PHP库/系统/微信  编辑

项目中引进了ThinkPHP3.2.3的模型层,发现当SQL语句出错时,系统抛出的异常不是我想要的效果,打开文件 ThinkPHP\Library\Think\Db\Driver.class.php,找到如下代码:

/**
 * 执行语句
 * 
 * @access public
 * @param string $str  sql指令
 * @param boolean $fetchSql  不执行,只是获取SQL
 * @return mixed
 */
public function execute($str,$fetchSql=false) {
	$this->initConnect(true);
	if ( !$this->_linkID ) return false;
	$this->queryStr = $str;
	
	if(!empty($this->bind)){
		$that   =   $this;
		$this->queryStr =   strtr($this->queryStr,array_map(function($val) use($that){ return '\''.$that->escapeString($val).'\''; },$this->bind));
	}
	if($fetchSql){
		return $this->queryStr;
	}
	
	//释放前次的查询结果
	if ( !empty($this->PDOStatement) ) $this->free();
	$this->executeTimes++;
	N('db_write',1); // 兼容代码
	
	// 记录开始执行时间
	$this->debug(true);
	$this->PDOStatement = $this->_linkID->prepare($str);
	if(false === $this->PDOStatement) {
		$this->error();
		return false;
	}
	foreach ($this->bind as $key => $val) {
		if(is_array($val)){
			$this->PDOStatement->bindValue($key, $val[0], $val[1]);
		}else{
			$this->PDOStatement->bindValue($key, $val);
		}
	}
	$this->bind =   array();

	$result = $this->PDOStatement->execute(); // 当有PDO内部异常时,此处就会直接抛出PHP异常,后面的代码不会被执行,页面被中断

	$this->debug(false);
	if ( false === $result) {
		$this->error();
		return false;
	} else {
		$this->numRows = $this->PDOStatement->rowCount();
		if(preg_match("/^\s*(INSERT\s+INTO|REPLACE\s+INTO)\s+/i", $str)) {
			$this->lastInsID = $this->_linkID->lastInsertId();
		}
		return $this->numRows;
	}
}

注意:

看到上面代码中的片段

$result = $this->PDOStatement->execute(); 

当上述PDO语句有异常时(如 SQL语句中数据表不存在),此处就会直接抛出PHP异常,后面的代码不会被执行,页面被中断,这不是我们想要的结果;

我们是希望PDO异常能够寄存到某个变量中,并且页面不会被中断,异常信息留到后面处理(希望异常在 $this->error() 中被处理),这也是ThinkPHP作者的设计意图,所以该驱动类文件(ThinkPHP\Library\Think\Db\Driver.class.php)需要调整下,找到如下代码调整:

// PDO连接参数
protected $options = array(
	PDO::ATTR_CASE              =>  PDO::CASE_LOWER,           // 需要改为 PDO::CASE_NATURAL,表示 字段名按照原始的方式显示
	PDO::ATTR_ERRMODE           =>  PDO::ERRMODE_EXCEPTION,    // 需要改为 PDO::ERRMODE_SILENT,方便用 errorInfo()方法 来获取异常信息
	PDO::ATTR_ORACLE_NULLS      =>  PDO::NULL_NATURAL,
	PDO::ATTR_STRINGIFY_FETCHES =>  false,
);

 

参考:

PHP中PDO错误/异常(PDOException)处理