PHP-PDO参数绑定问题
前言
今天在执行这样一段代码:
$data = [
'username' => 'hujingnb',
'address' => 'beijing',
];
$dbh = new PDO("mysql:host={$host};dbname={$dbname}", $username, $password);
$statement = $dbh->prepare('INSERT INTO `test_user` (`username`, `address`) VALUES (:username, :address)');
foreach($data as $key => $value ){
$statement->bindParam($key, $value);
}
$ret = $statement->execute();
这意思很明显了嘛. 但是, 当我看到插入的数据内容时, 我傻眼了.
什么? 为什么会这样, 一共就5行代码, 我哪里写的有问题?
解惑
最终, 还是编译器救了我. 我看到了这个:
注意我圈中的地方, 也就是说, 这个方法接了一个引用的值. 这样我想起了之前遇到的一个相同的坑, 具体可看我这篇文章: PHP 循环引用的问题
简单来说, 就是bindParam
方法, 接到$value
变量的地址存起来了, 每次循环拿到的都是同一个地址. 等到循环结束的时候, $value
所指定的值为数组的最后一个, 此时, statement
对象中记录的所有$value
自然也都是数组最后一个. 插入数据全部为'beijing'也就不奇怪了.
解决
既然知道了问题出在地址引用上, 解决的思路就放在地址的引用上了. 怎么解决呢?
1. unset
每次循环结束时, 都调用unset
方法, 将$value
释放调, 这样下次进入循环是,又是一个新的变量了.
foreach($data as $key => $value ){
$statement->bindParam($key, $value);
unset($value);
}
2. 将遍历去掉
不使用foreach
, 直接进行赋值, 这样也就没有中间变量的问题拉.
$statement->bindValue(":username", $data['username']);
$statement->bindValue(":address", $data['address']);
3.使用引用接
在foreach
中, 直接用引用接$value
的内容, 这样接到的本身, 就是数据value
的引用对象, 每个$value
的地址也就自然不同了.
foreach($data as $key => &$value ){
$statement->bindParam($key, $value);
}
4. 改用bindValue
和bindParams
功能差不多的方法, 还有一个bindValue
. 此方法接收的是值变量, 并不接收地址.
想来对于我们这种功能情况, 官方的想法本来就是用bindValue
方法吧, bindParams
方法暂时没想到什么使用场景.
5.直接将参数传给execute
execute
也可以接收参数的绑定. 故, 我们也可以将参数的绑定直接传给它, 中间不用调bind
方法了.
$ret = $statement->execute($data);
最后, bindParam
方法, 明显是希望 sql
已经创建之后, 其中的值会延后获取. 不过我想了想没有想到具体的应用场景.
在最后, 对于这种参数中接了引用的方法, 在foreach
中调用都要小心一些.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY