PHP Version Upgrade
Upgrade one minor version at a time. Never skip versions - each step surfaces deprecations that become errors in the next release. Every upgrade follows the same cycle: audit, automate, test, deploy.
Core Principles
| Principle |
Meaning |
| Changelog first |
Before any upgrade, search the web for the official PHP migration guide (php.net/migration) or ask the user for the changelog - never rely on static knowledge alone |
| One version at a time |
Upgrade 8.1 -> 8.2 -> 8.3 -> 8.4 sequentially - skipping versions makes it impossible to isolate breakage |
| Fix deprecations before upgrading |
Deprecations in version N become errors in version N+1 - treat them as mandatory fixes |
| Automate first, manual second |
Run Rector and PHPCompatibility before touching code by hand - they catch 80%+ of required changes |
| Prove it with tests |
Never consider an upgrade complete without a passing test suite on the target version |
| Pin your platform |
Set config.platform.php in composer.json to match your lowest deployment target |
Upgrade Process Overview
Phase 0: Read the Changelog
Before touching any code, obtain the actual changelog for the target PHP version:
- Search the web for
PHP X.Y migration guide (e.g., PHP 8.4 migration guide php.net)
- Or ask the user to provide the changelog / release notes
- Read the official migration page at
https://www.php.net/manual/en/migrationXY.php
This is non-negotiable. Each version has unique changes that static skill knowledge cannot fully capture.
Phase 1: Audit
Before changing any code, understand the scope of the upgrade.
- Run PHPCompatibility against the target version to identify incompatible code
- Run php-parallel-lint with the target PHP binary to catch syntax errors
- Run
composer outdated to check if all dependencies support the target version
- Review the official migration guide at php.net for the target version
- Check PHP extensions for compatibility (
ext-intl, ext-mbstring, etc.)
Phase 2: Automate
Use Rector to handle the bulk of code transformations automatically.
// rector.php
use Rector\Config\RectorConfig;
return RectorConfig::configure()
->withPaths([__DIR__ . '/src', __DIR__ . '/tests'])
->withPhpSets(php84: true); // adjust to target version
Always dry-run first:
vendor/bin/rector process --dry-run
Review changes, then apply:
vendor/bin/rector process
Commit Rector changes separately from manual fixes for clean git history.
Phase 3: Update Dependencies
- Update
composer.json with the new PHP version constraint: "php": ">=8.4"
- Update
config.platform.php to match the target version
- Run
composer update and resolve conflicts
- Update PHP extensions as needed
Phase 4: Test and Deploy
- Run the full test suite under the new PHP version
- Run static analysis (PHPStan/Psalm)
- Deploy to staging and verify
- Monitor production logs for deprecation notices after deployment
See Upgrade Process Reference for detailed tool configuration, CI pipeline setup, and Docker considerations.
Tools
| Tool |
Purpose |
When to Use |
| Rector |
Automated AST-based code transformation |
First step after auditing - handles most mechanical changes |
| PHPCompatibility |
PHP_CodeSniffer ruleset for cross-version compatibility |
Audit phase - identifies all incompatible code before you start |
| php-parallel-lint |
Parallel syntax checking (~20x faster than serial) |
Audit phase - catches syntax errors under the new version |
| PHPStan/Psalm |
Static analysis |
Verification phase - catches type errors after transformation |
| symfony/phpunit-bridge |
Deprecation summary in test output |
Ongoing - monitors deprecation count during upgrades |
Breaking Changes by Version
| Transition |
Key Breaking Changes |
| 8.0 -> 8.1 |
Fibers introduced, enums added, readonly properties, intersection types, never return type |
| 8.1 -> 8.2 |
Dynamic properties deprecated (use #[AllowDynamicProperties] temporarily), $GLOBALS access restrictions, readonly classes, disjunctive normal form types |
| 8.2 -> 8.3 |
Typed class constants, json_validate() added, #[Override] attribute, Randomizer additions, date/time exception changes |
| 8.3 -> 8.4 |
Implicit nullable types deprecated (function foo(string $bar = null) must become ?string $bar = null), property hooks, asymmetric visibility, new without parentheses deprecated for no-arg constructors, DOM extension namespace changes |
See Version Changes Reference for complete per-version details with code examples.
Common Pitfalls
| Pitfall |
Why It Hurts |
Prevention |
| Skipping versions |
Cannot isolate which changes broke what |
Always upgrade one version at a time |
| Ignoring deprecation warnings |
Deprecations become fatal errors in the next version |
Fix all deprecations before upgrading |
| Not checking dependencies |
Third-party packages may not support the target version |
Run composer outdated and check support before starting |
Using --ignore-platform-reqs |
Bypasses safety checks, causes runtime errors |
Never use it - fix the actual constraints instead |
Not pinning config.platform.php |
Local PHP differs from production, causing install mismatches |
Always set it to match production |
| Large unreviewed Rector runs |
Rector can make incorrect transformations in edge cases |
Always dry-run first, review changes, run on small batches |
| Forgetting PHP extensions |
Extensions change behavior or get deprecated between versions |
Audit all required extensions before upgrading |
Quick Reference: Upgrade Checklist
Reference Files
| Reference |
Contents |
| Upgrade Process |
Detailed tool configuration, CI pipeline setup, Docker strategy, and step-by-step commands |
| Version Changes |
Per-version breaking changes, new features, and deprecations with code examples (PHP 8.0 through 8.4) |
Integration with Other Skills
| Situation |
Recommended Skill |
| Upgrading Symfony alongside PHP |
Use the symfony-upgrade skill in frameworks/symfony/ |
| Updating Composer dependencies after PHP upgrade |
Use the composer-dependencies playbook skill |
| Modernizing PHP code patterns (DTOs, enums, strict types) |
Install php-modernization from dirnbauer/webconsulting-skills or netresearch/php-modernization-skill |
| Running static analysis after upgrade |
Install knowledge-virtuoso from krzysztofsurdy/code-virtuoso for testing strategies |
1---2name: php-upgrade3description: Step-by-step PHP version upgrade playbook for PHP 8.0 through 8.4+ with automated tooling. Use when the user asks to upgrade PHP to a new version, check PHP compatibility, fix deprecation warnings, run Rector for automated refactoring, audit code with PHPCompatibility, or plan a PHP migration strategy. Covers breaking changes per version, php.ini configuration updates, extension compatibility, Rector rule sets, testing strategies, and the changelog-first upgrade workflow.4---56# PHP Version Upgrade78Upgrade one minor version at a time. Never skip versions - each step surfaces deprecations that become errors in the next release. Every upgrade follows the same cycle: audit, automate, test, deploy.910## Core Principles1112| Principle | Meaning |13|---|---|14| **Changelog first** | Before any upgrade, search the web for the official PHP migration guide (php.net/migration) or ask the user for the changelog - never rely on static knowledge alone |15| **One version at a time** | Upgrade 8.1 -> 8.2 -> 8.3 -> 8.4 sequentially - skipping versions makes it impossible to isolate breakage |16| **Fix deprecations before upgrading** | Deprecations in version N become errors in version N+1 - treat them as mandatory fixes |17| **Automate first, manual second** | Run Rector and PHPCompatibility before touching code by hand - they catch 80%+ of required changes |18| **Prove it with tests** | Never consider an upgrade complete without a passing test suite on the target version |19| **Pin your platform** | Set `config.platform.php` in `composer.json` to match your lowest deployment target |2021---2223## Upgrade Process Overview2425### Phase 0: Read the Changelog2627Before touching any code, obtain the actual changelog for the target PHP version:28291. **Search the web** for `PHP X.Y migration guide` (e.g., `PHP 8.4 migration guide php.net`)302. **Or ask the user** to provide the changelog / release notes313. **Read the official migration page** at `https://www.php.net/manual/en/migrationXY.php`3233This is non-negotiable. Each version has unique changes that static skill knowledge cannot fully capture.3435### Phase 1: Audit3637Before changing any code, understand the scope of the upgrade.38391. **Run PHPCompatibility** against the target version to identify incompatible code402. **Run php-parallel-lint** with the target PHP binary to catch syntax errors413. **Run `composer outdated`** to check if all dependencies support the target version424. **Review the official migration guide** at php.net for the target version435. **Check PHP extensions** for compatibility (`ext-intl`, `ext-mbstring`, etc.)4445### Phase 2: Automate4647Use Rector to handle the bulk of code transformations automatically.4849```php50// rector.php51use Rector\Config\RectorConfig;5253return RectorConfig::configure()54 ->withPaths([__DIR__ . '/src', __DIR__ . '/tests'])55 ->withPhpSets(php84: true); // adjust to target version56```5758Always dry-run first:5960```bash61vendor/bin/rector process --dry-run62```6364Review changes, then apply:6566```bash67vendor/bin/rector process68```6970Commit Rector changes separately from manual fixes for clean git history.7172### Phase 3: Update Dependencies73741. Update `composer.json` with the new PHP version constraint: `"php": ">=8.4"`752. Update `config.platform.php` to match the target version763. Run `composer update` and resolve conflicts774. Update PHP extensions as needed7879### Phase 4: Test and Deploy80811. Run the full test suite under the new PHP version822. Run static analysis (PHPStan/Psalm)833. Deploy to staging and verify844. Monitor production logs for deprecation notices after deployment8586See [Upgrade Process Reference](references/upgrade-process.md) for detailed tool configuration, CI pipeline setup, and Docker considerations.8788---8990## Tools9192| Tool | Purpose | When to Use |93|---|---|---|94| **Rector** | Automated AST-based code transformation | First step after auditing - handles most mechanical changes |95| **PHPCompatibility** | PHP_CodeSniffer ruleset for cross-version compatibility | Audit phase - identifies all incompatible code before you start |96| **php-parallel-lint** | Parallel syntax checking (~20x faster than serial) | Audit phase - catches syntax errors under the new version |97| **PHPStan/Psalm** | Static analysis | Verification phase - catches type errors after transformation |98| **symfony/phpunit-bridge** | Deprecation summary in test output | Ongoing - monitors deprecation count during upgrades |99100---101102## Breaking Changes by Version103104| Transition | Key Breaking Changes |105|---|---|106| **8.0 -> 8.1** | Fibers introduced, enums added, readonly properties, intersection types, `never` return type |107| **8.1 -> 8.2** | Dynamic properties deprecated (use `#[AllowDynamicProperties]` temporarily), `$GLOBALS` access restrictions, readonly classes, disjunctive normal form types |108| **8.2 -> 8.3** | Typed class constants, `json_validate()` added, `#[Override]` attribute, `Randomizer` additions, date/time exception changes |109| **8.3 -> 8.4** | Implicit nullable types deprecated (`function foo(string $bar = null)` must become `?string $bar = null`), property hooks, asymmetric visibility, `new` without parentheses deprecated for no-arg constructors, DOM extension namespace changes |110111See [Version Changes Reference](references/version-changes.md) for complete per-version details with code examples.112113---114115## Common Pitfalls116117| Pitfall | Why It Hurts | Prevention |118|---|---|---|119| Skipping versions | Cannot isolate which changes broke what | Always upgrade one version at a time |120| Ignoring deprecation warnings | Deprecations become fatal errors in the next version | Fix all deprecations before upgrading |121| Not checking dependencies | Third-party packages may not support the target version | Run `composer outdated` and check support before starting |122| Using `--ignore-platform-reqs` | Bypasses safety checks, causes runtime errors | Never use it - fix the actual constraints instead |123| Not pinning `config.platform.php` | Local PHP differs from production, causing install mismatches | Always set it to match production |124| Large unreviewed Rector runs | Rector can make incorrect transformations in edge cases | Always dry-run first, review changes, run on small batches |125| Forgetting PHP extensions | Extensions change behavior or get deprecated between versions | Audit all required extensions before upgrading |126127---128129## Quick Reference: Upgrade Checklist130131- [ ] Review php.net migration guide for target version132- [ ] Run PHPCompatibility scan against target version133- [ ] Run php-parallel-lint with target PHP binary134- [ ] Verify all Composer dependencies support target version135- [ ] Configure and run Rector with target version set (dry-run first)136- [ ] Review and commit Rector changes137- [ ] Apply manual fixes for remaining issues138- [ ] Update `composer.json` PHP constraint and `config.platform.php`139- [ ] Run `composer update`140- [ ] Run full test suite on target PHP version141- [ ] Run static analysis (PHPStan/Psalm)142- [ ] Deploy to staging and verify143- [ ] Deploy to production and monitor logs144145---146147## Reference Files148149| Reference | Contents |150|---|---|151| [Upgrade Process](references/upgrade-process.md) | Detailed tool configuration, CI pipeline setup, Docker strategy, and step-by-step commands |152| [Version Changes](references/version-changes.md) | Per-version breaking changes, new features, and deprecations with code examples (PHP 8.0 through 8.4) |153154---155156## Integration with Other Skills157158| Situation | Recommended Skill |159|---|---|160| Upgrading Symfony alongside PHP | Use the `symfony-upgrade` skill in `frameworks/symfony/` |161| Updating Composer dependencies after PHP upgrade | Use the `composer-dependencies` playbook skill |162| Modernizing PHP code patterns (DTOs, enums, strict types) | Install `php-modernization` from `dirnbauer/webconsulting-skills` or `netresearch/php-modernization-skill` |163| Running static analysis after upgrade | Install `knowledge-virtuoso` from `krzysztofsurdy/code-virtuoso` for testing strategies |