CI/CD for PHP Projects: GitHub Actions
Modern web development is unthinkable without automation. Manually running tests, checking code style, and deploying to a server takes time and is prone to errors. The solution is CI/CD (Continuous Integration / Continuous Deployment). In this article, we will break down how to set up a full pipeline for PHP projects using GitHub Actions. You will learn how to automatically test code, check its quality, and deploy to a production server with every push to the repository.
What is CI/CD and why does a PHP developer need it?
Continuous Integration (CI) is a practice where every commit is automatically checked: unit tests, linters, and security checks are run. Continuous Deployment (CD) is the next step, where code that has successfully passed CI is automatically deployed to a server (staging or production).
This is especially relevant for PHP: the language is dynamic, and typing and syntax errors are often only detected at runtime. GitHub Actions allows you to set up a pipeline that:
- Runs PHPUnit tests on different PHP versions (7.4, 8.0, 8.1, 8.2).
- Checks code using PHP_CodeSniffer or PHPStan.
- Performs deployment to a server via SSH or Docker.
Creating a workflow in GitHub Actions
To start, create a directory .github/workflows in the root of your PHP project. Inside it, create a file, for example ci.yml. This will be your pipeline.
Let's look at a basic example for CI. It will run on every push to the main branch or when a Pull Request is created.
name: PHP CI
on: push: branches: [ "main" ] pull_request: branches: [ "main" ]
jobs: build: runs-on: ubuntu-latest
strategy: matrix: php-versions: ['7.4', '8.0', '8.1', '8.2']
steps: - uses: actions/checkout@v3
- name: Setup PHP uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php-versions }} tools: composer, phpunit
- name: Validate composer.json and composer.lock run: composer validate --strict
- name: Cache Composer packages id: composer-cache uses: actions/cache@v3 with: path: vendor key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} restore-keys: | ${{ runner.os }}-php-
- name: Install dependencies run: composer install --prefer-dist --no-progress
- name: Run PHPUnit tests run: phpunit --configuration phpunit.xmlBreakdown of key points:
- Matrix strategy — allows running tests on multiple PHP versions simultaneously. This guarantees code compatibility.
- shivammathur/setup-php — a popular action for setting up the PHP environment. It installs the required version, Composer, and PHPUnit.
- Caching vendor — speeds up subsequent runs by not downloading dependencies again.
- composer validate — checks the correctness of composer.json.
Adding static analysis and linting
Tests are good, but you can't do without code quality control. Let's add checks using PHPStan and PHP_CodeSniffer to the same workflow (or create a separate job).
- name: Run PHPStan run: vendor/bin/phpstan analyse src tests --level=max
- name: Run PHP_CodeSniffer run: vendor/bin/phpcs --standard=PSR2 src testsThese steps can be added after installing dependencies. PHPStan with the max level will find potential type errors, and PHP_CodeSniffer with the PSR-2 (or PSR-12) standard will ensure a uniform code style. If at least one step fails,