Migrating to PHP 8

Yo Yogesh.M Updated 17 Oct 2026
6 min read ·Lesson 90 of 109
In this post

Why Migrate? In simple terms: Every PHP version eventually stops receiving security fixes. Running an unsupported version means known vulnerabilities stay open forever. Newer versions are also signifi

Why Migrate?

In simple terms: Every PHP version eventually stops receiving security fixes. Running an unsupported version means known vulnerabilities stay open forever. Newer versions are also significantly faster and bring features that make code shorter and safer — union types, enums, readonly properties, match, named arguments, and more. Migrating an older application (for example, from PHP 7.4) to a current PHP 8 release is one of the most valuable maintenance tasks a team can do.

Technically: Each release documents its backward-incompatible changes, deprecations, and new features in the migration appendices of the PHP manual. PHP 8.0 was a major release with several breaking changes; the 8.x minor releases add features and mostly turn old behavior into deprecation notices first, before removing it in the next major version. A safe migration combines automated tools (static analysis, Rector), tests, deprecation logging, and a staged rollout.

Supported Versions

Each PHP version receives two years of active support followed by two years of security fixes. Check https://www.php.net/supported-versions.php for the current status and plan upgrades before a version reaches its end of life.


The Most Important Breaking Changes in PHP 8.0

Saner String-to-Number Comparisons

<?php
var_dump(0 == 'a');
var_dump('abc' == 0);
var_dump('1' == '01');
var_dump('10' == '1e1');
var_dump(100 == '1e2');

Output (PHP 8)

bool(false)
bool(false)
bool(true)
bool(true)
bool(true)
ComparisonPHP 7.4PHP 8
0 == 'a'truefalse
'abc' == 0truefalse
'1' == '01'truetrue
'10' == '1e1'truetrue

PHP 8 compares a number with a non-numeric string as strings instead of converting the string to 0. Code that relied on the old behavior — often unknowingly, for example in in_array() without the strict flag or in switch statements — may now take different branches. Using === and strict in_array(..., true) avoids the issue entirely (see Comparison Operators).

Other Notable 8.0 Changes

ChangeEffect
Internal functions throw TypeError / ValueError for invalid argumentsstrlen([]) throws instead of warning and returning null
Removed functionseach(), create_function(), money_format(), get_magic_quotes_gpc(), and others
@ no longer silences fatal errorsHidden failures become visible
Default error_reporting is E_ALLMore notices and deprecations appear
Stricter checks for arithmetic on arrays, objects, and null[] + 1 throws TypeError
Methods with the class name are no longer constructorsOld PHP 4–style constructors must be renamed to __construct()
Many resources became objectscurl_init(), xml_parser_create(), imagecreate() return objects; is_resource() checks fail

Deprecations in the PHP 8.x Series

Deprecations do not break code yet, but they will become errors in the next major version. Log them and fix them early.

