phpenv切换后web中exec('php -v')仍为旧版本,根本原因是PHP-FPM未加载shims路径:需在pool配置中显式设置env[PATH]并重启服务,且which php必须返回~/.phpenv/shims/php才表示shim机制生效。

phpenv 切换版本后 php -v 显示正确,但 exec('php -v') 或 Web 请求里还是旧版本——根本不是 phpenv 失效,而是 PATH 没真正接管子进程的执行路径。
which php 返回 /usr/bin/php 就说明 phpenv 没生效
phpenv 不是“改系统 PHP”,它靠 ~/.phpenv/shims 目录里的代理脚本转发命令。只有当 which php 输出 ~/.phpenv/shims/php,才表示 shell 正在走 phpenv 的调度链。
- 运行
which php,如果不是 shims 路径,说明PATH里有更靠前的 PHP(比如 Homebrew 的/opt/homebrew/bin/php、MAMP 的/Applications/MAMP/bin/php/...,甚至系统自带的/usr/bin/php) - 检查
echo $PATH,确认$HOME/.phpenv/shims是否排在所有其他 PHP 相关路径之前 - 编辑
~/.zshrc(macOS Catalina+ 默认)或~/.bash_profile,把这两行**放在文件最顶部**:export PATH="$HOME/.phpenv/shims:$HOME/.phpenv/bin:$PATH"eval "$(phpenv init -)" - 执行
source ~/.zshrc,再运行phpenv rehash强制重建所有 shim 脚本
exec()、system() 调用的 php 和终端里不是同一个
Web 场景下(Nginx + PHP-FPM),exec('php -v') 启动的子进程继承的是 PHP-FPM worker 进程启动时读取的环境变量,和你当前终端的 $PATH 完全无关。
- PHP-FPM 的
env[PATH]配置项决定子进程看到的PATH,默认值通常是系统启动时的原始值,不随 phpenv 变化 - 在对应 pool 的配置中(如
/etc/php/8.2/fpm/pool.d/www.conf)添加:env[PATH] = /home/yourname/.phpenv/versions/8.2.12/bin:/usr/local/bin:/usr/bin:/bin - 改完必须重启服务:
sudo systemctl restart php8.2-fpm(Ubuntu/Debian)或brew services restart php@8.2(macOS Homebrew) - 验证方式:在 PHP 脚本里写
<?php echo getenv('PATH'); ?>,对比终端里echo $PATH—— 若不一致,说明 FPM 没加载你的 PATH
phpenv init - 输出的代码到底改了什么
phpenv init - 输出的不是“设置全局变量”,而是两件事:shims 目录注入到 PATH,以及启用函数式封装(比如 phpenv 命令本身是 shell 函数,不是二进制)。
立即学习“PHP免费学习笔记(深入)”;
- 它不会修改
/etc/profile或注册表,也不会影响其他用户或其他终端会话 - shims 目录里每个文件(
php、composer、pecl)都是小 shell 脚本,根据当前phpenv shell或phpenv global设置,自动调用对应版本的真实二进制 - 所以
phpenv global 8.2后,php -v是 8.2;但若PATH里/usr/bin在shims前,which php仍返回/usr/bin/php,整个机制就绕过了 - 别漏掉
phpenv rehash:它负责扫描~/.phpenv/versions/下所有已安装版本,为每个生成对应的 shim 脚本;没这步,新装的版本根本不会出现在shims里
最容易被忽略的点是:Web 服务器和 CLI 是两套环境,PATH 配置必须分别处理。shims 解决的是你敲命令时的版本,FPM 的 env[PATH] 才决定 PHP 脚本里 exec() 调用的是哪个 php。两者缺一不可,且不能互相替代。



















