参考 – 有关PDO的常见问题

这是什么?

这是一个关于PHP数据对象的常见问题列表

为什么是这样?

由于PDO具有常规PHP用户所不了解的某些function,因此有关PDO中准备好的语句和error handling的问题相当频繁。 所以,这只是一个可以find它们的地方。

我应该在这里做什么?

如果您的问题已经与此清单密切相关,请在下面find您的问题,并将修复应用到您的代码。 简单回顾一下其他问题也是一个好主意,以便为其他常见问题做好准备。

列表

  • PDO查询失败,但我看不到任何错误。 如何从PDO获取错误消息?
  • 我如何使用LIKE运算符使用预处理语句?
  • 如何为IN()运算符创build一个准备好的语句?
  • 我可以使用PDO准备语句绑定标识符(表或字段名称)或语法关键字吗?
  • PDO准备语句在LIMIT语句中导致错误

也可以看看

  • 参考 – 这个符号在PHP中意味着什么?
  • 参考 – 这个错误在PHP中意味着什么?
  • 参考 – 什么是variables作用域,哪些variables可以从哪里访问,什么是“未定义的variables”错误?

PDO查询失败,但我看不到任何错误。 如何从PDO获取错误消息?

为了能够看到数据库错误,必须将PDO errmode设置为exception。 在许多方面,exception比常规错误更好:它们总是包含一个堆栈跟踪,可以使用try..catch捕获或使用专用的error handling程序处理。 即使未处理,它们也会像常规PHP错误一样提供所有重要信息,并遵循整个站点的错误报告设置。

请注意,将此模式设置为连接选项将使PDO也会在连接错误上抛出exception,这一点非常重要。
所以,下面是创build一个PDO连接的例子:

$dsn = "mysql:host=$host;dbname=$db;charset=utf8"; $opt = array( PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // other options ); $pdo = new PDO($dsn, $user, $pass, $opt); 

以这种方式进行连接,将始终通知您在执行查询期间发生的所有数据库错误。 请注意,您必须能够看到一般的PHP错误。 在现场,你必须查看错误日志,所以设置必须是

 error_reporting(E_ALL); ini_set('display_errors',0); ini_set('log_errors',1); 

而在本地开发服务器上可以在屏幕上显示错误:

 error_reporting(E_ALL); ini_set('display_errors',1); 

当然你也不应该在你的PDO语句前面使用错误抑制操作符( @ )。

另外,由于很多不好的例子告诉你把每个PDO语句放到try..catch块中,我必须做一个明确的注释:

不要使用try..catch操作符来回显错误信息。 未被捕获的exception对于这个目的已经非常出色,因为它将以与其他PHP错误相同的方式运行 – 所以,您可以使用站点范围的设置来定义行为 – 因此, 您将得到没有这个无用代码的错误消息。 虽然无条件地回复错误信息可能会向潜在的攻击者揭示一些敏感信息,但却使一个诚实的访问者感到困惑。

  • 自定义exception处理程序可以稍后添加,但不是必需的。 特别是对于新用户,build议使用未处理的exception,因为它们信息丰富,有用且安全。
  • 只有在你要处理错误时才使用try..catch – 比如说回滚一个事务。

PDO准备语句在LIMIT子句中导致错误

为了兼容性的目的,除非另有说明,否则PDO将通过用实际数据替代占位符来模拟准备好的语句,而不是单独发送给服务器。 并且使用“lazy”绑定(在execute()中使用数组),PDO将把每个参数视为一个string。 因此,准备好的LIMIT ?,? 查询变为LIMIT '10', '10' ,这是导致查询失败的无效语法。

这个问题也可以解决

  • 通过closures模拟模式(因为MySQL可以正确地对所有占位符进行sorting):

     $conn->setAttribute( PDO::ATTR_EMULATE_PREPARES, false ); 
  • 通过显式绑定和设置适当的types(PDO :: PARAM_INT):

     $stm = $pdo->prepare('SELECT * FROM table LIMIT ?, ?'); $stm->bindValue(1, $limit_from,PDO::PARAM_INT); $stm->bindValue(2, $per_page,PDO::PARAM_INT); $stm->execute(); $data = $stm->fetchAll(); 

我如何使用LIKE运算符使用预处理语句?

准备好的语句只能表示完整的数据字面量 。 不是文字的一部分,也不是一个复杂的expression,也不是标识符。 但是只有string或数字 。 所以,一个非常常见的错误就是这样的查询:

 $sql = "SELECT * FROM t WHERE column LIKE '%?%'"; 

如果你仔细思考这个查询,你会明白,在单引号内,一个问号成为一个字面的问号,对于准备好的语句没有任何特殊的含义。

所以,必须使用准备好的语句发送完整的string。 有两种可能的方法:

  • 先准备好FULLexpression式:

     $name = "%$name%"; $stm = $pdo->prepare("SELECT * FROM table WHERE name LIKE ?"); $stm->execute(array($name)); $data = $stm->fetchAll(); 
  • 或者在查询中使用连接

     $sql = "SELECT * FROM t WHERE column LIKE concat('%',?,'%')"; 

尽pipe后者似乎太臃肿了。