一、为什么需要持续集成
想象一下,你正在开发一个PHP项目,每次修改代码后都要手动运行测试、检查代码风格、打包部署……这些重复劳动不仅浪费时间,还容易出错。持续集成(CI)就是来解决这个问题的——它像是个勤劳的助手,每次代码变动时自动帮你完成这些琐事。
举个例子:
// 技术栈:PHP + GitLab CI
// 一个简单的PHP单元测试示例
class Calculator {
public function add(int $a, int $b): int {
return $a + $b;
}
}
// 对应的测试用例
use PHPUnit\Framework\TestCase;
class CalculatorTest extends TestCase {
public function testAdd() {
$calc = new Calculator();
$this->assertEquals(5, $calc->add(2, 3)); // 断言2+3=5
}
}
如果没有CI,每次修改add()方法后,你都得手动跑测试。而有了CI,提交代码时这些测试会自动运行。
二、搭建基础自动化流程
1. 选择CI工具
Jenkins、GitLab CI、GitHub Actions都不错。这里以GitLab CI为例,因为它和代码仓库天然集成。
2. 编写配置文件
在项目根目录创建.gitlab-ci.yml:
# 技术栈:GitLab CI
stages:
- test
- deploy
unit_test:
stage: test
image: php:8.1 # 使用PHP 8.1的Docker镜像
script:
- apt-get update && apt-get install -y git unzip
- curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
- composer install
- ./vendor/bin/phpunit tests/ # 运行所有测试
deploy_prod:
stage: deploy
only:
- main # 仅main分支触发部署
script:
- rsync -avz ./ user@server:/var/www/html/ # 简化版部署脚本
3. 关键点解析
stages定义了流水线的阶段顺序image指定运行环境,避免"在我机器上是好的"问题only限制特定分支触发任务
三、进阶实践技巧
1. 并行化加速
拆分测试任务可以大幅缩短等待时间:
# 并行运行不同测试组
test_unit:
script: ./vendor/bin/phpunit tests/Unit/
test_integration:
script: ./vendor/bin/phpunit tests/Integration/
2. 代码质量检查
加入PHPStan静态分析:
code_quality:
script:
- composer require --dev phpstan/phpstan
- vendor/bin/phpstan analyse src --level=5
3. 环境变量管理
敏感信息如数据库密码应通过CI变量注入:
// 代码中通过getenv()读取
$dbPassword = getenv('DB_PASSWORD');
然后在GitLab的Settings > CI/CD > Variables中设置变量。
四、避坑指南
1. 缓存依赖
每次重新安装composer依赖太耗时,可以缓存vendor目录:
cache:
paths:
- vendor/
2. 本地复现问题
如果CI失败但本地成功,可以用相同环境调试:
docker run --rm -v $(pwd):/app -w /app php:8.1 ./vendor/bin/phpunit
3. 通知机制
添加失败提醒到Slack:
after_script:
- |
if [ "$CI_JOB_STATUS" == "failed" ]; then
curl -X POST -H 'Content-type: application/json' --data "{\"text\":\"Build $CI_PIPELINE_ID 失败了!\"}" $SLACK_WEBHOOK
fi
五、完整案例演示
假设我们有个小型API项目,目录结构如下:
.
├── src/
│ └── UserController.php
├── tests/
│ └── UserControllerTest.php
├── composer.json
└── .gitlab-ci.yml
UserController.php内容:
class UserController {
public function getUser(int $id): array {
if ($id <= 0) {
throw new InvalidArgumentException("ID必须大于0");
}
return ['id' => $id, 'name' => '测试用户'];
}
}
对应的CI配置:
stages:
- test
- deploy
phpunit:
stage: test
image: php:8.1
services:
- mysql:5.7
variables:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: test_db
script:
- apt-get update && apt-get install -y libzip-dev mysql-client
- docker-php-ext-install pdo_mysql zip
- composer install
- ./vendor/bin/phpunit --coverage-text --colors=never
deploy:
stage: deploy
environment: production
script:
- scp -r src/ user@server:/var/www/api/
only:
- main
六、技术选型对比
| 工具 | 优点 | 缺点 |
|---|---|---|
| Jenkins | 插件生态丰富 | 配置复杂 |
| GitLab CI | 与GitLab深度集成 | 免费版并发有限 |
| GitHub Actions | 原生支持GitHub仓库 | 对私有仓库有限制 |
七、应用场景分析
适合场景:
- 团队协作开发
- 需要频繁发布的项目
- 测试覆盖率要求高的项目
不适合场景:
- 个人一次性脚本
- 没有测试用例的项目(CI效果大打折扣)
八、注意事项
- 测试隔离性:每个测试用例应该独立运行,不能依赖执行顺序
- 流水线时长:超过30分钟的流水线会降低开发效率
- 资源成本:并行任务会消耗更多CI资源
- 失败处理:建议设置"允许失败"的任务标记非关键检查
九、总结
通过自动化构建和测试,PHP项目可以获得:
- 更快的错误反馈(不用等同事发现你的代码报错)
- 更高的代码质量(每次提交都经过严格检查)
- 更轻松的部署过程(点个按钮就能上线)
就像给项目请了个24小时值班的质检员,虽然初期搭建需要投入时间,但长期来看绝对是笔划算的投资。
评论