Insights

PHP 8.2 reaches end of life on 31 December 2026. What to do in the time left

PHP 8.2 gets its last security fixes from the PHP project on 31 December 2026 (php.net, supported versions). It was released on 8 December 2022, left active support on 31 December 2024 and has received security fixes only since then. The most recent release at the time of writing is 8.2.35, published on 21 October 2026. After 31 December there will be no further 8.2 release from php.net. All end-of-life dates for PHP, Laravel and Symfony are on our end-of-life calendar.

That October release was not routine. According to the php.net security advisory of 21 October 2026, PHP 8.2.35 fixed two critical vulnerabilities, CVE-2026-109618 and CVE-2026-109619, that can allow unauthenticated remote code execution. The same fixes shipped in 8.3.36, 8.4.27 and 8.5.12, and php.net wrote that "there are no complete mitigations, updating is the only safe choice". If a flaw like that is found in January, the fix will not ship for 8.2.

This article covers what changes on 1 January, how to find out what keeps your application on 8.2, which version to move to, and what to do if you cannot finish in time.

What changes on 1 January 2027

Nothing switches off. The application keeps running exactly as before. What changes is what happens the next time someone finds a vulnerability in PHP itself, as in October: the fix ships for the supported branches and not for 8.2. In the security-only phase php.net already releases "on an as-needed basis", so what you lose is every fix found after 31 December, however many there are.

The same date matters in three other ways.

  • PHP 8.4 leaves active support on 31 December 2026 and gets security fixes only until 31 December 2028. From January, only 8.5 and 8.6 get regular bug fixes. The PHP 8.6 release schedule (wiki.php.net) targets general availability on 19 November 2026.
  • Platforms set their own dates. Google App Engine standard ends support for its php82 runtime on 31 December 2026 and decommissions it on 31 December 2027, when deployments on that runtime stop working. AWS Elastic Beanstalk lists its PHP 8.2 platform for retirement on 31 March 2027. Some hosts charge for keeping an old version once the PHP project stops patching it: mittwald currently charges €5 net per PHP version, per project, per month for versions the community no longer patches (today 8.1 and older), and €15 in a second phase without guaranteed fixes.
  • Distribution packages do not follow php.net. Debian 12 ships PHP 8.2 as its default PHP and maintains its own php8.2 package. Debian's long-term support for release 12 is scheduled to run until 30 June 2028 (Debian LTS wiki). If your PHP comes from Debian's repositories, check the Debian security tracker for php8.2 before you plan around 31 December. Your end date may be Debian's, not php.net's.

Step 1: find out what you really run

Check on the production server, and check both the command line and the process that serves web requests, because they can be different versions:

php -v
php -m
ps aux | grep -E "php-fpm" | head -3

On Debian and Ubuntu the PHP-FPM master process shows its configuration path, for example /etc/php/8.2/fpm/php-fpm.conf. That is the version your users hit. Also write down where the binary comes from: a distribution package, a third-party repository, a Docker image tag, or a setting in a hosting panel. Each has its own upgrade path and its own end date.

Step 2: find what holds you on 8.2

Most applications stay on 8.2 because a framework or a dependency holds them there. Composer tells you which:

composer why-not php 8.4

It lists the installed packages whose PHP constraint excludes 8.4. That is the minimum scope of the work: a package with an open constraint such as >=7.2 will not show up here, and can still break on 8.4.

Then check the framework, because it sets the ceiling:

FrameworkSupported PHPSecurity fixes until
Laravel 108.1 to 8.3ended 4 February 2025
Laravel 118.2 to 8.4ended 12 March 2026
Laravel 128.2 to 8.524 February 2027
Laravel 138.3 to 8.517 March 2028
Symfony 6.48.1 or newerNovember 2027
Symfony 7.48.2 or newerNovember 2029

Sources: laravel.com/docs/13.x/releases and symfony.com/releases, both checked 25 October 2026.

A Laravel 10 application can move to PHP 8.3 at most, and Laravel 10 itself stopped receiving security fixes in February 2025. In that case the PHP upgrade and the framework upgrade are one project, and it is cheaper to plan them as one.

Finally, look at extensions. PHP 8.4 moved IMAP, OCI8, PDO_OCI and PSpell out of the PHP distribution to PECL. If php -m lists imap and your code calls imap_open(), solve that first. A shared host that moves you to 8.4 may not offer the PECL version at all.

Step 3: pick the target version

TargetSecurity fixes untilWhat it buys from January 2027
8.331 December 2027one year, already security-only
8.431 December 2028two years
8.531 December 2029three years, with bug fixes until the end of 2027