VersionKey Deprecations and Changes
8.1Passing null to non-nullable parameters of internal functions (strlen(null)); implicit lossy float-to-int conversions; return types added to internal methods (#[\ReturnTypeWillChange] silences notices when extending them)
8.2Dynamic properties (see PHP Properties); ${var} string interpolation; utf8_encode()/utf8_decode()
8.3Mostly additions (typed class constants, #[\Override], json_validate()); few incompatibilities
8.4Implicitly nullable parameters (string $x = null, see Nullable Types); E_STRICT constant; trigger_error() with E_USER_ERROR; new defaults such as bcrypt cost 12
8.5Non-canonical casts (integer), (double), (boolean), (binary); curl_close() and other no-op functions

Examples of Deprecation Notices

<?php
echo strlen(null);   // PHP 8.1+

class Product {}
$product = new Product();
$product->colour = 'blue';   // PHP 8.2+
Deprecated: strlen(): Passing null to parameter #1 ($string) of type string is deprecated in ... on line 2
Deprecated: Creation of dynamic property Product::$colour is deprecated in ... on line 6

A Step-by-Step Migration Plan

1. Take Inventory

  • Which PHP version runs today, and which is the target?
  • Which extensions does the application use? Are they available for the target version (see Installing Extensions (PECL / PIE))?
  • Which Composer packages block the upgrade?
composer why-not php 8.4

This lists installed packages whose requirements do not allow PHP 8.4, showing what must be updated first.

2. Improve the Safety Net

  • Run the existing test suite; add tests for critical flows (checkout, login, payments) if they are missing.
  • Add static analysis (PHPStan or Psalm) configured for the target version.

3. Find Incompatibilities Automatically

# Static check for version-specific problems (PHP_CodeSniffer + PHPCompatibility)
vendor/bin/phpcs --standard=PHPCompatibility --runtime-set testVersion 8.4 src/

# Static analysis targeting the new version (phpstan.neon: parameters: phpVersion: 80400)
vendor/bin/phpstan analyse src

4. Upgrade Code Automatically With Rector

Rector rewrites code automatically: it fixes many incompatibilities and can modernize syntax (constructor promotion, match, typed properties, explicit nullable types).

<?php
// rector.php
use Rector\Config\RectorConfig;

return RectorConfig::configure()
    ->withPaths([__DIR__ . '/src', __DIR__ . '/tests'])
    ->withPhpSets(php84: true);
composer require --dev rector/rector
vendor/bin/rector process --dry-run   # preview the changes
vendor/bin/rector process             # apply them

Review Rector's changes like any other code change, in small commits.

5. Update Dependencies

Upgrade frameworks and libraries to versions supporting the target PHP version — often the largest part of the work for older applications. Upgrade one major framework version at a time, following each framework's upgrade guide.

6. Run the Application With Deprecations Visible

In development and CI, run with error_reporting = E_ALL and log deprecations. In production, log them too (without displaying them) after the upgrade, to catch code paths the tests missed.

7. Test in CI Across Versions

# Excerpt of a CI matrix (GitHub Actions)
strategy:
  matrix:
    php: ['8.3', '8.4', '8.5']

Running tests on both the current and target versions allows the code to stay compatible with both during the transition.

8. Roll Out Gradually

Deploy to a staging environment that mirrors production, then to production — ideally to a subset of servers first — while monitoring error logs, performance, and business metrics. Keep the old version available for a quick rollback.


Common Mistakes

Upgrading Several Major Versions at Once Without Tests

Effect: Many failures at once, hard to diagnose.

Fix: Build a test safety net first; upgrade step by step if the gap is large.

Ignoring Deprecation Notices

Effect: The next upgrade breaks the application.

Fix: Log and fix deprecations continuously.

Forgetting Extensions and Server Configuration

Effect: The code is ready, but php.ini settings or extensions differ on the new version.

Fix: Recreate the configuration for the new version and verify with php -m and a configuration check.

Upgrading PHP but Not Dependencies

Effect: Old libraries fail or emit many deprecations.

Fix: Update Composer packages as part of the migration.


Best Practices

  • Stay on supported PHP versions and plan upgrades before end-of-life dates.
  • Read the official migration guides for every version between the current and target versions.
  • Use tests, static analysis, PHPCompatibility, and Rector to find and fix problems automatically.
  • Treat deprecations as tasks, and run CI on both current and target versions.
  • Roll out gradually with monitoring and a rollback plan.

Official reference: https://www.php.net/manual/en/appendices.php

0 Comments

Reviewed before they appear

No comments yet.

PHP
PHP Home PHP Switch PHP Match Alternative Syntax PHP Loops While Loop Do While Loop For Loop Foreach Loop Nested Loops Break Statement PHP Home PHP Intro PHP Install PHP Built-in Web Server PHP Syntax PHP Tags PHP and HTML PHP Comments PHP Multiline Comments PHP Variables Variables Scope PHP Casting Logical Operators Null Coalescing Operator Spaceship Operator Operator Precedence Continue Statement Modify Strings PHP If...Else...Elseif PHP If Modify Strings PHP If Operators PHP Functions Concatenate Strings PHP If...Else Slicing Strings User-defined Functions Slicing Strings PHP Shorthand if Escape Characters Default Argument Values PHP Nested if Pass by Reference String Interpolation Named Arguments PHP File Upload Variadic Functions Return Values Search in Strings Multibyte Strings Type Declarations in Functions PHP Numbers PHP Math PHP Floats PHP Random Numbers PHP Constants PHP Properties PHP Methods PHP Constructor Constructor Property Promotion PHP Cookies PHP Destructor PHP Access Modifiers Readonly Properties PHP Sessions PHP Inheritance Method Overriding PHP Filters The final Keyword CSRF Protection PHP Filters Advanced Session Security Secure Cookies PHP Magic Constants File Upload Security PHP Callback Functions PHP Operators Filesystem Security PHP JSON Arithmetic Operators Error Reporting in Production Hiding PHP Assignment Operators PHP Configuration (php.ini) Comparison Operators PHP Command Line (CLI) PHP Exceptions Increment / Decrement Operators Migrating to PHP 8 PHP Form Validation PHP Form Required PHP Form URL/E-mail Error Handling Form Input Sanitizing Escaping Output (htmlspecialchars) Custom Error Handler Checkbox, Radio and Select Inputs Sticky Forms PHP Form Complete PHP Date and Time Date Formatting Error Logging HTTP Headers and Redirects Output Buffering Sending Email PHP cURL Consuming REST APIs PHP Generators
Ask about this post
AI Ask about this post

Ask questions about Migrating to PHP 8 and get answers drawn from it.

Signed-in readers only.