TLDR:除了下面显示的情况之外,还有没有人知 Prop 体情况,其中PDO::exec()
, PDO::query()
, PDO::prepare()
, 或 PDOStatement::execute()
尽管 PDO::ATTR_ERRMODE
可以返回 false 而不抛出异常被设置为 PDO::ERRMODE_EXCEPTION
?
我正在尝试决定是否要为我以后编写的每个数据库查询添加一个 false 检查,或者这是否是多余的。
编辑:我目前只使用 MySQL,但如果可移植性是一个因素,这可能足以作为决定的基础。我用 PDO::ATTR_EMULATE_PREPARES => FALSE
如果这很重要。
这就是我提到的具体案例。如果你准备一个带有 0 个或多个占位符(任一类型)的语句,然后向 PDOStatement::execute()
提供一个参数数组。元素多于占位符,false
不抛出异常就返回。请注意,如果 PDOStatement::bindValue()
执行成功(并且只有额外的绑定(bind)失败)改为使用。使用少于占位符的参数确实会引发异常,无论参数是通过数组提供给执行函数还是使用 PDOStatement::bindValue()
绑定(bind)/PDOStatement::bindParam()
.
// Execute returns false, no exception thrown
$so = $rh->pdo->prepare("SELECT * FROM config");
if($so->execute(['Test']) === FALSE) echo '1. False returned <br />';
// Execute does not return false, no exception thrown
$so = $rh->pdo->prepare("SELECT * FROM config");
if($so->bindValue(1, 'Test') === FALSE) echo '2. Binding failed <br />';
if($so->execute() === FALSE) echo '2. False not returned <br />';
// Execute returns false, no exception thrown
$so = $rh->pdo->prepare("SELECT * FROM config WHERE webmaster_name = ?");
if($so->execute(['Test', 'Wee']) === FALSE) echo '3. False returned <br />';
// Execute does not return false, no exception thrown
$so = $rh->pdo->prepare("SELECT * FROM config WHERE webmaster_name = ?");
$so->bindValue(1, 'Test');
if($so->bindValue(2, 'Wee') === FALSE) echo '4. Binding failed <br />';
if($so->execute() === FALSE) echo '4. False not returned <br />';
Outputs:
1. False returned
2. Binding failed
3. False returned
4. Binding failed
在 select 语句中,在这种情况下依赖异常并不是特别危险,因为如果您尝试在
FALSE
上调用 fetch 方法,无论如何都会发生错误。而不是 PDOStatement
目的。但是,如果您不进行错误检查,诸如 INSERTS 或 UPDATES 之类的查询可能会默默地失败。我一直在学习 PDO,我正在尝试决定 future 错误处理的一般做法。
我绝对更喜欢异常(exception),因为我已经有一个很好的站点范围的处理程序,可以针对不同的场景进行配置。并且似乎使用异常意味着更少的输入,因为您不必显式检查许多 PDO 函数的返回。
还是你? (提示戏剧音乐)
当我阅读时,我发现不止一次提到 PDO 函数(不是获取类型)返回 false 而没有抛出异常。
我的问题是检查这些函数的返回是否被认为是最佳实践,或者大多数人是否认为这是矫枉过正。
我在 SO 上看到了很多相互矛盾的陈述。我在一方面看到了许多声明:“PDO 异常是可靠的”; “当返回 FALSE 时,总是会抛出 PDO 异常”(由说“我认为是真的”的人投票赞成)。
这些是一些让我感到疑惑的评论,尽管除了我提到的那个之外,我还没有看到一个具体的例子。
来自 Can PDO methods fail and not throw PDOException? :
我似乎无法从几个测试用例中复制这个场景(我关闭了仿真模式)。
- "(Ryan Vincent) when emulates is false and ... binding types are incorrect. It may not throw an exception sometimes."
这个好像被反驳了?我不知道如何测试这个。
- "(Xorifelse) Now for committing to fail, I believe there is 1 scenario that would cause it to return
false
without throwing an exception and that is when the connection to the server drops after connecting to the database and before callingPDO::commit
, quite good to know if you have a remote database server. So to answer your question, yes it can fail without throwing an exception, but its timing has to be very specific even more so if you have a local database."
来自 will a false returned PDO execute() the same as the exception it thrown? :
这是我遇到的唯一能够复制的特定场景(见上文)。
- "(Niksac) I have seen
execute()
returningfalse
without throwing an exception which is kind of unexpected / bad behaviour in my opinion. This means that we basically have to do both - error and exception handling in parallel. In my case: if I prepared an insert query without any parameters and then executed with a parameter. Execute will not throw an exception but returnfalse
."
来自 Should I check the return value of an execute operation in pdo php :
- "(castis)
$stmt->execute()
can absolutely returnfalse
without throwing an exception."
我想我至少发现了另外一个可能的非特定提及(错误返回,无一异常(exception)),尽管我无法再次追踪它们。
在线查看 PDO 教程,其中大多数不会在使用异常模式时检查返回值。但我确实遇到了几个人推荐它。
我描述的案例不是我在日常使用中可能会搞砸的东西。或者如果我真的搞砸了,我应该立即找出答案。如果我曾经在查询中动态构建占位符或参数的数量,我会知道在这种情况下确保计数匹配和/或检查 false。
如果不是真的有必要,我只是不想检查每次使用执行、查询等的返回值。如果我提到的示例是唯一已知的情况,我会很放心地将大多数查询中的错误检查排除在外,这将允许我进行更多的方法链接:
$user_info = $rh->pdo->query("SELECT * FROM users WHERE user_id = 1")->fetch();
// vs
$so = $rh->pdo->query("SELECT * FROM users WHERE user_id = 1");
if($so === FALSE) // Throw an exception
$user_info = $so->fetch();
我想我正在寻找的是更有经验的开发人员的一些保证,可以像我看到的那样绕过这个检查。要么,要么人们告诉我他们是如何绕过该检查而被烧毁的。
最佳答案
根据您使用的数据库,肯定有不同的陷阱。如果考虑可移植性,我不会依赖上面您似乎发现的某些可能是 MySQL 的特性。
例如,有这些:
关于异常模式下的 PHP PDO - 仍然需要检查执行函数(和其他函数)的返回?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42353280/