In most codebases, going from 8.2 to 8.4 is not much more work than going to 8.3, so 8.3 is rarely worth the detour. We default to 8.4 and choose 8.5 when every dependency already allows it, which composer why-not php 8.5 will show. A release that is a few weeks old, as 8.6 will be in December, is a poor target for a deadline. Give the libraries time to catch up.

Step 4: know what breaks between 8.2 and 8.4

PHP 8.3 changed little that affects typical web applications. PHP 8.4 is where most of the work is, and most of it is deprecations:

  • Implicitly nullable parameters. function find(User $user = null) is deprecated and becomes ?User $user = null. In older codebases this is the most frequent change by a wide margin, and it is mechanical.
  • Session settings. session.sid_length and session.sid_bits_per_character are deprecated. Check php.ini, .user.ini files and ini_set() calls.
  • trigger_error() with E_USER_ERROR is deprecated. Throw an exception instead.
  • E_STRICT is gone as an error level and the constant is deprecated. Old custom error handlers often mention it.
  • Stricter behavior. exit() throws a TypeError for invalid argument types, round() rejects invalid rounding modes, and PDO MySQL attributes such as ATTR_EMULATE_PREPARES now expect booleans.

By default, PHP logs deprecations and carries on. Check your error handler first: older frameworks and many custom set_error_handler() callbacks turn every notice into an exception, and then the first deprecation becomes a fatal error. Even with a default handler, an application can pass every test on 8.4 and still write thousands of deprecation notices an hour. Run it on 8.4 in staging with E_DEPRECATED logged, exercise it, and read the log before you switch production.

Step 5: let tools do the mechanical part

Rector applies PHP version sets to your code, but it also checks which PHP version your project runs and skips every rule that needs a newer one. Unless you set withPhpVersion(), it takes that version from the lower bound of require.php in composer.json. So ->withPhpSets(php84: true) behaves differently depending on the constraint:

  • with "php": "^8.2", Rector applies only the rules up to 8.2. The 8.4 rules are skipped, including the one that makes nullable parameters explicit;
  • with "php": "^8.4", Rector applies everything up to 8.4, including syntax that only exists in 8.3 and 8.4, such as typed class constants. That code fails on 8.2.

During the transition, keep "php": "^8.2" and run the one 8.4 rule you need now with a separate, small configuration: ->withRules([ExplicitNullableParamTypeRector::class])->withPhpVersion(PhpVersion::PHP_84). The ?User it writes works on PHP 7.1 and later. Raise the constraint to ^8.4 on the day you switch, then run the full php84 set. Each time, run with --dry-run first and review the diff. On a large codebase the diff is long, and nearly all of it is correct.

PHPStan 2 accepts a range, phpVersion: {min: 80200, max: 80400}, and then reports a good part of what will break on either version. Add 8.4 to the CI matrix next to 8.2, so every change is tested on both until the switch.

What the tools do not give you is evidence that the application still does what it did. If there are no tests on the paths that earn money (login, checkout, invoicing, the nightly export), write a few that record today's behavior before you change the runtime under them.

If you will not make it by 31 December

That happens, and there are reasonable ways to handle it, in this order:

  1. If you run distribution packages, confirm how long your distribution patches php8.2. You may have more time than php.net suggests.
  2. Buy time on purpose. Patched PHP builds from vendors such as Freexian, TuxCare or Zend, or a host's Extended Support, keep the interpreter patched. They do not patch your framework or your Composer dependencies, so treat them as a bridge with an end date.
  3. Reduce exposure while you work. Keep everything else patched, run composer audit as a scheduled CI job every week, disable PHP extensions you do not use, and set the switch date.

Running 8.2 for a few weeks in January is a manageable risk if the switch date is set and written down.

A plan for the weeks left

From late October there are about nine weeks, and for most teams the last two are holidays. A plan that fits: one week for steps 1 and 2, one week for the target decision and dependency updates, two to three weeks for code changes and tests, one to two weeks in staging, then the production switch before mid-December with a written rollback. If the list from step 2 includes a framework upgrade, assume the switch moves into the first quarter and arrange the bridge now.

If you want a second pair of eyes on that list, send us your composer.lock. We reply with the support dates for your PHP and framework versions, and how many known advisories and abandoned packages the file shows, at no cost and with no access to your code. If you need the full picture, the Debt Check (€300) adds a short questionnaire and gives you a report within three business days: the risks in order of priority, what blocks the move to a supported version, and a recommended path with price ranges. A Takeover or Care can often be quoted at a fixed price straight from it; an upgrade gets its fixed price after a Code Audit.

Sources

Checked 25 October 2026.

Want a second pair of eyes on your app?

Send us your composer.lock. We reply with the support dates for your PHP and framework versions, and how many known advisories and abandoned packages the file shows, at no cost and with no access to your code.