$npx -y skills add krzysztofsurdy/code-virtuoso --skill php-upgradeStep-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
| 1 | # PHP Version Upgrade |
| 2 | |
| 3 | 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. |
| 4 | |
| 5 | ## Core Principles |
| 6 | |
| 7 | | Principle | Meaning | |
| 8 | |---|---| |
| 9 | | **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 | |
| 10 | | **One version at a time** | Upgrade 8.1 -> 8.2 -> 8.3 -> 8.4 sequentially - skipping versions makes it impossible to isolate breakage | |
| 11 | | **Fix deprecations before upgrading** | Deprecations in version N become errors in version N+1 - treat them as mandatory fixes | |
| 12 | | **Automate first, manual second** | Run Rector and PHPCompatibility before touching code by hand - they catch 80%+ of required changes | |
| 13 | | **Prove it with tests** | Never consider an upgrade complete without a passing test suite on the target version | |
| 14 | | **Pin your platform** | Set `config.platform.php` in `composer.json` to match your lowest deployment target | |
| 15 | |
| 16 | --- |
| 17 | |
| 18 | ## Upgrade Process Overview |
| 19 | |
| 20 | ### Phase 0: Read the Changelog |
| 21 | |
| 22 | Before touching any code, obtain the actual changelog for the target PHP version: |
| 23 | |
| 24 | 1. **Search the web** for `PHP X.Y migration guide` (e.g., `PHP 8.4 migration guide php.net`) |
| 25 | 2. **Or ask the user** to provide the changelog / release notes |
| 26 | 3. **Read the official migration page** at `https://www.php.net/manual/en/migrationXY.php` |
| 27 | |
| 28 | This is non-negotiable. Each version has unique changes that static skill knowledge cannot fully capture. |
| 29 | |
| 30 | ### Phase 1: Audit |
| 31 | |
| 32 | Before changing any code, understand the scope of the upgrade. |
| 33 | |
| 34 | 1. **Run PHPCompatibility** against the target version to identify incompatible code |
| 35 | 2. **Run php-parallel-lint** with the target PHP binary to catch syntax errors |
| 36 | 3. **Run `composer outdated`** to check if all dependencies support the target version |
| 37 | 4. **Review the official migration guide** at php.net for the target version |
| 38 | 5. **Check PHP extensions** for compatibility (`ext-intl`, `ext-mbstring`, etc.) |
| 39 | |
| 40 | ### Phase 2: Automate |
| 41 | |
| 42 | Use Rector to handle the bulk of code transformations automatically. |
| 43 | |
| 44 | ```php |
| 45 | // rector.php |
| 46 | use Rector\Config\RectorConfig; |
| 47 | |
| 48 | return RectorConfig::configure() |
| 49 | ->withPaths([__DIR__ . '/src', __DIR__ . '/tests']) |
| 50 | ->withPhpSets(php84: true); // adjust to target version |
| 51 | ``` |
| 52 | |
| 53 | Always dry-run first: |
| 54 | |
| 55 | ```bash |
| 56 | vendor/bin/rector process --dry-run |
| 57 | ``` |
| 58 | |
| 59 | Review changes, then apply: |
| 60 | |
| 61 | ```bash |
| 62 | vendor/bin/rector process |
| 63 | ``` |
| 64 | |
| 65 | Commit Rector changes separately from manual fixes for clean git history. |
| 66 | |
| 67 | ### Phase 3: Update Dependencies |
| 68 | |
| 69 | 1. Update `composer.json` with the new PHP version constraint: `"php": ">=8.4"` |
| 70 | 2. Update `config.platform.php` to match the target version |
| 71 | 3. Run `composer update` and resolve conflicts |
| 72 | 4. Update PHP extensions as needed |
| 73 | |
| 74 | ### Phase 4: Test and Deploy |
| 75 | |
| 76 | 1. Run the full test suite under the new PHP version |
| 77 | 2. Run static analysis (PHPStan/Psalm) |
| 78 | 3. Deploy to staging and verify |
| 79 | 4. Monitor production logs for deprecation notices after deployment |
| 80 | |
| 81 | See [Upgrade Process Reference](references/upgrade-process.md) for detailed tool configuration, CI pipeline setup, and Docker considerations. |
| 82 | |
| 83 | --- |
| 84 | |
| 85 | ## Tools |
| 86 | |
| 87 | | Tool | Purpose | When to Use | |
| 88 | |---|---|---| |
| 89 | | **Rector** | Automated AST-based code transformation | First step after auditing - handles most mechanical changes | |
| 90 | | **PHPCompatibility** | PHP_CodeSniffer ruleset for cross-version compatibility | Audit phase - identifies all incompatible code before you start | |
| 91 | | **php-parallel-lint** | Parallel syntax checking (~20x faster than serial) | Audit phase - catches syntax errors under the new version | |
| 92 | | **PHPStan/Psalm** | Static analysis | Verification phase - catches type errors after transformation | |
| 93 | | **symfony/phpunit-bridge** | Deprecation summary in test output | Ongoing - monitors deprecation count during upgrades | |
| 94 | |
| 95 | --- |
| 96 | |
| 97 | ## Breaking Changes by Version |
| 98 | |
| 99 | | Transition | Key Breaking Changes | |
| 100 | |---|---| |
| 101 | | **8.0 -> 8.1** | Fibers introduced, enums added, readonly properties, intersection types, `never` return type | |
| 102 | | **8.1 -> 8.2** | Dynamic properties deprecated (use `#[AllowDynamicProperties]` temporarily), `$GLOBALS` access restrictions, readonly classes, disjunctive normal form types | |
| 103 | | **8.2 -> 8.3** | Typed class constants, `json_validate()` added, `#[Override]` attribute, `Randomizer` additions, date/time exception chang |