What’s New and Migration
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. The reference material consulted while preparing these pages is listed in the section bibliography. |
This page is written against PHP 8.5, checked on 2026-10-05. PHP 8.5 is the current release (latest patch 8.5.11, 2026-09-24). PHP 8.6 is upcoming: it was at RC2 on that date, with general availability scheduled for 2026-11-19, so 8.6 items below are marked as upcoming and may still change. Every other page in this section marks the version that introduced a feature; this page puts the versions side by side.
Release by release
Each release has a migration guide in the PHP Manual listing new features, backward-incompatible changes and deprecations. Read the guides of every version between the one you run and the one you move to.
| Release | GA | Headline changes |
|---|---|---|
2015-12-03 |
New engine (about twice as fast as 5.6, much less memory); scalar and return type declarations; |
|
2016-12-01 |
Nullable types ( |
|
2017-11-30 |
|
|
2018-12-06 |
Flexible heredoc/nowdoc; trailing commas in calls; |
|
2019-11-28 |
Typed properties; arrow functions |
|
2020-11-26 |
JIT; named arguments; attributes; constructor property promotion; union types, |
|
2021-11-25 |
Enumerations; readonly properties; fibers; first-class callable syntax |
|
2022-12-08 |
Readonly classes; DNF types; |
|
2023-11-23 |
Typed class constants; |
|
2024-11-21 |
Property hooks; asymmetric visibility |
|
2025-11-20 |
Pipe operator |
|
8.6 (upcoming) |
2026-11-19 (scheduled) |
Partial function application |
The 8.6 migration guide is published in the manual when 8.6 is released; until then, the UPGRADING file in the
PHP-8.6 branch of php-src is the authoritative list.
Support timeline
Each release gets two years of active support (bug and security fixes), then two years of security fixes only. Since a 2024 policy change, both periods end on 31 December, which also extended 8.1 to the end of 2025. After that a branch is end of life: it receives no fixes at all, including for actively exploited vulnerabilities.
| Branch | Released | Active support until | Security support until | State on 2026-10-05 |
|---|---|---|---|---|
7.0 to 7.4 |
2015-12-03 to 2019-11-28 |
— |
2019-01-10 to 2022-11-28 |
End of life |
8.0 |
2020-11-26 |
2022-11-26 |
2023-11-26 |
End of life |
8.1 |
2021-11-25 |
2023-11-25 |
2025-12-31 |
End of life |
8.2 |
2022-12-08 |
2024-12-31 |
2026-12-31 |
Security fixes only (8.2.34) |
8.3 |
2023-11-23 |
2025-12-31 |
2027-12-31 |
Security fixes only (8.3.35) |
8.4 |
2024-11-21 |
2026-12-31 |
2028-12-31 |
Active (8.4.26) |
8.5 |
2025-11-20 |
2027-12-31 |
2029-12-31 |
Active (8.5.11) |
8.6 (upcoming) |
2026-11-19 (scheduled) |
2028-12-31 (by policy) |
2030-12-31 (by policy) |
Release candidate |
Libraries and frameworks set their own minimums. Laravel 13 requires PHP 8.3 to 8.5, and the next major version is
expected to require 8.4. Composer’s "php" constraint in composer.json and config.platform.php make the
requirement explicit (see Composer and Packages).
Deprecations and removals
PHP removes features in two steps. A minor release deprecates a feature: it still works, but emits an
E_DEPRECATED notice (a soft deprecation is documented only, with no notice). The next major release (8.0, then
9.0) removes it. The table lists the deprecations that most often appear in real code.
| Version | Deprecated | Removed |
|---|---|---|
7.0 |
PHP 4-style constructors; static calls to non-static methods |
|
7.1 |
|
— |
7.2 |
|
|
7.3 |
Case-insensitive constants; non-string needles in |
— |
7.4 |
Unparenthesised nested ternaries; |
|
8.0 |
Optional parameters before required ones; |
Everything deprecated in 7.x: |
8.1 |
Passing |
— |
8.2 |
Dynamic properties; |
— |
8.3 |
|
— |
8.4 |
Implicitly nullable parameters ( |
|
8.5 |
The backtick operator; non-canonical casts |
— |
8.6 (upcoming) |
|
— |
Source: PHP 8.5 — Deprecated features, 8.4, 8.3, 8.2, 8.1, 8.0 — Backward incompatible changes and 7.4
Contrary to some upgrade guides, list() is not deprecated: it still works without a notice in 8.5 and in
8.6.0RC2, although [] (7.1) is the usual syntax.
This script runs on PHP 8.5, but every marked line produces a deprecation. Deprecations found at compile time are reported before the script starts; the rest go through the error handler as the lines run:
<?php
error_reporting(E_ALL);
set_error_handler(function (int $level, string $message, string $file, int $line): bool {
echo "line $line: $message\n";
return true;
});
class Member
{
public function rename(string $name = null): void {} // implicitly nullable parameter (8.4)
}
$member = new Member();
$member->nickname = 'ada'; // dynamic property (8.2)
$name = 'Ada';
echo "Hello ${name}\n"; // ${} interpolation (8.2)
$count = (integer) '3'; // non-canonical cast name (8.5)
$version = 'a9';
$version++; // increment of a non-numeric string (8.5)
var_dump(strftime('%Y')); // strftime (8.1)
Deprecated: Non-canonical cast (integer) is deprecated, use the (int) cast instead in legacy.php on line 19
Deprecated: Member::rename(): Implicitly marking parameter $name as nullable is deprecated, the explicit nullable type must be used instead in legacy.php on line 10
Deprecated: Using ${var} in strings is deprecated, use {$var} instead in legacy.php on line 17
line 14: Creation of dynamic property Member::$nickname is deprecated
Hello Ada
line 21: Increment on non-numeric string is deprecated, use str_increment() instead
line 22: Function strftime() is deprecated since 8.1, use IntlDateFormatter::format() instead
string(4) "2026"
The fixes are mechanical: ?string $name = null, a declared property (or #[\AllowDynamicProperties] as a stopgap),
{$name}, (int), str_increment($version) and IntlDateFormatter.
PHP 9
No release date is set for PHP 9.0, but several RFCs have already been accepted for it. Undefined variables will
throw an Error instead of a warning. "${var}" interpolation will be removed. Autovivification on false
($x = false; $x[] = 1;, which silently turns $x into an array) will throw. In general, every feature deprecated
during the 8.x series is a candidate for removal in 9.0, so code that runs on 8.5 without deprecation notices is
the best preparation.
How to upgrade
-
Read the migration guides for every version you skip, especially the backward-incompatible changes.
-
Make deprecations visible. Run the test suite and staging with
error_reporting=E_ALLand logE_DEPRECATED; PHPUnit’sfailOnDeprecation="true"anddisplayDetailsOnTestsThatTriggerDeprecations="true"turn them into test failures (see Testing with PHPUnit and Pest). -
Check compatibility statically. PHPStan reports calls to deprecated functions with its deprecation-rules extension, and the PHPCompatibility sniffs for PHP_CodeSniffer report syntax and functions that do not exist or are removed in a target version.
-
Rewrite automatically. Rector’s PHP sets apply each version’s upgrades (constructor promotion,
match, readonly, explicit nullable types, …). Review the diff like any other change; see Static Analysis and Refactoring. -
Upgrade dependencies with Composer, raising the
"php"constraint last. -
Run the new version in CI alongside the old one before switching production.
<?php
// rector.php -- upgrade a code base to PHP 8.5 syntax
use Rector\Config\RectorConfig;
return RectorConfig::configure()
->withPaths([__DIR__ . '/src', __DIR__ . '/tests'])
->withPhpSets(php85: true); // or withPhpSets() to follow composer.json's "php" constraint
Source: Rector — Documentation and PHPCompatibility
vendor/bin/rector process --dry-run # show the changes as a diff
vendor/bin/rector process # apply them
vendor/bin/phpcs -p src --standard=PHPCompatibility --runtime-set testVersion 8.5-
Run with Rector 2.6.7 on a PHP 7-era class, the dry run reports:
class Member
{
- private $name;
- public function __construct(string $name = null) { $this->name = $name; }
+ public function __construct(private readonly ?string $name = null)
+ {
+ }
public function label(int $kind): string
{
- switch ($kind) { case 1: return 'staff'; default: return 'reader'; }
+ return match ($kind) {
+ 1 => 'staff',
+ default => 'reader',
+ };
}
}
Applied rules:
* ClassPropertyAssignToConstructorPromotionRector
* ChangeSwitchToMatchRector
* ReadOnlyPropertyRector
Source: Rector — Documentation and PHPCompatibility — Usage
Where older books and tutorials are outdated
The PHP books this section draws on were written for PHP 5.2 to 7.3 (see the bibliography on the PHP Reference home page). Each page in this section has its own "outdated" section; this table collects every book statement about the language that is no longer true, with the version where it changed.
| What the book says or does | Where | Changed in | Current approach |
|---|---|---|---|
|
Wiley ch. 8, Beak ch. 12 (quiz) |
removed in 7.0 |
mysqli or PDO with prepared statements |
|
Kromann, Nixon |
removed in 7.0 |
|
PHP 4-style constructors (a method named like the class) |
Beak ch. 5 |
deprecated 7.0, ignored since 8.0 |
|
mcrypt for encryption |
Beak ch. 1, 6 and 8 |
deprecated 7.1, removed 7.2 |
sodium, or OpenSSL with AES-GCM (Cryptography) |
|
Beak ch. 4, Nixon ch. 6 |
removed in 8.0 |
|
|
Beak ch. 2, Kromann ch. 4 |
removed in 8.0 |
closures and arrow functions (Closures) |
|
Kromann ch. 6 |
removed in 8.0 |
Composer’s PSR-4 autoloader (Namespaces and Autoloading) |
|
Beak ch. 3, Kromann ch. 12 |
removed in 8.0 |
|
The |
Beak ch. 1 |
removed in 8.0 |
|
|
Kromann ch. 9-10 |
removed in 8.0 |
escape on output (Files and Streams) |
|
Nixon ch. 10, 27 |
removed in 8.0 |
nothing: magic quotes were removed in 5.4; use prepared statements |
Bareword array keys |
Kromann ch. 14 |
fatal |
quoted keys |
|
Beak ch. 1 |
false since 8.0 |
|
Arithmetic on non-numeric strings gives a warning and |
Powers ch. 4 |
|
validate and cast input first |
Internal functions return |
Beak ch. 11 |
|
catch the exceptions (Errors and Exceptions) |
PDO throws exceptions by default (said of PHP 7, whose default was silent) |
Kromann ch. 28 |
true only since 8.0 |
rely on |
Checking |
Powers ch. 13, Kromann ch. 27 |
mysqli throws since 8.1 |
rely on |
|
Beak ch. 3, Powers ch. 16, Kromann ch. 12 |
deprecated 8.1 |
|
|
Beak ch. 6 and 12, Kromann ch. 13 |
deprecated 8.1 |
escape for the output context with |
|
Beak ch. 5 |
deprecated 8.1 |
|
|
Beak ch. 5 |
no-op since 8.1 |
omit it (Reflection) |
Resources ( |
the books' cURL, GD and fileinfo examples |
objects since 8.0-8.1, close functions deprecated 8.5 |
let the object go out of scope |
Assigning undeclared (dynamic) properties on objects |
all books (written before 8.2) |
deprecated 8.2 |
declare properties |
|
Beak ch. 8 |
|
the flag, and |
|
Beak ch. 2, Kromann |
|
variadic parameters (Functions) |
|
Beak ch. 10 |
deprecated 8.5 |
|
|
Beak ch. 5 |
soft-deprecated 8.5 |
|
The backtick operator and |
Kromann ch. 9, Nixon ch. 7 |
backticks deprecated 8.5 |
|
OPcache as an extension to install and load |
Beak ch. 1 |
always built in since 8.5 |
configure it, nothing to install (OPcache and JIT) |
References to avoid copying arrays; PHP 5 zval diagrams |
Beak ch. 1 |
copy-on-write and the PHP 7 zval |
pass by value (References and Memory) |
|
Wiley ch. 8 and 15, Kromann ch. 14 |
|
|
PEAR packages; no Composer |
Kromann ch. 7, Wiley, all other books |
Composer since 2012; PECL to PIE (2025) |
Composer and PIE (Composer and Packages) |
PSR-0 and underscore pseudo-namespaces ( |
Wiley |
PSR-0 deprecated 2014 |
namespaces and PSR-4 |
PSR-2 coding style |
Kromann ch. 21 |
deprecated 2019 |
PER Coding Style 3.0 (PSR Standards) |
|
Powers ch. 1-5 |
— |
log errors in production; fatal errors include backtraces since 8.5 (Debugging) |
Beyond these corrections, none of the books covers the language added since PHP 7.4: typed properties, arrow
functions, attributes, named arguments, match, enums, readonly properties and classes, fibers, first-class callable
syntax, property hooks, asymmetric visibility, the pipe operator and the rest of the table at the top of this page.