PHP 8.5 brings a solid mix of language improvements, practical extension updates, and deprecations worth cleaning up before PHP 9.0.
It is not a flashy release built around one massive headline feature. Instead, it improves day-to-day developer experience in a lot of useful places: cleaner data transformations, better URL handling, nicer debugging, a few welcome standard library additions, and a clearer path away from old legacy patterns.
In this article, I want to focus on what actually matters when writing and maintaining PHP code: what you can start using right away, what deserves attention during migration, and which changes are most useful in real-world projects.
The pipe operator makes transformations easier to read
One of the most visible additions in PHP 8.5 is the pipe operator, |>.
Its purpose is simple: pass the result of one expression into the next one from left to right. That makes chained transformations much easier to read than deeply nested function calls.
<?php
$title = ' PHP 8.5 Released ';
$slug = $title
|> trim(...)
|> strtolower(...)
|> (fn($value) => str_replace(' ', '-', $value));
echo $slug; // php-8.5-released
This is especially nice for string processing, array transformations, or small data-cleaning pipelines.
The biggest benefit is readability. You read the code in the same order it runs.
One thing to keep in mind: functions that need multiple arguments, like str_replace(), will often require a small closure.
The new URI extension is one of the most useful additions
PHP 8.5 also introduces a built-in URI extension.
This is a big deal because URL handling in many projects still relies on a mix of parse_url(), string concatenation, and custom helpers. That usually works until it does not.
The new API gives PHP a cleaner and more structured way to work with URIs and URLs.
<?php
use Uri\Rfc3986\Uri;
$uri = new Uri('https://example.com/blog/php-8-5');
$updated = $uri
->withPath('/blog/php-8-5/comments')
->withQuery('page=2&sort=recent');
echo $updated->toString();
// https://example.com/blog/php-8-5/comments?page=2&sort=recent
That makes a lot of sense in apps dealing with pagination, canonical URLs, crawlers, API clients, or SEO tooling.
It is one of those additions that will probably save more bugs than it gets credit for.
Small new functions that remove a lot of noise
PHP 8.5 also adds several small functions and APIs that reduce boilerplate.
Among the most useful are:
array_first()array_last()get_error_handler()get_exception_handler()Locale::isRightToLeft()locale_is_right_to_left()IntlListFormatterFILTER_THROW_ON_FAILURE
Here is a simple example with array_first() and array_last():
<?php
$items = ['PHP', 'Laravel', 'Vue'];
var_dump(array_first($items)); // PHP
var_dump(array_last($items)); // Vue
And here is one with FILTER_THROW_ON_FAILURE:
<?php
try {
$email = filter_var(
'vincent@@example.com',
FILTER_VALIDATE_EMAIL,
FILTER_THROW_ON_FAILURE
);
} catch (Throwable $e) {
echo 'Invalid email';
}
None of these changes are huge on their own.
But together, they make code a little more direct and a little less repetitive, which is exactly the kind of improvement that ages well.
#[\NoDiscard] helps prevent silent mistakes
Another interesting addition is the #[\NoDiscard] attribute.
It allows you to mark a function whose return value should not be ignored.
That is especially useful for transformation functions where forgetting to use the returned value is usually a bug.
<?php
#[\NoDiscard]
function normalizeEmail(string $email): string
{
return strtolower(trim($email));
}
$email = normalizeEmail(' Vincent.Capek@Example.COM ');
PHP 8.5 also introduces the (void) cast so you can explicitly ignore a return value when that is intentional.
This makes intent clearer and helps distinguish real mistakes from deliberate choices.
Fatal errors are more useful now
PHP 8.5 improves debugging by adding stack traces to fatal errors.
This sounds small, but in practice it is a very welcome quality-of-life improvement.
When something crashes badly, getting more context immediately can save time, especially in larger apps or older codebases where tracking the source of a fatal error can be annoying.
It is one of those improvements you do not think about until the moment you need it.
Practical extension improvements you will actually notice
PHP 8.5 also includes several useful updates across built-in extensions.
A few stand out more than others in day-to-day work.
DOM gets outerHTML
Dom\Element::$outerHTML is finally available.
That is great for scraping, HTML cleanup, testing, or any tool that manipulates markup.
<?php
$doc = Dom\HTMLDocument::createFromString(
'<article class="post"><h1>Hello</h1></article>'
);
$article = $doc->querySelector('article.post');
echo $article->outerHTML;
getimagesize() improves support for modern formats
PHP 8.5 improves getimagesize() support for HEIF, HEIC, and SVG.
That is genuinely useful for uploads, media libraries, CMS features, and portfolio-like projects where modern image formats show up more often.
Partitioned cookies are now supported
Cookies and sessions now support the partitioned flag.
This matters more in modern browser environments where third-party cookie behavior has become stricter.
cURL exposes more diagnostic information
PHP 8.5 adds more details to curl_getinfo().
That helps when debugging outgoing HTTP requests, proxies, authentication behavior, or connection timing.
mail() reports failures more honestly
If you still use mail() in some environment, PHP 8.5 improves error reporting around sendmail failures.
That does not modernize mail(), but it does make it less opaque.
The deprecations are not scary, but they are worth cleaning up
PHP 8.5 also deprecates a number of old patterns.
Most of them are not difficult to fix, but they are exactly the sort of things that can sit around in a codebase for years if ignored.
Some of the most important ones are:
-
case;instead ofcase:inswitch - non-canonical casts like
(boolean),(integer),(double) - backticks as an alias for
shell_exec() -
__sleep()and__wakeup()in favor of__serialize()and__unserialize() - using
nullas an array offset or inarray_key_exists() - incrementing non-numeric strings with
++ - legacy functions like
curl_close(),imagedestroy(),finfo_close(),xml_parser_free(),mysqli_execute(), andsocket_set_timeout()
Here is a simple before-and-after example:
Before:
<?php
$value = (boolean) $input;
$output = `ls -la`;
switch ($status) {
case 'draft';
echo 'draft';
break;
}
After:
<?php
$value = (bool) $input;
$output = shell_exec('ls -la');
switch ($status) {
case 'draft':
echo 'draft';
break;
}
These are not dramatic changes, but they are good signals.
They push PHP code toward more consistency and away from old habits that are either confusing, unnecessary, or easy to misuse.
What I would prioritize first in a real migration
If I were upgrading a real project to PHP 8.5, I would focus on three things first.
1. Try the features that can simplify real code
The pipe operator and the new URI extension are the two most interesting practical additions to experiment with right away.
They can make everyday code cleaner without needing a big architectural change.
2. Clean up easy deprecations early
Things like (boolean), backticks, case;, or legacy close/free functions are usually simple to fix and easy to detect with a global search.
3. Check extension-related behavior where it matters
If your app handles HTML, images, outgoing HTTP requests, or more advanced cookie behavior, PHP 8.5 has changes worth testing directly.
That is where the most practical wins are.
Final thoughts
PHP 8.5 is not the kind of release that tries to reinvent the language.
Instead, it improves the everyday experience of writing PHP.
The pipe operator improves readability. The URI extension fills a long-standing gap. The new functions remove little bits of friction. Debugging gets better. Extension updates feel grounded in real use cases. And the deprecations help nudge codebases toward cleaner patterns.
That makes PHP 8.5 a very solid release.
Not because it changes everything, but because it improves the places where developers spend time every day.
Top comments (0)