动态 mysqli 准备语句失败
Posted
技术标签:
【中文标题】动态 mysqli 准备语句失败【英文标题】:dynamic mysqli prepared statement fails 【发布时间】:2013-02-12 07:35:19 【问题描述】:我正在尝试为我的 mysqli 连接编写一个非常小的抽象层,但遇到了问题。 由于我正在维护旧代码,我需要从我的查询中获取一个关联数组,因为这是代码的设置方式,因此一旦它工作对我来说工作量就会减少...... 此函数适用于所有类型的查询(不仅仅是选择)...
我写的函数是这样的:
function connectDB($query,$v=array())
$mysqli = new mysqli(HOST,USER,PW,DATABASE);
if($res=$mysqli->prepare($query))
//dynamically bind all $v
if($v)
$values=array($v[0]);
for($i=1; $i<count($v); $i++)
$'bind'.$i=$v[$i];
$values[]=&$'bind'.$i;
call_user_func_array(array($res,'bind_param'),$values);
$res->execute();
//bind all table rows to result
if(strtolower(substr($query,0,6))=="select")
$fields=array();
$meta=$res->result_metadata();
while($field=$meta->fetch_field())
$$field->name=null;
$fields[$field->name]=&$$field->name;
call_user_func_array(array($res,"bind_result"),$fields);
//return associative array
$results = array();
$i=0;
while($res->fetch())
$results[$i]=array();
foreach($fields as $k => $v) $results[$i][$k] = $v;
$i++;
else
$results=$mysqli->affected_rows;
if($mysqli->affected_rows<1) $results=$mysqli->info;
$res->close();
$mysqli->close();
return $results;
所以如果我打电话:
$MySqlres=connectDB("select * from `modx_events` events limit 1");
var_dump($MySqlres);
我得到了一个很好的关联数组,其中包含我选择的内容。
不幸的是,下面的 mysql 查询将返回 NULL 作为其所有数组键的值:
$MySqlres=connectDB("select *, events.`id` as `ID`,venues.`name` as `venueName`,
venues.`suburb` as `venueSuburb`,venues.`advertiser` as `venueAdvertiser`
from `modx_events` events left join `modx_venues` venues on events.`venue`=venues.`id`
where events.`id`!='e' order by events.`start_date` asc, venues.`name` limit 1");
(相同的查询作为纯 SQL 运行,并将返回正确的值) 知道这可能是什么吗?我的关联数组函数是否失败?我实现查询的方式有问题吗?
ps: PDO 不是一个选项,也没有安装 mysqlnd... :(
添加的问题
只是为了保留关联数组的返回,开销太大了吗?我应该改用$res->fetch_object()
吗?
【问题讨论】:
【参考方案1】:Mysqli 的动态预处理语句很差,这使得小型抽象层的创建成为一场噩梦。 我强烈建议您切换到 PDO 或摆脱准备好的语句并根据手动处理的占位符创建常规查询(首选)。
作为姑息补丁,您可以尝试使用get_result()
函数,该函数将返回一个常规结果变量,您可以使用fetch_assoc()
遍历常规方式
但它只适用于 mysqlnd 构建。
另请注意,为每个查询创建 mysqli 对象是一个很大的禁忌。
创建一次,然后使用global $mysqli;
在查询函数中分配它
开销太大了
我不明白你在说什么开销
【讨论】:
谢谢!我只是将实例化移动到示例的函数中。我同意没有任何实时代码! (请不要我的编辑) 我建议你使用我的抽象库而不是自己编写。它更有用并且总是有效的。您可以在我的个人资料中找到该链接。如果你想坚持自己的 - 好吧,调试它。【参考方案2】:我刚刚修复了这个功能。 也许这对其他人来说很有趣:
function connectDB($mysqli,$query,$v=array())
if($mysqli->connect_errno)
return array('error'=>'Connect failed: '.$mysqli->connect_error); //error handling here
exit();
if(substr_count($query,"?")!=strlen($v[0]))
return array('error'=>'placeholders and replacements are not equal! placeholders:'.substr_count($query,"?").' replacements:'.strlen($v[0]).' ('.$v[0].')'); //error handling here...
exit();
if($res=$mysqli->prepare($query))
//dynamically bind all $v
if($v)
$values=array($v[0]);
for($i=1; $i<count($v); $i++)
$'bind'.$i=$v[$i];
$values[]=&$'bind'.$i;
call_user_func_array(array($res,'bind_param'),$values);
$res->execute();
//bind all table rows to result
if(strtolower(substr($query,0,6))=="select")
$field=$fields=$tempRow=array();
$meta=$res->result_metadata();
while($field=$meta->fetch_field())
$fieldName=$field->name;
$fields[]=&$tempRow[$fieldName];
$meta->free_result();
call_user_func_array(array($res,"bind_result"),$fields);
//return associative array
$results=array();
$i=0;
while($res->fetch())
$results[$i]=array();
foreach($tempRow as $k=>$v) $results[$i][$k] = $v;
$i++;
$res->free_result();
else //return infos about the query
$results["affectedRows"]=$mysqli->affected_rows;
$results["info"]=$mysqli->info;
$results["insertID"]=$mysqli->insert_id;
$res->close();
return $results;
干杯
【讨论】:
以上是关于动态 mysqli 准备语句失败的主要内容,如果未能解决你的问题,请参考以下文章
mysqli_stmt::bind_param():变量的数量与准备好的语句中的参数数量不匹配