搜索

首页  >  问答  >  正文

php - PDO和PDOStatement为什么会同时存在?这样的设计是出于什么考虑呢?

问题描述:
都知道自PHP 5.1.0 起,PDO就算是PHP的标配的一部分了,PDO提供了3个类PDOPDOStatementPDOExceptionPDOException这个类就不用说了,功能和定位啥的看名字都很清楚。

那么问题来了:为什么会同时存在PDOPDOStatement这两个类?

为什么会有这样的疑问,先看下图(图片截取自@PHP官网手册):

图片是PDOPDOStatement类所声明的方法,可以看出,这两个类提供的方法虽然绝大部分不同,但是明显核心方法有重叠或重复,比如:

PDOStatement::execute()还好说,而PDO::query()PDO::exec() 同时存在的必要性又是什么呢?而且还会造成使用和理解上面的不畅。

好吧,就算有同时存在的必要性
那么还是有一点为什么要同时存在这两个类呢?而不是一个类(假如只有 PDO类)就将这两个类所能做的事情一起做了呢?
PDO 类和 PDOStatement 类之间是什么关系呢?

如果 PDO 类用来执行SQL和管理链接,而 PDOStatement 类只用来处理结果集,那么感觉就舒服顺畅多了。

希望有大牛能给予解释 PHPPDO 这么设计的考虑是什么,真诚感谢~

我想大声告诉你我想大声告诉你2781 天前786

全部回复(3)我来回复

  • 曾经蜡笔没有小新

    曾经蜡笔没有小新2017-05-16 13:13:25

    我的理解是,一个用来执行普通的SQL,另外一个可以进行参数绑定之类的……

    回复
    0
  • 仅有的幸福

    仅有的幸福2017-05-16 13:13:25

    我说一下个人理解,有错误的地方还请大家指正。
    首先看一下PDO类

    PDO::prepare — Prepares a statement for execution and returns a statement object
    PDO::query — Executes an SQL statement, returning a result set as a PDOStatement object

    可以看到query()和prepare()都是返回一个PDOStatement对象,那么这就说明PDOStatement可以操作结果集。
    再看PDO::prepare,手册说是执行一条预处理语句,实际上他是得到一条预处理语句PDOStatement,然后再通过调用PDOStatement::execute() 来真正执行SQL。
    通常我们一些项目都会使用prepare来执行SQL语句,这样的做法是为了防止SQL注入,和提高相同模板SQL的查询性能,引入官方手册内容:
    The query only needs to be parsed (or prepared) once, but can be executed multiple times with the same or different parameters. When the query is prepared, the database will analyze, compile and optimize its plan for executing the query. For complex queries this process can take up enough time that it will noticeably slow down an application if there is a need to repeat the same query many times with different parameters. By using a prepared statement the application avoids repeating the analyze/compile/optimize cycle. This means that prepared statements use fewer resources and thus run faster.

    The parameters to prepared statements don't need to be quoted; the driver automatically handles this. If an application exclusively uses prepared statements, the developer can be sure that no SQL injection will occur (however, if other portions of the query are being built up with unescaped input, SQL injection is still possible).
    至于楼主说的PDO::query和PDO::exec不同,如下:
    query是只执行一个select语句,exec是执行select,insert,update,delete
    PDO::query执行一条SQL语句,如果通过,则返回一个PDOStatement对象
    PDO::exec执行一条SQL语句,并返回受影响的行数。此函数不会返回结果集合。
    PDOStatement::execute前面也说了一些介绍,他是PDOStatement下的一个子函数,一个特性在于它支持绑定参数,不用考虑SQL注入安全问题,另一个特性是支持多次执行,同模板SQL有助于性能提高。
    如果你只查询一个语句,用query好处是query返回的结果集可以直接遍历。
    而你用exec执行他是只返回受影响的行数,并不是PDOStatement结果集,你是没法直接遍历的。按照官方建议使用query或execute。
    我理解的大概就是这样。

    回复
    0
  • PHP中文网

    PHP中文网2017-05-16 13:13:25

    1.exec
    2.query
    3.prepare+execute

    上面3种方法都可以执行SQL,如果觉得容易混淆,可以只用第3种方法.
    因为只要是exec和query能实现的,prepare+execute也一样能实现.
    而prepare+execute能实现的,比如预处理参数化查询,exec和query却不能实现.
    exec和query更多是为了方便而出现的,比如有时候我们执行的SQL语句并没有外来的参数,这时用exec和query就会简洁些,显然exec更适合执行单条写操作(INSERT/UPDATE/DELETE)语句,因为exec能直接返回受影响的行,如果你用query,你还得调用rowCount()才能获得受影响的行,比如:
    $db->query($sql)->rowCount();$db->query($sql)->rowCount();
    当如果你执行没有外来参数的SQL获取SELECT结果,这时则应该用query而不是exec:
    $db->query($sql)->fetchAll();当如果你执行没有外来参数的SQL获取SELECT结果,这时则应该用query而不是exec:
    $db->query($sql)->fetchAll();

    如果你执行的SQL带有输入的参数,为了防止SQL注入,你应该用prepare:🎜
    $sql = "SELECT * FROM `io_post` WHERE `id` IN (?, ?, ?)";
    $params = array(1, 3, 5); //$params是一个参数数组,元素按顺序一一对应$sql中的问号?占位符
    $stmt = $db->prepare($sql);
    $stmt->execute($params); //execute会自动对参数数组的每个元素进行bindValue
    $stmt->fetchAll(); //如SELECT结果集
    $stmt->rowCount(); //如INSERT/UPDATE/DELETE受影响的行

    回复
    0
  • 取消回复