1. 为什么 2024 年还要折腾 PHP 7.4
如果你还在维护 2020 年前后的老项目,或者接手了一个跑了好几年都没大改的业务系统,那你大概率绕不开 PHP 7.4。虽然官方安全支持已经在 2022 年 11 月终止,但现实世界里大量生产环境依然跑在 7.4 上,尤其是那些依赖老框架(Laravel 6/7、ThinkPHP 5、Yii 2)或者老扩展(比如特定版本的 MongoDB 驱动、Swoole 早期版本)的项目,直接升 8.x 往往要动不少业务代码,测试成本不低。
这篇教程就是写给这类场景的:你在 macOS 上做本地开发,但项目必须跑在 PHP 7.4 环境下。我会把从零到一的过程完整走一遍——用 Homebrew 安装 PHP 7.4、配置 php-fpm、安装常用扩展、搭配 Nginx 和 MySQL,最后整理一些我实际踩过的坑。无论你用的是 Intel 芯片的老 Mac,还是 M1/M2/M3 的 Apple Silicon,每一步我都会把差异点指出来。
先说明一点:我默认你已经装好了 Xcode Command Line Tools 和 Homebrew,如果你还没装,先把这两样搞定再往下看。命令很简单:
bash复制xcode-select --install
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
装完 Homebrew 后,建议先跑一下 brew doctor 确认环境健康,没问题再继续。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 安装前的决策:Homebrew 是唯一靠谱的选择
macOS 自带的 PHP 版本随系统更新而变动,而且系统 PHP 的配置文件分散在多个目录,扩展管理也很别扭。更关键的是,系统 PHP 不能随便动,因为 macOS 本身有些脚本依赖它,搞坏了会影响系统稳定性。
所以本地开发环境一定要用 Homebrew 的 PHP,理由有三点:
- 版本独立,不会污染系统级 PHP,两者互不干扰
- 安装路径统一在
/usr/local(Intel)或/opt/homebrew(Apple Silicon)下,文件结构清晰 - 切换版本方便,后续如果想升到 8.x,一条命令就能搞定
还有一个决策点是:PHP 7.4 官方已经停止维护,Homebrew 的核心仓库也把相关 formula 移除了,所以安装时需要从 shivammathur/php 这个第三方 tap 获取。这个 tap 是目前维护 PHP 旧版本最活跃的源,针对 macOS 各版本都有对应构建,实测下来可靠性很高。
3. 完整安装流程:从添加 tap 到验证版本
3.1 添加 tap 源
bash复制brew tap shivammathur/php
这个 tap 仓库专门提供 PHP 5.6 到 8.4 的各类版本,支持 Intel 和 Apple Silicon。添加完之后,你可以先搜索确认一下 7.4 是否在列表里:
bash复制brew search php@7.4
正常会返回 shivammathur/php/php@7.4 这样的结果。看到它就可以放心安装了。
3.2 安装 PHP 7.4
bash复制brew install shivammathur/php/php@7.4
这一步会连带安装一些依赖库,比如 libxml2、sqlite、openssl、oniguruma 等。整个过程需要几分钟,取决于你的网速和机器性能。装完后,终端会提示你 PHP 7.4 是 keg-only 的,也就是说它不会被自动链接到 /usr/local/bin 或 /opt/homebrew/bin,需要手动配置 PATH。
3.3 配置 PATH
在 ~/.zshrc(如果你用的是 zsh)里加一行:
bash复制export PATH="/opt/homebrew/opt/php@7.4/bin:$PATH"
export PATH="/opt/homebrew/opt/php@7.4/sbin:$PATH"
注意路径前缀:Apple Silicon 机器是 /opt/homebrew/opt/,Intel 机器是 /usr/local/opt/。这一点特别容易搞混,我见过不少人因为路径写错导致装了新版本却始终用的是系统自带 PHP。
保存后执行:
bash复制source ~/.zshrc
php -v
如果输出类似 PHP 7.4.33 (cli) (built: ...),说明安装成功。7.4.33 是 7.4 系列的最后一个版本,也是整个分支最稳定的版本,遇到它很正常。
3.4 确认 php-fpm
CLI 版本没问题后,再看看 php-fpm:
bash复制php-fpm -v
如果提示找不到命令,检查一下 /opt/homebrew/opt/php@7.4/sbin 是否在 PATH 里。php-fpm 是 PHP FastCGI 进程管理器,后面搭配 Nginx 就要靠它处理 PHP 请求。
注意:PHP 7.4 在较新的 macOS(特别是 Sonoma 及以上)上运行时,可能会因为编译配置问题报一些警告,不影响正常使用,但如果你遇到
dyld相关报错,后面第 8 节会有排查方案。
4. 核心配置:让 php-fpm 跑得顺手
4.1 配置文件位置
Homebrew 安装的 PHP 7.4 配置路径如下:
- 主配置:
/opt/homebrew/etc/php/7.4/php.ini - 池配置:
/opt/homebrew/etc/php/7.4/php-fpm.d/www.conf - php-fpm 主配置:
/opt/homebrew/etc/php/7.4/php-fpm.conf
当你需要改 PHP 参数(比如 memory_limit、upload_max_filesize、display_errors),改的是 php.ini;当你需要调整进程数、用户权限、监听方式时,改的是 php-fpm.d/www.conf。
4.2 推荐的基础参数
先看 php.ini,以下几个参数是本地开发时几乎必调的:
ini复制memory_limit = 512M
upload_max_filesize = 20M
post_max_size = 20M
max_execution_time = 60
display_errors = On
error_reporting = E_ALL
本地环境一定要把 display_errors 打开,否则代码报错只给你一个白屏,排查效率极低。memory_limit 设 512M 是因为 Composer、PHPUnit 这类工具在跑大项目时内存吃得很凶,默认的 128M 很容易爆。
再看 www.conf,重点是这几项:
ini复制user = $(whoami)
group = $(staff)
listen = 127.0.0.1:9000
pm = dynamic
pm.max_children = 20
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10
user 和 group 默认是 _www,这是 Web 服务专用账号,但本地开发时文件权限经常出问题——比如你用 php artisan 命令生成的日志文件属主是你自己,而 php-fpm 进程是 _www 用户,就会产生权限不足的报错。所以本地环境直接改成你的用户名最省事。
listen 选择 127.0.0.1:9000 是 TCP 方式,方便后面 Nginx 用 fastcgi_pass 127.0.0.1:9000 连接。也可以改成 Unix Socket 方式(listen = /tmp/php-cgi.sock),性能略好,但配置多一步,新手建议先用 TCP,调通后再考虑优化。
4.3 启动和停止
用 brew services 管理最方便,开机自启,免去手动启动的麻烦:
bash复制brew services start php@7.4
如果你不想开机自启,只是临时用一下,也可以手动跑:
bash复制/opt/homebrew/opt/php@7.4/sbin/php-fpm --fpm-config /opt/homebrew/etc/php/7.4/php-fpm.conf
启动后确认一下进程状态:
bash复制ps aux | grep php-fpm
能看到 master 进程和几个 worker 进程就说明跑起来了。
5. 扩展安装:pecl 与编译的取舍
5.1 pecl 一条路走到底
PHP 7.4 自带的 pecl 命令可以用来安装绝大多数 PECL 扩展,这是最推荐的方式。比如安装 Redis 扩展:
bash复制pecl install redis
安装过程会问你 enable igbinary serializer support? 之类的问题,本地开发直接按回车选默认就行。装完后在 php.ini 末尾加一行:
ini复制extension=redis.so
然后在命令行验证:
bash复制php -m | grep redis
看到 redis 就说明加载成功了。
5.2 需要编译安装的场景
有些扩展不在 PECL 仓库里,或者版本比较特殊,需要手动编译。这种情况一般分三步:下载源码、phpize 初始化、configure && make && install。
以 swoole 为例(假设你的项目需要特定版本):
bash复制git clone https://github.com/swoole/swoole-src.git
cd swoole-src
git checkout v4.6.7
phpize
./configure
make -j$(sysctl -n hw.ncpu)
sudo make install
编译时间看机器性能,一般几分钟到十几分钟。装完后别忘了在 php.ini 里加 extension=swoole.so。
注意:编译扩展时如果报
Cannot find config.m4,说明你下载的源码目录不对,或者没有在源码根目录执行phpize。这是最常见的问题,遇到时先检查当前目录。
5.3 必装扩展清单
根据我维护老项目的经验,下面几个扩展在 PHP 7.4 环境里几乎必装:
bcmath:高精度数学运算,Laravel 的货币计算、优惠券分摊逻辑经常用到intl:国际化支持,很多框架的本地化功能依赖它opcache:OPcache 能显著提升 PHP 执行效率,本地开发虽然效果不明显,但生产环境必开redis:连接 Redis 服务pdo_mysql:连接 MySQL 数据库,这个在编译 PHP 时通常已经内置,如果php -m里没有,需要确认你用的是哪个 PHP
bcmath 和 intl 在 Homebrew 的 PHP 7.4 formula 里可能默认没启用。检查方式:
bash复制php -m | grep -E "bcmath|intl"
如果为空,需要单独安装。intl 在 Homebrew 里是通过 icu4c 依赖支持的,有时会因为 ICU 版本不匹配导致安装失败,这种问题我会在第 8 节展开。
6. 搭配 Nginx:让浏览器跑起你的项目
6.1 安装 Nginx
bash复制brew install nginx
Nginx 默认监听 8080 端口,因为 80 端口在 macOS 上经常被其他服务占用。本地开发用 8080 完全够用,没必要去折腾端口映射。
6.2 配置 PHP 站点
Nginx 主配置在 /opt/homebrew/etc/nginx/nginx.conf,建议不要直接改主文件,而是在 /opt/homebrew/etc/nginx/servers/ 目录下新建一个站点配置。这个目录在主配置里默认已经 include 了,直接把配置文件扔进去就行。
创建一个 php-site.conf:
nginx复制server {
listen 8080;
server_name localhost;
root /Users/yourname/projects/myapp/public;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.ht {
deny all;
}
}
重点解释几个关键点:
root指向你项目的public目录,Laravel、ThinkPHP 这类框架都是这个结构try_files这行的作用是把所有不存在的文件请求重写到index.php,这是现代 PHP 框架的标配入口方式fastcgi_pass必须和 php-fpm 的listen保持一致,都是127.0.0.1:9000SCRIPT_FILENAME必须用$document_root拼接,很多人漏了这行导致页面空白
改完配置后:
bash复制nginx -t
检查语法没问题后重载配置:
bash复制nginx -s reload
浏览器访问 http://localhost:8080,如果能看到你的项目页面,那就通了。
6.3 遇到空白页怎么办
页面空白说明 PHP 进程没正常执行。先看 php-fpm 日志:
bash复制tail -f /opt/homebrew/var/log/php-fpm.log
再看 Nginx 错误日志:
bash复制tail -f /opt/homebrew/var/log/nginx/error.log
日志会告诉你具体原因,最常见的就是 SCRIPT_FILENAME 配置错误,或者 php-fpm 没启动。按图索骥排查就行。
7. 配套数据库与服务:MySQL 8.0 和 Redis
7.1 安装 MySQL 8.0
bash复制brew install mysql@8.0
同样,mysql@8.0 也是 keg-only,需要手动链接:
bash复制brew link mysql@8.0 --force
启动服务:
bash复制brew services start mysql@8.0
默认安装后 root 用户没有密码,本地开发可以先用着,但建议还是设置一下:
bash复制mysql_secure_installation
按提示设置 root 密码、移除匿名用户、禁用远程 root 登录,这些都对。
7.2 安装 Redis
bash复制brew install redis
brew services start redis
测试连通性:
bash复制redis-cli ping
返回 PONG 就正常。
到这里,一套完整的 PHP 7.4 开发环境就跑起来了:PHP 7.4 + php-fpm + Nginx + MySQL 8.0 + Redis,项目所需的配套服务基本齐了。
8. 常见问题与排查技巧实录
8.1 php -v 显示的不是 7.4
这是最常遇到的问题。装了 7.4 但 php -v 还是显示系统自带 PHP,原因基本是 PATH 配置不对。检查一下:
bash复制which php
如果输出的是 /usr/bin/php,说明你的 PATH 里系统目录排在 Homebrew 目录前面。回到第 3.3 节,确认 ~/.zshrc 里 export 的那两行没有被二次覆盖,并且你确实执行了 source ~/.zshrc。
8.2 扩展安装后 php -m 里看不到
分两种情况:
- 如果
php -m | grep redis没有任何输出,先确认你把extension=redis.so加到了正确的php.ini。用php --ini查看实际加载的配置文件路径,有时候你改的是/etc/php.ini,但 PHP 实际加载的是/opt/homebrew/etc/php/7.4/php.ini,改了等于白改 - 如果
php -m里能看到,但 php-fpm 跑起来后访问页面报类找不到,说明 php-fpm 加载的配置文件和你 CLI 不是同一个。用php-fpm -i | grep 'Loaded Configuration File'确认
这种情况通常是因为系统存在多个 PHP 版本,配置文件各自独立,排查时要先统一使用 Homebrew 的 PHP,把系统 PHP 的路径从 PATH 里彻底移除。
8.3 intl 扩展安装失败,ICU 版本冲突
intl 扩展依赖 ICU 库,而 macOS 系统自带的 ICU 版本和 Homebrew 的 PHP 7.4 编译时用的版本可能不一致,导致 configure 阶段报错。
解决方法是显式指定 ICU 路径:
bash复制export ICU_INCLUDE=/opt/homebrew/opt/icu4c/include
export ICU_LIBS="-L/opt/homebrew/opt/icu4c/lib"
pecl install intl
如果还是不行,可以试试先升级 icu4c:
bash复制brew upgrade icu4c
然后重新安装扩展。
8.4 php-fpm 启动后端口被占用
如果 listen = 127.0.0.1:9000 被其他进程占用,php-fpm 会启动失败。用下面命令查看:
bash复制lsof -i :9000
如果确实有进程占用,可以先停掉冲突的进程,或者把 php-fpm 的监听端口改成 9001,同时同步修改 Nginx 的 fastcgi_pass。
8.5 大文件上传超时
本地测试上传大文件遇到 502 或超时,一般和两个参数有关:PHP 的 max_execution_time 和 Nginx 的 proxy_read_timeout。PHP 这边在第 4.2 节已经调过了,Nginx 侧需要在 location ~ \.php$ 块里加上:
nginx复制fastcgi_read_timeout 300;
本地调试时 300 秒足够应对大多数情况。
8.6 Homebrew 升级后 PHP 7.4 被清理
brew upgrade 不会主动删除旧版本,但如果没锁定版本,某些操作可能会把 7.4 的链接弄丢。保险起见:
bash复制brew pin php@7.4
这样在全局升级时,PHP 7.4 会被跳过,避免意外升级导致本地环境失效。
9. 最后再分享几个小技巧
我个人的使用习惯是,把常用的启停命令封装成 alias:
bash复制alias php7-start="brew services start php@7.4"
alias php7-stop="brew services stop php@7.4"
alias nginx-restart="nginx -s reload"
写进 ~/.zshrc 里,日常开发效率会高不少。
另外一个建议是:本地环境尽量保持和线上环境一致。如果线上是 CentOS + PHP 7.4 + Nginx + MySQL 5.7,本地就尽量做同一版本组合,避免出现"本地好好的,上线就炸"的尴尬。macOS 和 Linux 虽然底层不同,但 PHP 层面的行为和配置项基本一致,差距主要在扩展安装方式上,至少能规避大部分版本相关的坑。
这套环境我前后用过一年多,从 Intel Mac 换到 Apple Silicon 后,重新安装一遍也只用了一个多小时。最大的心得就是:不要和系统 PHP 纠缠,不要手动往 /usr/local 里乱塞东西,一切交给 Homebrew 管理,出问题时也能快速重来。希望这篇教程能帮你少走点弯路。
