phpEnv解决PHP Notice: Only variables should be passed by reference
PHP引用传参错误的本质是仅变量可按引用传递,表达式或函数返回值无法使用。常见触发函数如end()、array_pop()等。正确做法是先赋值给变量再传入。切换PHP环境无法解决此问题,应修正代码结构以符合要求。
该错误与 phpEnv 无关,因其本质是 PHP 语言层面的引用传参语法规则:仅变量可按引用传递,表达式或函数返回值不可;phpEnv 仅切换 PHP 版本,不改变此核心语义检查,故换环境无法解决。

很多人遇到这个报错第一反应是换环境、改配置,折腾一圈发现还是压不住。其实问题的根子在 PHP 函数传参方式上,跟 phpEnv 半点关系都没有。
为什么 phpEnv 解决不了这个问题
phpEnv 是个本地 PHP 环境管理工具,主要帮你在不同 PHP 版本(比如 7.4、8.1、8.3)之间快速切换。但它改变不了 PHP 引擎对「引用传参」的语法检查规则。这个报错从 PHP 5.3 时代就存在了,PHP 7+ 和 PHP 8.x 全系列都有,只要 error_reporting 里包含了 E_NOTICE 或 E_STRICT(现在已经合并到 E_ALL 里了),它就会在运行时冒出来。
换个说法:用 phpEnv 装 PHP 8.2,写 array_pop(explode('@', $str)) 一样报错。把 error_reporting 设为 0 或者只保留 E_ERROR | E_WARNING 确实能看到提示消失了,但这只是掩耳盗铃,隐患还在代码里。phpEnv 没有提供所谓的「绕过引用检查」开关——也不该有这种开关。
哪些函数会直接触发这个 Notice
问题的根源在于:这些函数内部的参数声明为引用传递(&$array),所以调用时传的必须是一个变量,不能是表达式或者函数返回值:
end()、current()、next()、prev()、reset()—— 数组指针操作函数array_pop()、array_shift()、array_splice()—— 修改原数组的函数mysqli_stmt::bind_param()—— 预处理绑定时,第三个及以后的参数要注意preg_match()的第三个参数&$matches—— 如果写成preg_match($p, $s, $arr ?? [])就会出错
来看看典型的错误写法:
$host = end(explode('@', $email)); // ❌
$stmt->bind_param('ss', $user, md5($pass)); // ❌
preg_match('/(\d+)/', $str, $matches ?? []); // ❌
正确写法:拆成两步,显式使用变量
核心原则很简单:让被引用的参数位置上出现一个「有地址的变量名」,而不是一个临时的计算结果。
- 先把
explode()的结果赋给一个变量,再传给end()或array_pop() - 预处理绑定密码时,别在
bind_param()里直接调用sha1()或password_hash(),要么在 SQL 里处理,要么提前算好存到变量里 - 用
?? []或三元运算符时,确保最终传进去的是变量,不是表达式
修正后的代码:
$parts = explode('@', $email);
$host = end($parts); // ✅
$password_hash = password_hash($pass, PASSWORD_DEFAULT);
$stmt->bind_param('ss', $user, $password_hash); // ✅
$matches = [];
preg_match('/(\d+)/', $str, $matches); // ✅
容易被忽略的坑:对象属性 + 引用函数组合
比如这种写法:$row->type = end(explode(':', $row->global_id)),表面上看是在赋值操作,但 end() 需要引用一个数组,而 explode(...) 返回的是临时数组,没有变量名指向它。
这种写法在 PHP 7.4+ 会明确报 Notice,而且 IDE(比如 PhpStorm)通常不会标红——因为语法层面它是合法的,只有运行时才会暴露问题。
- 正确的做法是先提取数组:
$ids = explode(':', $row->global_id); $row->type = end($ids); - 如果
$row->global_id可能为空或不是字符串,还要加is_string()判断,否则explode()本身也会发出警告 - 别指望通过 phpEnv 切换 PHP 版本来掩盖这类逻辑问题——它暴露的是代码结构缺陷,跟环境没有关系


































