Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save DaveLiddament/922dd45cd10b14b6b614e96bee7380af to your computer and use it in GitHub Desktop.

Select an option

Save DaveLiddament/922dd45cd10b14b6b614e96bee7380af to your computer and use it in GitHub Desktop.
Prompt: Update project to run in all PHP active versions
I want this project to support PHP 8.3, 8.4, and 8.5 with a CI matrix. Right
now it probably only supports one version. Here's the plan:
## Goals
- Support PHP 8.3, 8.4, and 8.5
- Local Docker services for each version
- GitHub Actions matrix that runs CI against all three
- Infection (mutation testing) runs only on 8.5 in a dedicated job
- Single `composer.lock` that works on all three versions (project, not
library — locked dependencies only)
## Constraints
- This is a project, not a library. Don't use `highest`/`lowest` dependency
matrix strategies. Only run against the locked dependencies.
- Don't change PHP code unless there's a genuine syntax incompatibility.
Most 8.5 features (readonly classes, typed constants, first-class
callables) already work on 8.3.
- Daily development continues on 8.5 — the default `app` docker-compose
service stays as 8.5 with xdebug enabled.
## Exploration first
Before writing any code:
1. Find sibling project `test-splitter` (or similar) and copy its
multi-version Docker/CI pattern if it exists
2. Check the current `composer.json` for the PHP constraint
3. Check current `Dockerfile`, `docker-compose.yml`, `Makefile`, and
`.github/workflows/` for the existing setup
4. Scan the codebase for any truly 8.5-only syntax (pipe operator `|>`,
property hooks, asymmetric visibility). Most 8.5 "features" are
actually 8.3+ and don't need changing.
## Implementation plan
### composer.json
- Update `"php": "~8.5"` to `"php": "8.3.*|8.4.*|8.5.*"`
- Add `config.platform.php = "8.3.0"` so the lock file is pinned to
dependencies compatible with all target versions
- Split `ci` composer script so infection is NOT in it (infection runs
in its own dedicated job)
### composer.lock
- Regenerate with `composer update --with-all-dependencies` after the
platform pin. Expect major downgrades (e.g. PHPUnit 13 → 12.5,
symfony 8 → 7.4) because 8.4+-only packages get replaced with
8.3-compatible versions.
### vendor-bin/*/composer.json (if using bamarni/composer-bin-plugin)
- Add `config.platform.php = "8.3.0"` to EVERY sub-composer file
- Delete each vendor-bin lock file and regenerate
- Watch out for tools with minimum PHP requirements. For example,
`maglnet/composer-require-checker` 4.21+ requires PHP 8.4 — pin to
`^4.20` if needed.
### Dockerfile
- Parameterise with `ARG PHP_VERSION=8.5` if not already
- Add `ARG XDEBUG_ENABLED=1` and make xdebug installation conditional:
`RUN if [ "$XDEBUG_ENABLED" = "1" ]; then pecl install xdebug && \
docker-php-ext-enable xdebug; fi`
### docker-compose.yml
Add per-version services extending the default `app`. Keep xdebug
enabled on ALL of them because CI needs it for coverage:
```yaml
services:
app:
build:
context: .
args:
PHP_VERSION: "8.5"
tty: true
stdin_open: true
environment:
XDEBUG_MODE: debug
volumes:
- .:/app
- composer-cache:/root/.composer/cache
app-php83:
extends:
service: app
build:
context: .
args:
PHP_VERSION: "8.3"
app-php84:
extends:
service: app
build:
context: .
args:
PHP_VERSION: "8.4"
app-php85:
extends:
service: app
build:
context: .
args:
PHP_VERSION: "8.5"
volumes:
composer-cache:
Makefile (if present)
Add targets:
app/ci-all: app/ci-83 app/ci-84 app/ci-85
app/ci-83:
@$(DOCKER_COMP) run --rm app-php83 composer ci-local
app/ci-84:
@$(DOCKER_COMP) run --rm app-php84 composer ci-local
app/ci-85:
@$(DOCKER_COMP) run --rm app-php85 composer ci-local
.github/workflows/ci.yml
Rewrite as a matrix + dedicated infection job:
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
ci:
name: "PHP ${{ matrix.php-version }}"
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
php-version: ['8.3', '8.4', '8.5']
steps:
- uses: actions/checkout@v5
- uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-version }}
extensions: bcmath, intl, zip
tools: composer:v2
coverage: xdebug
- uses: ramsey/composer-install@v3
with:
dependency-versions: locked
- run: composer ci
infection:
name: "Infection (PHP 8.5)"
runs-on: ubuntu-latest
needs: ci
steps:
- uses: actions/checkout@v5
- uses: shivammathur/setup-php@v2
with:
php-version: '8.5'
extensions: bcmath, intl, zip
tools: composer:v2
coverage: xdebug
- uses: ramsey/composer-install@v3
with:
dependency-versions: locked
- run: composer infection
infection.json5 (if applicable)
If you use PHPStan as infection's static analysis tool, set
"staticAnalysisToolOptions": "--memory-limit=-1" — infection's internal
PHPStan invocation defaults to 128M which OOMs on non-trivial codebases.
README
Update the install instructions to list all three supported versions.
Verification
After all changes, run in order:
1. make app/ci in the default 8.5 container — sanity check
2. Build each versioned container: docker compose build app-php83 && docker compose build app-php84 && docker compose build app-php85
3. make app/ci-83, make app/ci-84, make app/ci-85 — each must
pass the full CI suite
4. composer infection on 8.5 — must pass MSI threshold
Common pitfalls to watch for
- Vendor-bin sub-projects DON'T inherit the main config.platform pin.
You MUST add it to each sub-composer.json individually.
- composer bin all install won't regenerate locks — you need update
or delete the lock files first.
- Xdebug must stay ENABLED on all versioned services because the
coverage step needs it.
- Infection's PHPStan runs with its own memory limit independent of
the project's phpstan.neon — configure it in infection.json5.
- Package minimum PHP versions can bite you. Check the error messages
carefully and find older versions that support PHP 8.3.
Out of scope
- Don't backport to PHP 8.2 or earlier
- Don't replace readonly classes with alternatives
- Keep the default development version at 8.5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment