先说个最简单的逻辑:GitLab CI 默认并不会给你装上 PHP 8.1。如果你直接在 .gitlab-ci.yml 里写 php --version,大概率会看到返回的是 PHP 7.x,甚至直接报错。你得主动告诉它,用 PHP 8.1 的环境,否则测试和部署都可能在版本不匹配上栽跟头。

怎么让 GitLab Runner 跑 PHP 8.1?
GitLab Runner 本身不决定 PHP 版本,它靠你指定的 image 或 services 来提供运行环境。最稳妥的方式就是直接用官方 PHP Docker 镜像。
- 优先选
php:8.1-cli—— 非常轻量,没有 Apache/Nginx,适合跑 CLI 测试任务。 - 如果项目需要 Web 环境,比如跑 PHPUnit 加内置服务器,那就用
php:8.1-apache。不过注意,得手动启用mod_rewrite和设置 DocumentRoot。 - 千万别图省事用
ubuntu:22.04再加手动apt install php8.1。这种做法经常因为源失效或者扩展缺失(比如mbstring、xml)导致构建失败,实在不值得。
PHPUnit 测试阶段常踩的坑
PHP 8.1 对类型声明更严格了,PHPUnit 的版本必须≥9.5才能支持它。否则你会看到诸如Fatal error: Cannot declare class PHPUnit...或Typed property must not be accessed before initialization这样的报错。
- 检查
composer.json:确保"phpunit/phpunit": "^9.5"或者"^10.0"(后者要求 PHP≥8.1.0)。 - 在 CI 里别依赖全局
phpunit,统一用./vendor/bin/phpunit调用。 - 如果项目用了
ext-opcache相关的优化(比如预加载),在 CI 阶段建议关闭:php -d opcache.enable=0 ./vendor/bin/phpunit。
部署到生产服务器时路径与权限问题
CI 构建产物(比如 build/ 或 dist/)默认在 Runner 的临时目录里。直接用 rsync 或 scp 推到目标服务器时,很容易因为用户权限、SELinux、路径不存在等原因失败。
- 部署脚本里加上前置检查:
ssh $DEPLOY_USER@$HOST 'mkdir -p /var/www/myapp && chown -R $DEPLOY_USER:$DEPLOY_USER /var/www/myapp'。 - PHP 8.1 的
opcache.validate_root默认是On,部署后首次访问可能 500。建议部署后执行ssh $USER@$HOST 'sudo systemctl reload php8.1-fpm'(如果是 FPM 模式)。 - 别在
before_script里composer install --no-dev后直接 rsync 整个 repo 目录。应该只同步public/、vendor/、.env.production这些必要文件,避免泄露.git/或开发环境的配置。
真正麻烦的往往不是写对 .gitlab-ci.yml,而是 PHP 8.1 的扩展兼容性(比如 igbinary、redis)和部署目标机的 PHP-FPM pool 配置是否匹配。这些问题不会在 CI 日志里报错,但上线后 502 或白屏才会暴露出来。