探索

整理一个基于 thinkphp 3.23 的 crm 系统,可能因为本地 PHP 版本较高的原因,本地测试出现很多 bug。

页面报错:Column not found: 1054 Unknown column 'A' in 'where clause',后面跟了一大堆的 trace 信息。通过排查,找到最终的错误文件,在模板文件中:

<php>
    if(isset($_REQUEST['time1']) && $_REQUEST['time1'] != ''&&isset($_REQUEST['time2']) && $_REQUEST['time2'] != '') { 
        $map['shijian'] = array(array('egt',I('time1').' 00:00:00'),array('elt',I('time2').' 59:59:59'));
    }
    $where['bianhao'] = array("eq",$v['bianhao']);
    $map['_complex'] = $where;
    echo M('rukus')->where($map)->sum('shuliang');
    $where="";
    $map="";
</php>

注意:代码在 html 文件中,使用了内置标签 <php></php>,并不是正常的 PHP 代码,需要编译解析。

点击查看模板内置标签 php 使用方法

整个查询使用了复合查询,复合查询的前半部分是一个区间查询,假设 time1time22019-11-13$v['bianhao']n123,查询条件为:

( ( shijian >= '2019-11-13 00:00:00' ) AND ( shijian <= '2019-11-13 59:59:59' )) AND ( bianhao = 'n123' )

当 time1、time2 不存在时,查询条件为:

bianhao = 'n123'

从正常的分析角度,写法没有问题,但结果还是报错了。网上查了一下这个错误,大部分报错情况是因为条件中的某个字段值为字符串,但没有添加上引号包裹。举个例子: bianhao = n123

通过测试确定报错点在 $where['bianhao'] = array("eq",$v['bianhao']);

查看 runtime 下的访问日志:

...
SQL: SELECT SUM(shuliang) AS tp_sum FROM `xy_rukus` WHERE `bianhao` = 'ddd' LIMIT 1   [ RunTime:0.0000s ]
...
ERR: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'A' in 'where clause'

从 SQL 语句上并不能看出端倪,先放一边。

尝试将 $where['bianhao'] = array("eq",$v['bianhao']); 改成 $where['bianhao'] = $v['bianhao'],依然报错。

也就是说,(在视图模板中字符串赋值)数组查询或者表达式查询都不可用。考虑使用字符串条件:"biaohao = '$v[bianhao]'"。所以条件改成:

...
    $where['_string'] = " bianhao = '$v[bianhao]' ";
    $map['_complex'] = $where;
...

结果还是不行。见鬼!!!

解决

使用 M('rukus')->->getLastSql(); 查看发现,错误在输出 sql 之前,也就是执行查询的语句,此路不同。

设置断点,反复查了一会儿,发现 $map 值在传入的时候,变成了 'A',这是什么情况???

通过在语句之间插入输出语句 echo px;var_dump($map);,检查 $map 和 $where 在执行查询之前的值。

最终发现,$map 初始值设为了空字符串,而在 $map['shijian'] = array(array('egt',I('time1').' 00:00:00'),array('elt',I('time2').' 59:59:59')); 赋值后,值变成了 A

思虑再三,猜测是初始值的设置的问题(虽然还是一肚子疑问,PHP 不是弱类型语言吗,变量赋值应该会自动转换类型啊)。将 $where 和 $map 初始值设为 array(),再次测试,完美,不再有任何问题。

总结

这个错误是由于 PHP 高版本变量类型转换不再自动转换造成的,初始化时为字符串类型,之后转变为数组类型失败,保留了一个 A 字符,造成了后续的 SQL 查询问题。

一开始猜想是 thinkphp 在视图模板中的 PHP 代码需要解析转换,可能使用数组条件添加的字符串类型的字段值,不能够正常地添加引号。没想到是 PHP 高版本新特性导致的。