PHP JOIN查询报错:在数组上调用get_result()成员函数
问题描述
- 运行环境:Windows 8.1.6、10.4.24-MariaDB、Apache/2.4.53 (Win64)、libmysql - mysqlnd 8.1.6、OpenSSL/1.1.1n、PHP/8.1.6
- 异常现象:SQL JOIN语句在命令行执行正常,PHP单表查询可返回记录,但执行JOIN查询时报错:
Uncaught Error: Call to a member function get_result() on array - 命令行可正常执行的SQL:
SELECT productoptionsr.contentnamekey,content.contentname LEFT JOIN content ON productoptionsr.contentnamekey=content.contentnamekey FROM productoptionsr WHERE businessnamekey='8c9007ab5e9942a80b19887057511d7b1f3c5bbea8672dc03f4fd8291f6c18ab' AND ponamekey='c91bafa8aebfb760547c761110441790f263d3c23721a5034b4d26e97b231668' ORDER BY seq;
- PHP调用查询的代码:
DBSelect($DB, "$TABLE[PRODUCTOPTIONSR]", "PRODUCTOPTIONSR.contentnamekey, CONTENT.contentname INNER JOIN CONTENT ON PRODUCTOPTIONSR.contentnamekey=CONTENT.contentnamekey", "businessnamekey='8c9007ab5e9942a80b19887057511d7b1f3c5bbea8672dc03f4fd8291f6c18ab' AND ponamekey='c91bafa8aebfb760547c761110441790f263d3c23721a5034b4d26e97b231668' ORDER BY seq");
报错原因
- SQL拼接语法错误:自定义的
DBSelect函数参数设计仅支持单表查询,它会将selection参数直接拼接在SELECT后,table参数放在FROM后,导致生成的SQL完全不符合语法规范。例如你传入的参数会生成如下错误SQL:
SELECT PRODUCTOPTIONSR.contentnamekey, CONTENT.contentname INNER JOIN CONTENT ON PRODUCTOPTIONSR.contentnamekey=CONTENT.contentnamekey FROM PRODUCTOPTIONSR WHERE businessnamekey='xxx' AND ponamekey='xxx' ORDER BY seq;
该SQL执行时会触发数据库语法错误,DBExecute捕获异常后返回的是错误信息数组(来自DBState函数),而非预期的mysqli_stmt对象。
- 类型不匹配调用错误:
DBSelect函数中直接对$stmt调用get_result()方法,但此时$stmt已经是错误信息数组,数组没有get_result()方法,因此触发Call to a member function get_result() on array错误。
解决方案
方案1:调整调用参数适配现有函数
如果不想修改DBSelect函数,可将JOIN语句移到table参数中,selection仅保留需要查询的字段:
DBSelect($DB, "$TABLE[PRODUCTOPTIONSR] INNER JOIN CONTENT ON PRODUCTOPTIONSR.contentnamekey=CONTENT.contentnamekey", "PRODUCTOPTIONSR.contentnamekey, CONTENT.contentname", "businessnamekey='8c9007ab5e9942a80b19887057511d7b1f3c5bbea8672dc03f4fd8291f6c18ab' AND ponamekey='c91bafa8aebfb760547c761110441790f263d3c23721a5034b4d26e97b231668' ORDER BY seq");
这样生成的SQL会是正确格式,能正常执行。
方案2:优化DBSelect函数增强兼容性
修改DBSelect函数,增加对关联查询的支持,并增加错误类型判断:
function DBSelect($DB, $fromClause, $selection, $conditions = "", $limit=0) { global $sql_request; // 构建基础SQL $sql = "SELECT $selection FROM $fromClause"; // 拼接条件 if (!empty($conditions)) { $sql .= " WHERE $conditions"; } // 拼接分页 if($limit>0) { $sql .= " LIMIT $limit"; } $sql_request = $sql; $result = []; try { $stmt = DBExecute($DB, $sql); // 先判断是否为错误数组 if (is_array($stmt)) { Abort("DBSelect执行失败: " . $stmt["error"] . " 查询语句: " . $stmt["query"]); } if (!($res = $stmt->get_result())) { Abort("DBSelect get_result()失败: (" . $stmt->errno . ") " . $stmt->error ." $sql"); } // 直接顺序获取数据,无需倒序再反转 while ($row = $res->fetch_assoc()) { $result[] = $row; } $stmt->close(); return $result; } catch (Exception $e) { error_log($e->getMessage()); return DBState($DB, [ "errno"=>$e->getCode(), "error"=>$e->getMessage() ]); } }
修改后,调用时可直接将包含JOIN的语句传入第一个参数$fromClause,同时避免了对错误数组调用对象方法的问题,还简化了数据获取逻辑。
内容的提问来源于stack exchange,提问作者Ran Bo
相关产品推荐
相关产品推荐

