PHP Conference Japan 2024

SQLite3Stmt::execute

(PHP 5 >= 5.3.0, PHP 7, PHP 8)

SQLite3Stmt::execute执行预处理语句并返回结果集对象

描述

public SQLite3Stmt::execute(): SQLite3Result|false

执行预处理语句并返回结果集对象。

警告

通过对同一个语句对象调用此方法检索到的结果集对象不是独立的,而是共享相同的底层结构。因此,建议在再次对同一个语句对象调用SQLite3Stmt::execute()之前,先调用SQLite3Result::finalize()

参数

此函数没有参数。

返回值

成功执行预处理语句时返回一个SQLite3Result对象,失败时返回false

参见

添加注释

用户贡献注释 2 个注释

10
gmail@asmqb7
8 年前
SQLite3 PHP 绑定(并非 SQLite3 本身)当前存在一个问题,导致所有查询都执行两次。显然这个问题已经存在相当一段时间了。

更多信息请参见:https://bugs.php.net/bug.php?id=64531

在发现上述问题之前,我发布了这个:http://stackoverflow.com/questions/36617708/odd-behavior-with-sqlite3-non-select-prepared-transactions-and-fetcharray(包含复制粘贴的错误演示)

解决方法:我强烈建议将任何可能对非SELECT查询结果运行fetchArray()的代码包装在numColumns()检查中,如下所示

<?php

$op
= $db->prepare(...);

$r = $op->execute(); // 查询 #1

if ($r->numColumns()) { // 返回列数,这里用作真/假测试
while ($row = $r->fetchArray(SQLITE3_ASSOC)) { // 查询 #2
// 你的代码在这里
}
}

?>

澄清一下

- 查询 #1 是 SQLite3 查询第一次执行的地方,查询 #2 是查询再次执行的地方。是的,*所有内容* 都执行了两次;这就是错误。

- 如果你的代码只会读取而不会更改数据库(例如,不会导致数据库更改触发器运行的SELECT),那么你就可以了。你的查询会运行两次,但不会改变结果。

- 如果你的代码会写入数据库——例如INSERT——如果列数为零,则**必须**不运行fetchArray()(并且不再次执行查询)。

- 手册中没有记录,但在这里 -https://php.net/manual/en/book.sqlite3.php#113144 - 用户'bohwaz'提到自PHP 5.3.11以来还有一个SQLite3Stmt::readOnly()函数,它会告诉你是否刚刚写入数据库。目前这没有记录,但可能是numColumns()的更合适的替代方案(我不确定它做什么,它可能和numColumns()一样)。

对于使用SQLite3的大量工作,你可能更喜欢PDO。讽刺的是,此绑定更轻量级,并提供对某些SQLite3特定原语和行为的直接访问……但它会将所有查询都执行两次。

[[给版主的说明(此部分可在阅读后删除;我也欢迎对以下内容的反馈)

- 请不要将此评论视为错误报告——我只是想让其他人意识到这个问题,这样他们就不必花几个小时抓耳挠腮了。:P

- 在提交此评论之日,此页面有一个未批准的diff卡在DocBook中,所以我无法添加类似“由于错误#64531,建议你将fetchArray()包装在numColumns()中……”的内容,我认为这比这个评论更有分量,直到这个错误被修复。]]
1
macguru
7 年前
我通过在执行后使用finalize()成功避免了预处理语句多次执行。

$stmt->execute()->finalize();

希望这对其他人有帮助。
To Top