代码拉取完成,页面将自动刷新
6
【轻量级 PR】:Imi框架将默认的PdoMysqlDriver引擎切换为 SwooleMysqlDriver引擎之后报错
已关闭
add imi-swoole/src/Db/Driver/Swore/Statement.php
主题:
Imi框架将默认的PdoMysqlDriver引擎切换为 SwooleMysqlDriver引擎之后报错
[PHP]
Version: v8.0.17
Swoole: v4.8.8
imi: v2.1.6 (0d8219e)
Timezone: PRC
Opcache: Not
imiphp/imi-swoole v2.1.7
报错内容:
类似 expects 11 parameter, 10 given ,就是少了参数
追踪源头:
1、Imi\Db\Query::buildUpdateSql、buildInsertSql等SQL构建时,无论参数是否为null,均会构建在sql语句中,例如:
update `system_crontab` set `name` = :name,`type` = :type,`target` = :target,`params` = :params,`rule` = :rule,`singleton` = :singleton,`status` = :status,`remark` = :remark,`update_op` = :update_op,`update_time` = :update_time where `id` = :p1 limit 1
这里总共11个参数
2、Imi\Swoole\Db\Driver\Swoole\Statement::execute(array $inputParameters = null): bool 在处理避免客户端提交超过DB Model的数据时,对参数进行了处理,如下:
$sqlParamsMap = $this->sqlParamsMap;
if ($sqlParamsMap)
{
foreach ($sqlParamsMap as $index => $paramName)
{
if (isset($inputParameters[$paramName]))
{
$bindValues[$index] = $inputParameters[$paramName];
}
elseif (isset($inputParameters[$key = ':' . $paramName]))
{
$bindValues[$index] = $inputParameters[$key];
}
}
}
这样,当传输的 inputParameters 中包含 null,就会被isset 给过滤掉,例如客户端提交的参数为:
{
":name":"urlCrontab",
":type":"curl",
":target":"http:\/\/127.0.0.1:9501\/123456",
":params":null, <== 注意这里的,不可避免的有空值,除非在控制器进行特殊处理;
":rule":"59 *\/1 * * * *",
":singleton":"1",
":status":"1",
":remark":"\u8bf7\u6c42127.0.0.1",
":update_op":1,
":update_time":1649513242,
":p1":1
}
这里总共11个参数,与前面Query构建的sql是一致的。
经过上面的过滤函数之后,数据就变成了:
{
"0":"urlCrontab",
"1":"curl",
"2":"http:\/\/127.0.0.1:9501\/123456",
<== 注意这里,第三个参数数据丢了
"4":"59 *\/1 * * * *",
"5":"1",
"6":"1",
"7":"\u8bf7\u6c42127.0.0.1",
"8":1,
"9":1649513242,
"10":1
}
最终导致报错,数据与sql对于需求的参数数量不一致。
解决方案
Imi\Swoole\Db\Driver\Swoole\Statement的execute函数,第189行修改
$sqlParamsMap = $this->sqlParamsMap;
if ($sqlParamsMap)
{
foreach ($sqlParamsMap as $index => $paramName)
{
if (isset($inputParameters[$paramName]))
{
$bindValues[$index] = $inputParameters[$paramName];
}
elseif (isset($inputParameters[$key = ':' . $paramName]))
{
$bindValues[$index] = $inputParameters[$key];
}else{
// for inputParameters paramName : null
$bindValues[$index] = null;
}
}
}
因为php函数中isset不仅是检测参数是否存在,也同样包含参数为null,而参数存在为null是正确的,所以最后要给他补回来。
最终,整个程序的test都能正确运行。