我偶然发现了一个(恕我直言,记录很差)事实,即默认情况下 PHP PDO 为其 MySQL 驱动程序启用了标志 MYSQL_ATTR_DIRECT_QUERY
。
这意味着它不是实际使用准备语句,而是模拟准备语句的行为。这意味着它将占位符客户端替换为转义值,并按原样将完整查询发送到数据库。
过去这样做是有充分理由的,因为在旧版本的 MySQL 下,准备好的语句会绕过查询缓存。但这种情况已经有一段时间了。仍有轻微的性能优势,因为它减少了从您的应用程序到数据库的往返次数,但我不确定这是否值得?
使用此方法的明显缺点是我们仍然依赖客户端转义,这通常不是一个好主意。我过去遇到过 mysqli_real_escape_string
的奇怪问题,由于某些字符集配置错误,允许无效字符进入查询。我宁愿不再发生类似的事情。
我只找到关于这个问题的半真半假和肤浅的评论(例如“是的,你可以启用它”或“它会导致“问题””)。寻找我不关闭它的真正原因?无论如何,在 MySQL/PDO 中使用实际准备好的语句是否与模拟的准备好的语句不兼容?
我问的部分原因是因为我们使用依赖于 PDO 的 PHPActiverecord。它不附带测试,我不希望它在生产中突然中断,因为关闭模拟的准备好的语句会巧妙地改变某些边缘情况或其他情况下的行为。
(作为旁注,在任何人提出之前:检查 PDO::ATTR_EMULATE_PREPARES
将不起作用,因为它实际上(完全)没有为 MySQL 驱动程序实现,您必须检查 PDO::MYSQL_ATTR_DIRECT_QUERY
代替。是的,那个花了我一段时间。)
澄清一下:我想知道是否有充分的理由不关闭此行为。不是我一开始就不应该关心的原因。
最佳答案
问题基于一个无效的假设:不完全支持模拟准备。 (完全支持它们)。
事实上,MYSQL_ATTR_DIRECT_QUERY 只不过是 ATTR_EMULATE_PREPARES 的别名。
源代码中的证明:connection handling和 Attribute Getter Code和 Attribute Setter Code .
setter 代码是最有说服力的。即:
390 case PDO_MYSQL_ATTR_DIRECT_QUERY:
391 case PDO_ATTR_EMULATE_PREPARES:
392 ((pdo_mysql_db_handle *)dbh->driver_data)->emulate_prepare = Z_BVAL_P(val);
393 PDO_DBG_RETURN(1);
有关为什么绝对应该关闭模拟准备的更多信息,请参阅 this answer .
关于php - 为什么我不禁用 PDO::MYSQL_ATTR_DIRECT_QUERY?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18803023/