该错误与phpEnv无关,因其本质是PHP语言层面的引用传参语法规则:仅变量可按引用传递,表达式或函数返回值不可;phpEnv仅切换PHP版本,不改变此核心语义检查,故换环境无法解决。

这个错误和 phpEnv 无关,改配置、换环境都压不住——它只跟 PHP 函数的参数传递方式有关。
为什么 phpEnv 不能解决 Only variables should be passed by reference
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 版本 ≠ 关掉语言层面的语法校验。
- 你用 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+ 会明确报错,且 IDE(如 PhpStorm)通常不会标红——因为它语法合法,只是运行时报 Notice。
- 必须先提取数组:
$ids = explode(':', $row->global_id); $row->type = end($ids); - 如果
$row->global_id可能为空或非字符串,还要加is_string()判断,否则explode()会警告 - 别依赖 phpEnv 的「PHP 版本切换」来掩盖这类逻辑缺陷;它暴露的是代码结构问题,不是环境问题
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











