PHP version upgrade strategy — migration and deprecation handling
Intermediate5 min read·php-09-026
interview
Concept
PHP version upgrades require understanding what changed, what broke, what was deprecated, and how to migrate safely in a production system.
PHP release cycle: PHP follows an annual release cycle. Each major.minor version is supported for 3 years: 2 years of active support (security + bug fixes) + 1 year of security-only support. Running end-of-life PHP is a significant security risk — vulnerabilities are not patched.
Migration strategy:
- Audit current PHP version — what warnings, deprecations, and errors does current code produce under
error_reporting(E_ALL)? - Use CI/CD with the target PHP version — run tests against the new version before upgrading production.
- Static analysis — PHPStan and Psalm can detect issues without running the code.
php -lsyntax-checks files. - Rector — automated PHP upgrade tool that applies codemod rules to fix deprecated patterns.
- Feature flags or staged rollout — upgrade one server at a time behind a load balancer.
Breaking changes across major versions:
- PHP 7.0: Scalar type declarations, strict_types, uniform variable syntax (some expressions broke).
- PHP 8.0: String-to-int comparison semantics changed, several deprecated features removed,
__toStringexceptions allowed. - PHP 8.1: Readonly properties, enums, fibers — mostly additive. Some implicit nullable changes.
- PHP 8.2: Dynamic properties deprecated (must declare
#[AllowDynamicProperties]). - PHP 8.4: JIT improvements, property hooks, implicit nullable deprecated.
Code Example
php
<?php
// Checking PHP version at runtime
echo PHP_VERSION; // "8.4.1"
echo PHP_MAJOR_VERSION; // 8
echo PHP_MINOR_VERSION; // 4
echo PHP_RELEASE_VERSION; // 1
// Conditional code for different versions
if (PHP_VERSION_ID >= 80400) {
// PHP 8.4+ specific code
} elseif (PHP_VERSION_ID >= 80100) {
// PHP 8.1+ specific code
}
// Deprecation check — run your test suite with:
// error_reporting(E_ALL);
// ini_set('display_errors', '1');
// All E_DEPRECATED notices will surface
// PHP 8.0 breaking change example — string to int comparison
// Before 8.0: 0 == "any string" was TRUE
// PHP 8.0+: 0 == "any string" is FALSE (string coerced to 0 only if numeric)
$x = 0;
var_dump($x == "hello"); // PHP 7: true, PHP 8: false!
var_dump($x == "0"); // PHP 7+8: true (numeric string)
// PHP 8.2 — dynamic properties deprecated
class OldStyle
{
// Setting $obj->newProp = 'value' where $newProp isn't declared → E_DEPRECATED in 8.2
}
// Fix: declare the property, or add #[AllowDynamicProperties]
#[\AllowDynamicProperties]
class NewStyle {}
// Rector upgrade command
// composer require rector/rector --dev
// ./vendor/bin/rector process src --config rector.php
// rector.php:
// $rectorConfig->sets([LevelSetList::UP_TO_PHP_84]);
// PHP_EOL, PHP_INT_MAX, PHP_INT_MIN, PHP_FLOAT_MAX constants
// are stable across all PHP versions — safe to use
// composer.json platform constraint — enforce minimum PHP version
// "require": { "php": "^8.2" }
// Prevents installing on incompatible PHP versions