PHP扩展PDO MySQL之PDOStatement::bindParam vs bindValue技术
前些日子将 LBlog 在线体验站点 http://lblog.lmlphp.com/ 搬迁到了 VPS 上,其实已经过去了好几个月了。新的 VPS 上 PHP 的版本比较高,所以运行的时候会出现提示 mysql 系列的函数过时的 Deprecated 错误。这个错误最简单的办法就是在报错级别那里屏蔽掉,但是这个不是我的风格,我更希望以更好的方式来解决。但是一上班根本没有时间,写个 MysqlPdo Enhance 的类,按照之前 LMLPHP 中 Mysql 驱动类的风格。为此,写 PDO 操作类的时候还专门定义了接口来约束自己的行为,生怕出问题,测试之后证明,完全兼容之前的 Mysql 类,写完花了这么几个月的时间,真的伤不起。
这次写 PDO 驱动类的时候,没有参照其他人的写法,完全看官方文档,结合自己的需要,尽量的简单的实现。其实 PDO 已经是面向对象的风格了,其实并不需要什么驱动类来太多的封装,写这个只是为了更好的兼容项目中的代码。刚开始我看 bindValue 和 bindParam 的时候,文档给我的感觉只是一个是变量,一个是确切的值。到后来才发现一个是引用,一个是普通传参。在测试修改操作的时候,发现数据库中最后一个字段和前一个字符串一样,int 类型没有收到影响,可能当时脑子太累的缘故,这个问题竟然搞了好久,第二天才弄清楚是因为在循环的时候使用了 bindParam 导致的。
MysqlPdoEnhance 驱动类已经上传到 LMLPHP 和 LBlog 中,LBlog 已经在初始化实例的时候自动选择对应的驱动类。这次改善使得 LBlog 系统更加优秀,对服务器环境的适应能力更强了。
MysqlPdoEnhance 类延续了 Mysql 类的简单风格,只有一个重量级的 query 方法,自动判断是返回资源还是影响的行数。同时也发现在使用 PDO 操作时,不能很好的做到这一点。因为执行 SELECT 的时候也有影响的行数,这点与一般的常识不一样,一般懂数据库的人都应该知道,SELECT 是不会影响到行的,但是 PDO 中的 rowCount 方法返回的值是选出的行数。所以,因为这个缘故,只能从 SQL 上面做一个简单的判断了,算是不太完美。
附 query 方法节选。
public function query($sql, $params = array()){ $stmt = $this->db->prepare($sql, array(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true)); if($params){ foreach ($params as $k => $v){ if(is_array($v)){ $value = $v['value']; $type = isset($v['type']) ? $v['type'] : false; $length = isset($v['length']) ? $v['length'] : false; if($type && $length){ $stmt->bindValue($k, $value, $type, $length); }elseif($type){ $stmt->bindValue($k, $value, $type); }else{ $stmt->bindValue($k, $value); } }else{ $stmt->bindValue($k, $v); } } } $stmt->execute(); if(preg_match('/^update|^insert/i', trim($sql))){ return $stmt->rowCount(); }else{ return $stmt->fetchAll(PDO::FETCH_ASSOC); } }