
1. Mac 上 PHP 开发环境到底难在哪在 Mac 上折腾 PHP 开发环境几乎每个后端或全栈方向的人都经历过一段不太愉快的时光。macOS 自带的 PHP 版本往往偏旧而且随着系统升级会被直接移除用 Homebrew 装 PHP 又经常遇到依赖冲突、扩展缺失、配置文件路径混乱的问题想同时维护多个项目、跑不同 PHP 版本时切换成本更是高得离谱。我自己最早是用 Homebrew 手动装 PHP再单独编译扩展后来换成 Docker 方案虽然隔离性好但每次改配置都要重建镜像调试体验并不算顺畅。FlyEnv 这个工具就是冲着这些痛点来的。它把 PHP、Nginx、MySQL、Redis、Node.js 等常用开发组件打包成一套可视化管理方案在 Mac 上装完之后基本不用再碰命令行去处理环境问题。这篇文章我会从实际使用角度出发把 FlyEnv 在 Mac 上的安装、配置、多版本管理、常见坑点全部拆开讲一遍适合正在被 PHP 环境折磨的开发者也适合刚接触 Mac 开发环境的新手参考。提示本文所有操作均基于 macOS 本地开发场景不涉及任何服务器部署或网络代理相关内容。2. 为什么我最终选了 FlyEnv 而不是继续手搓2.1 传统 Mac PHP 环境方案的三个死结在聊 FlyEnv 之前先说说我踩过的那些坑这样你才能理解为什么一个“一站式”工具值得单独写一篇。第一个死结是Homebrew 的版本管理混乱。Homebrew 默认只保留最新版本的 PHP想装 PHP 7.4 或者 8.0 需要额外 tap而且不同版本之间的扩展路径、ini 文件位置都不一样。我试过在一台机器上同时装 PHP 7.4 和 PHP 8.2结果php -v输出的版本和php-fpm实际加载的版本对不上排查了半天才发现是 PATH 顺序问题。第二个死结是扩展安装门槛高。PHP 的很多扩展比如 imagick、swoole、redis在 Mac 上需要先装系统级依赖再用 pecl 编译。每次系统升级或者 PHP 版本切换这些扩展都要重新编译一遍非常消耗时间。第三个死结是服务管理分散。Nginx、MySQL、Redis 各自用不同的方式启动有的用 brew services有的用 launchctl端口冲突、进程残留是家常便饭。尤其是 MySQL经常出现“上次没关干净这次启动报端口占用”的情况。2.2 FlyEnv 的核心思路把环境当“应用”来管FlyEnv 的设计逻辑和上面这些方案完全不同。它不依赖系统级的包管理器去装 PHP而是自己维护一套独立的运行时目录每个组件PHP、Nginx、MySQL 等都是独立安装、独立配置、独立启停的。你可以把它理解成一个“开发环境的应用商店”需要什么就装什么装完在界面里点一下就能启动。这种设计带来的直接好处有三个。一是版本切换零成本装多个 PHP 版本后在界面里点一下就能切换全局默认版本不需要改 PATH 或重启终端。二是配置可视化Nginx 的 vhost、PHP 的 ini、MySQL 的 my.cnf 都能在界面里直接编辑改完点保存就生效不用去记那些深埋在/usr/local/etc里的路径。三是服务状态一目了然哪个服务在跑、占哪个端口、日志在哪界面上直接看得到。2.3 和其他方案的横向对比方案版本切换扩展管理服务管理上手成本适合场景Homebrew 手动装麻烦需编译分散高喜欢完全掌控的资深用户Docker简单镜像内解决集中中需要环境隔离的团队MAMP简单受限集中低只跑简单项目FlyEnv简单界面化集中低多版本、多项目的日常开发Docker 方案虽然隔离性好但在 Mac 上文件挂载的性能损耗比较明显尤其是跑 Laravel 这种文件读写频繁的框架时响应速度会慢一截。FlyEnv 是原生运行没有这层损耗这也是我最终选它的重要原因。3. Mac 上安装 FlyEnv 的完整流程3.1 安装前的系统检查和准备在装 FlyEnv 之前有几个前置条件需要确认。首先是 macOS 版本建议在 macOS 12 及以上老版本系统可能会遇到运行时库不兼容的问题。其次是磁盘空间FlyEnv 本身不大但如果你打算装多个 PHP 版本加 MySQL建议预留至少 10GB 空间。检查系统版本可以直接在终端里跑sw_vers输出里ProductVersion就是当前系统版本。另外确认一下当前用户是否有管理员权限因为 FlyEnv 安装某些组件时需要写入/Applications目录。注意如果你的 Mac 是 Apple Silicon 芯片M1/M2/M3下载时一定要选 arm64 版本选成 x86 版本虽然能通过 Rosetta 运行但性能会打折扣而且某些扩展可能编译失败。3.2 下载与首次启动的注意事项FlyEnv 官网提供了 macOS 的 dmg 安装包下载后直接拖进 Applications 文件夹即可。首次打开时macOS 可能会提示“无法验证开发者”这是因为应用没有走 App Store 签名流程。解决办法是在“系统设置 - 隐私与安全性”里找到对应的提示点击“仍要打开”。启动后FlyEnv 会引导你选择数据目录。默认是在用户目录下的.flyenv文件夹我建议保持默认不要改到外置硬盘或者 iCloud 同步目录里因为数据库文件放在同步目录下容易出问题。首次启动还会让你选择要安装的基础组件。这里不用全选按需来就行。我一般先装 PHP、Nginx、MySQL 这三个Redis 和 Node.js 后面用到再装。3.3 安装 PHP 时的版本选择逻辑FlyEnv 的 PHP 版本列表覆盖了从 5.6 到 8.3 的主流版本。选哪个版本取决于你的项目需求。如果是维护老项目可能需要在 PHP 7.4 上跑如果是新项目直接上 PHP 8.2 或 8.3。我自己的做法是装三个版本PHP 7.4 用来兼容老代码PHP 8.1 作为主力开发版本PHP 8.3 用来测试新特性。装完之后在 FlyEnv 的 PHP 管理界面里可以给每个版本单独配置 ini 参数和扩展。安装过程中 FlyEnv 会自动下载对应的运行时包速度取决于网络情况。如果下载卡住可以检查一下是否有其他程序占用了大量带宽。3.4 配置 Nginx 和 MySQL 的关键参数Nginx 装完后默认会监听 80 端口。如果你的 Mac 上已经有其他程序占了 80 端口比如系统自带的 Apache需要先在 FlyEnv 里把 Nginx 的监听端口改成 8080 或者其他空闲端口。MySQL 的默认配置里max_connections是 151对于本地开发来说够用了。但如果你经常跑大量并发测试可以调到 500。另外innodb_buffer_pool_size默认值偏小建议调到 256M 或 512M能明显改善查询性能。[mysqld] max_connections 500 innodb_buffer_pool_size 512M character-set-server utf8mb4 collation-server utf8mb4_unicode_ci改完配置后记得在界面上点“重启”让配置生效直接关掉再开有时候不会重新加载配置文件。4. 多版本 PHP 切换与扩展管理的实操细节4.1 全局版本与项目级版本的切换方式FlyEnv 的 PHP 版本切换分两个层级。全局切换是在 PHP 管理界面里点“设为默认”这个操作会修改终端里php命令指向的版本。项目级切换则是通过 FlyEnv 生成的 vhost 配置来实现的每个站点可以指定用哪个 PHP 版本处理。举个例子我有两个项目一个跑在 PHP 7.4 上一个跑在 PHP 8.2 上。在 FlyEnv 的“网站”模块里分别给两个项目建 vhost然后在每个 vhost 的 PHP 版本选项里选对应的版本。这样访问不同的本地域名时Nginx 会自动把请求转发给对应版本的 PHP-FPM 处理互不干扰。这个机制的原理是 FlyEnv 为每个 PHP 版本单独启动了一个 php-fpm 进程监听不同的 socket 或端口Nginx 根据 vhost 配置里的fastcgi_pass指向不同的进程。4.2 常用扩展的一键安装与手动编译FlyEnv 的 PHP 扩展管理界面里列出了常用的扩展如 redis、imagick、swoole、xdebug 等勾选后点安装即可。它背后做的事情是下载预编译好的扩展包放到对应 PHP 版本的扩展目录然后在 ini 里加上extension行。但并不是所有扩展都有预编译包。遇到没有的扩展时就需要手动编译。FlyEnv 提供了“手动安装扩展”的入口你需要先把扩展源码下载到本地然后在界面里指定源码路径它会调用对应版本的phpize和php-config来编译。提示手动编译扩展前确保已经通过 FlyEnv 安装了对应 PHP 版本的开发工具包包含 phpize 和 php-config否则编译会报找不到命令。4.3 php.ini 的修改与生效验证FlyEnv 里每个 PHP 版本都有独立的 php.ini 文件可以在界面上直接打开编辑。常见的修改包括调整upload_max_filesize、post_max_size、memory_limit等。改完之后怎么验证生效了最直接的方法是在终端里跑php -i | grep memory_limit如果输出的值和你改的一致说明生效了。但要注意终端里的php命令用的是全局默认版本如果你改的是非默认版本的 ini需要在 FlyEnv 里切换到那个版本再验证或者直接通过浏览器访问phpinfo()页面查看。4.4 扩展加载顺序引发的典型问题PHP 扩展的加载顺序有时候会影响功能。比如opcache必须在其他扩展之前加载xdebug如果加载太早可能会和某些扩展冲突。FlyEnv 默认的加载顺序是经过测试的一般不需要改。但如果你手动添加了扩展发现某个功能异常可以检查一下 ini 里extension行的顺序。我遇到过一次redis扩展和igbinary扩展的加载顺序问题导致 redis 序列化数据时出错。把igbinary调到redis前面就好了。这类问题比较隐蔽排查时可以先看 PHP 错误日志里面通常会有扩展加载相关的警告。5. 本地站点配置与数据库管理的实战操作5.1 用 FlyEnv 建站从域名到根目录在 FlyEnv 里建一个本地站点流程比手动改 Nginx 配置简单很多。点“新建网站”填几个关键信息就行域名比如myproject.test、根目录指向项目的 public 目录、PHP 版本、是否开启 HTTPS。域名解析这块FlyEnv 会自动帮你写 hosts 文件把myproject.test指向 127.0.0.1。不需要手动去改/etc/hosts省了一步操作。如果你用的域名后缀不是.test比如.local可能会和 macOS 的 Bonjour 服务冲突建议统一用.test后缀。根目录的选择有个细节Laravel 项目要指向public目录ThinkPHP 也是指向public而 WordPress 则是指向项目根目录。选错了会导致 404 或者源码泄露建站时注意一下。5.2 HTTPS 本地证书的生成与信任FlyEnv 支持给本地站点开启 HTTPS它会自动生成自签名证书。但自签名证书浏览器默认不信任访问时会弹安全警告。解决办法是把 FlyEnv 生成的根证书导入到 macOS 的钥匙串里并设为“始终信任”。具体操作是在 FlyEnv 的证书管理界面里导出根证书然后双击导入钥匙串在“系统”钥匙串里找到这个证书右键“显示简介”在“信任” section 里把“使用此证书时”改为“始终信任”。这样之后所有由这个根证书签发的站点证书都会被浏览器信任。5.3 MySQL 数据库的创建、导入与导出FlyEnv 内置了数据库管理工具可以直接在界面上创建数据库、执行 SQL、导入导出数据。对于日常开发来说最常用的操作是导入生产环境的脱敏数据到本地。导入时有个坑要注意如果 SQL 文件比较大超过 100MB直接在界面里导入可能会超时。这时候可以用命令行方式mysql -h 127.0.0.1 -P 3306 -u root -p your_database backup.sqlFlyEnv 的 MySQL 默认 root 密码是空的如果你改了密码记得在命令里用-p参数输入。另外导入前最好先确认一下 SQL 文件的字符集如果是utf8mb4的数据库创建时也要用utf8mb4否则中文会乱码。5.4 Redis 和 Node.js 的联动配置现在很多 PHP 项目会用到 Redis 做缓存或队列前端可能还用 Node.js 跑构建工具。FlyEnv 里这两个组件也是独立管理的。Redis 装完后默认监听 6379 端口PHP 项目里配置 Redis 连接时host 写127.0.0.1port 写6379就行。如果 Redis 设置了密码记得在 PHP 的 Redis 配置里同步。Node.js 的版本管理 FlyEnv 也支持可以装多个版本并按项目切换。对于前端项目来说这个功能很实用因为不同项目依赖的 Node 版本可能不一样。6. 常见问题排查与避坑经验实录6.1 端口冲突的排查思路端口冲突是本地开发环境最常见的问题。表现是服务启动失败日志里提示Address already in use。排查方法是先用lsof查一下端口被谁占了lsof -i :80 lsof -i :3306 lsof -i :6379输出里会显示占用端口的进程 PID 和名称。如果是之前没关干净的进程直接kill -9 PID干掉就行。如果是系统服务占用了比如 macOS 自带的 Apache 占了 80 端口可以在 FlyEnv 里把 Nginx 端口改成 8080。6.2 PHP-FPM 启动失败的几种原因PHP-FPM 启动失败通常有几个原因。一是配置文件语法错误比如 ini 里多了一个引号或者少了一个分号。二是 socket 文件路径不存在或权限不对。三是依赖的扩展加载失败导致 php-fpm 进程直接退出。排查时先看 FlyEnv 里的错误日志里面会显示具体的错误行。如果是配置文件问题FlyEnv 通常会提示哪一行有语法错误。如果是扩展问题可以先把可疑的扩展注释掉再逐个启用来定位。6.3 数据库连接被拒绝的解决路径“Connection refused” 这个错误在 MySQL 上很常见。原因可能是 MySQL 服务没启动、端口不对、或者绑定地址限制。FlyEnv 的 MySQL 默认绑定127.0.0.1如果你从 Docker 容器里连需要改成0.0.0.0。另一个常见原因是 MySQL 8.0 之后的认证插件变了默认用caching_sha2_password老版本的 PHP 客户端可能不支持。解决办法是在 MySQL 里把用户的认证方式改成mysql_native_passwordALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY your_password; FLUSH PRIVILEGES;6.4 系统数据清理与 FlyEnv 的磁盘占用Mac 用久了“系统数据”会越来越大FlyEnv 的运行时文件、日志、数据库文件也会占不少空间。定期清理是有必要的。FlyEnv 的日志文件可以在界面上直接清空数据库的 binlog 如果不需要也可以关掉。另外每个 PHP 版本的运行时目录里会有一些缓存文件可以在切换版本时清理一下。我一般每个月检查一次把不用的 PHP 版本和对应的数据库备份删掉能释放好几个 G 的空间。6.5 常见问题速查表问题现象可能原因解决方式Nginx 启动报端口占用80 端口被其他程序占用改 Nginx 端口或关掉占用程序PHP-FPM 启动失败ini 语法错误或扩展加载失败查看错误日志注释可疑扩展MySQL 连接被拒绝服务未启动或认证插件不兼容启动服务改认证方式为 native本地域名无法访问hosts 未生效或 DNS 缓存检查 hosts刷新 DNS 缓存HTTPS 证书不受信任根证书未导入钥匙串导出根证书并设为始终信任扩展安装后不生效ini 未加载或加载顺序问题检查 ini 中 extension 行顺序7. 我个人的使用体会与几个实用建议用 FlyEnv 这段时间最大的感受是它把“环境管理”这件事从“需要专门花时间维护”变成了“几乎不用管”。以前每次换项目或者系统升级都要花半天时间重新配环境现在这些操作在界面上点几下就完成了。有几个小建议可以分享。一是不要装太多 PHP 版本虽然切换方便但每个版本都占空间而且扩展要分别装维护成本会上升。一般两到三个版本足够覆盖大部分场景。二是定期备份数据库FlyEnv 的数据库文件在数据目录里虽然本地开发数据丢了影响不大但有些测试数据积累起来也不容易。三是关注 FlyEnv 的更新新版本通常会修复一些兼容性问题尤其是 macOS 系统升级后及时更新能避免很多莫名其妙的报错。另外如果你之前用 Homebrew 装过 PHP装 FlyEnv 之前最好先把 Homebrew 的 PHP 卸载掉避免 PATH 冲突。卸载命令是brew uninstall php如果有多个版本就逐个卸载。卸载完记得检查一下~/.zshrc里有没有残留的 PHP 路径配置有的话一并清理掉。最后再分享一个小技巧FlyEnv 的网站配置支持“复制”功能建新站点时可以复制已有站点的配置改一下域名和根目录就行比从头建快很多。对于需要频繁建测试站点的场景这个功能很省事。