同时运行多个 PHP 版本并不是把多个安装包直接覆盖到同一目录,而是让不同版本的 PHP 解释器各自独立存在,再根据项目或站点把请求导向对应的进程。开发环境中需要让命令行快速在 7.4、8.0、8.2 之间切换,服务器环境则更多采用 php-fpm 多实例监听不同端口,或者用 Docker 为每个版本创建独立容器。下面从开发机、Linux 服务器、Windows 和容器化四个角度说明具体做法。

开发机用 phpbrew 管理多版本
phpbrew 是一个面向 PHP 的版本管理工具,它把不同版本的 PHP 编译到用户目录下,不依赖系统包管理器,也不污染 /usr/local 等路径。安装 phpbrew 前需要准备 curl、gcc、make、libxml2-dev、libssl-dev 等编译依赖。以 Ubuntu 为例可以先执行 sudo apt install build-essential libxml2-dev libsqlite3-dev libcurl4-openssl-dev libssl-dev,然后使用官方脚本安装 phpbrew。安装完成后执行 phpbrew init,在 shell 配置文件里加入 source ~/.phpbrew/bashrc 即可。
phpbrew 安装新版本时可以按需添加编译参数和扩展。例如要安装 PHP 8.2 并启用默认扩展、FPM、MySQL 扩展,可以执行下面命令。这种方式的好处是每个版本拥有独立的扩展目录和 php.ini,不会出现 A 版本加载了 B 版本扩展导致的符号错误。
# 安装并编译 PHP 8.2,同时启用 fpm 和默认扩展 phpbrew install 8.2 +default +fpm +mysql # 切换到 8.2 作为当前 shell 的默认版本 phpbrew use php-8.2.0 # 查看当前版本 php -v
如果需要临时在某个项目中使用其他版本,可以进入项目目录后执行 phpbrew switch php-8.1.0,离开后再切回。phpbrew 还支持为同一版本同时编译多个扩展组合,这对调试扩展兼容性很有帮助。缺点是编译时间较长,CI 或临时服务器上不如直接使用预编译包。类似的工具还有 phpenv,它更轻量,但需要自己处理编译和扩展安装,适合对编译流程比较熟悉的开发者。
Linux 服务器上 php-fpm 多实例监听不同端口
生产环境通常不会重新编译 PHP,而是使用系统仓库或第三方源安装多个版本。Ubuntu 可以添加 Ondrej PPA 后同时安装 php7.4-fpm、php8.1-fpm、php8.2-fpm 等包。每个版本会生成独立的 systemd 服务,例如 php8.1-fpm.service 和 php8.2-fpm.service,默认配置文件位于 /etc/php/8.1/fpm/pool.d/www.conf 与 /etc/php/8.2/fpm/pool.d/www.conf。
默认情况下,多个版本的 FPM 可能都尝试监听同一个套接字或端口,导致后启动的服务失败。需要为不同版本分配不同的监听地址。例如让 8.1 监听 127.0.0.1:9001,8.2 监听 127.0.0.1:9002。修改配置文件中的 listen 字段即可:
; PHP 8.1 的 www.conf listen = 127.0.0.1:9001 user = www-data group = www-data ; PHP 8.2 的 www.conf listen = 127.0.0.1:9002 user = www-data group = www-data
完成配置后分别执行 systemctl restart php8.1-fpm 和 systemctl restart php8.2-fpm。接着在 Nginx 中为不同站点或不同路径指定不同的 FastCGI 后端。下面示例中,旧项目目录 /var/www/legacy 的 PHP 请求交给 9001,新项目目录 /var/www/app 的 PHP 请求交给 9002:
server {
listen 80;
server_name legacy.ipipp.com;
root /var/www/legacy;
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass 127.0.0.1:9001;
}
}
server {
listen 80;
server_name app.ipipp.com;
root /var/www/app;
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass 127.0.0.1:9002;
}
}
这个方案的优势是性能稳定,请求直接进入本机 FPM 进程,不需要额外网络层。需要注意的是,两个 PHP 版本会各自维护 session 文件和扩展配置,如果两个站点共享同一个缓存服务或数据库,要确认连接参数和扩展行为一致。服务器 CLI 默认版本可以通过 update-alternatives --set php /usr/bin/php8.1 切换,这样命令行、Composer 或定时任务会使用指定版本,但不影响已经通过 Nginx 分流到不同 FPM 的站点。
Windows 环境通过 FastCGI 端口区分版本
Windows 下同时运行多个 PHP 版本,常见方式是下载不同版本的 ZIP 包分别解压到独立目录,例如 D:\php\8.1 和 D:\php\8.2,然后让各自的 php-cgi.exe 监听不同端口。启动命令可以写成:
D:\php\8.1\php-cgi.exe -b 127.0.0.1:9001 -c D:\php\8.1\php.ini D:\php\8.2\php-cgi.exe -b 127.0.0.1:9002 -c D:\php\8.2\php.ini
这里的 -b 参数指定绑定地址和端口,-c 参数指定该版本使用的 php.ini 路径。Windows 下如果使用 Nginx,可以在 server 块中把 fastcgi_pass 指向不同端口;如果使用 IIS,可以在 FastCGI 设置中分别添加两个可执行文件,并配置不同活动目录或应用程序映射。要注意 Windows 官方 PHP 包分为线程安全和非线程安全版本,FastCGI 模式建议选择 NTS 版本,TS 版本在 Apache mod_php 或部分旧式 IIS 场景下更常见。
这种方案的优点是无需安装虚拟机或额外服务,适合本地开发和轻量测试。缺点是 php-cgi 进程不会像 Linux 下的 FPM 那样自动拉起,进程崩溃后需要手动重启。可以借助 NSSM 把 php-cgi 注册为 Windows 服务,设置启动参数后随系统启动,这样更稳定。命令行切换版本则可以通过修改系统环境变量 PATH 的顺序实现,或者编写批处理脚本临时把对应 PHP 目录放到 PATH 最前面。
用 Docker 隔离版本和扩展冲突
如果服务器上已经安装了 Docker,用容器隔离 PHP 版本是最干净的方式之一。每个容器中的 PHP、扩展和配置文件完全独立,不会互相污染。例如下面命令启动 PHP 7.4 FPM 和 PHP 8.2 FPM,分别映射到宿主机 9001 和 9002 端口:
# 启动 PHP 7.4 FPM,挂载旧项目代码 docker run -d --name php74 -p 9001:9000 \ -v /var/www/legacy:/var/www/html \ php:7.4-fpm # 启动 PHP 8.2 FPM,挂载新项目代码 docker run -d --name php82 -p 9002:9000 \ -v /var/www/app:/var/www/html \ php:8.2-fpm
Nginx 可以继续使用前面提到的 FastCGI 分流配置,只需要把 fastcgi_pass 指向宿主机对应端口。若需要额外扩展,不建议直接进入容器手工安装,而应编写 Dockerfile 基于官方镜像执行 docker-php-ext-install 或 pecl install,把扩展固化到镜像中。这样在测试、预发布和生产环境能够保持完全一致。
Docker 方案特别适合微服务或持续集成环境,可以在同一台机器上运行四个、五个甚至更多版本的 PHP,而不用担心端口冲突以外的系统依赖问题。代价是多了一层容器网络和文件系统映射,少数对文件实时性要求较高的场景需要调整挂载方式或使用卷缓存。对于宝塔面板用户,也可以在软件商店安装多个 PHP 版本,并在站点设置中选择对应版本,底层仍然是通过不同 FPM 端口或套接字实现的。
综合来看,开发机优先使用 phpbrew 或 phpenv,Linux 生产环境使用 FPM 多实例加 Nginx 分流,Windows 本地用多端口 FastCGI,需要强隔离或快速复制环境时选择 Docker。无论哪种方式,核心原则都是让每个 PHP 版本有独立的解释器、配置和扩展目录,避免共用 php.ini 或扩展路径,否则切换版本时容易出现加载失败或行为不一致。
PHP多版本共存PHP版本切换php-fpm多实例修改时间:2026-10-02 23:50:26