PHP heredoc 里写 // 注释,SQL 直接炸:用 -- 不用 //
某天下午,我在一个后台管理系统的报表接口里修了一个查询逻辑,顺手在 SQL heredoc 里加了一行 // 修复说明,php -l 检查通过,自信提交。然后上线之后,接口直接返回 500,错误日志里一行醒目的:
You have an error in your SQL syntax ... near '// 修复说明' at line 7
php -l 明明过了,为什么运行时报 SQL 语法错?
现象
php -l filename.php输出No syntax errors detected,一切正常- 线上调用报
1064 You have an error in your SQL syntax,错误 near 后面跟着//字符 - 本地直接执行 PHP 脚本同样复现,与环境无关
根因
PHP 的 // 是PHP 解析器层的行注释。但 heredoc(<<<SQL ... SQL)是字符串字面量,PHP 解析器把它当作字符串内容整体传递,不会剥离其中的任何 PHP 风格注释。
换句话说,// 出现在 heredoc 内,它就是字符串的一部分,会原封不动地被拼进最终 SQL。
当这段 SQL 送到 MySQL 时,MySQL 的注释语法只有三种:
--(双横线 + 至少一个空格)#(井号)/* ... */(块注释)
MySQL 不认识 //,于是把 // 及其后面的内容当作 SQL token 解析,直接触发 1064。
坑:php -l 通过 ≠ SQL 语法正确
php -l 只校验 PHP 语法层,字符串内容它不管。IDE 语法高亮有时也会把 heredoc 内的 // 标灰——那是 IDE 的渲染逻辑,和运行时毫无关系。两个假信号叠加,特别容易让人放松警惕。
错误示例
$sql = <<<SQL
SELECT a.id, COUNT(*) AS total
FROM orders a
LEFT JOIN order_items b ON a.id = b.order_id
WHERE a.status = 1
// 2026-05: 去掉了渠道过滤条件
AND a.created_at LIKE '{$month}%'
GROUP BY a.id
SQL;
$rows = Db::query($sql); // → MySQL 1064正解
方案 1:用 -- (SQL 标准行注释,注意后面要有空格)
$sql = <<<SQL
SELECT a.id, COUNT(*) AS total
FROM orders a
LEFT JOIN order_items b ON a.id = b.order_id
WHERE a.status = 1
-- 2026-05: 去掉了渠道过滤条件
AND a.created_at LIKE '{$month}%'
GROUP BY a.id
SQL;-- 后面必须跟至少一个空格,否则 MySQL 不识别。-- comment 是合法的,--comment 不是。
方案 2:用 /* */ 块注释(跨 DB 通用)
$sql = <<<SQL
SELECT a.id, COUNT(*) AS total
FROM orders a
WHERE a.status = 1
/* 2026-05: 去掉了渠道过滤条件 */
AND a.created_at LIKE '{$month}%'
SQL;方案 3:把注释放到 PHP 层,不进 SQL
// 2026-05: 去掉了渠道过滤条件
$sql = <<<SQL
SELECT a.id, COUNT(*) AS total
FROM orders a
WHERE a.status = 1
AND a.created_at LIKE '{$month}%'
SQL;正解:SQL 内注释用 -- (带空格)或 /* */,// 只能活在 PHP 层
改完后用 grep -n '//' yourfile.php 检查,确认 heredoc 块内没有 // 残留。或者直接跑一次 EXPLAIN <sql>,比 php -l 更早发现 SQL 语法问题。
一句话外卖
PHP heredoc 是字符串,不是代码块——
//进去就是 SQL 的一部分,MySQL 不认,换--或/* */。