---
title: 'Performance, Operations and Debugging Improvements in PHP 8.4'
source: 'https://youtube.com/watch?v=Raw8haMsahQ'
video_id: 'Raw8haMsahQ'
date: 2026-08-03
duration_sec: 1081
---

# Performance, Operations and Debugging Improvements in PHP 8.4

> Source: [Performance, Operations and Debugging Improvements in PHP 8.4](https://youtube.com/watch?v=Raw8haMsahQ)

## Summary

PHP 8.4 introduces several performance, debugging, and operations improvements that often go unnoticed. This video highlights seven such changes, including sprintf compiler optimization, the deprecated attribute, lazy objects, SHA-NI integration, get_browser performance, DOM HTML5 parsing, and closure naming in stack traces.

### Key Points

- **sprintf compiler optimization** [00:19] — PHP 8.4 compiles sprintf calls with only %s or %d modifiers into string interpolation, eliminating function call overhead. This makes sprintf more readable without performance penalty.
- **Deprecated attribute** [02:25] — New #[Deprecated] attribute can be applied to functions and methods (and constants in 8.5) to trigger deprecation notices, replacing trigger_error with E_USER_DEPRECATED. Supports custom messages and version info.
- **Lazy objects** [04:43] — PHP 8.4 adds native support for lazy objects, allowing deferred initialization. Using Reflection API, you can create lazy ghost objects that initialize only when properties are accessed, improving performance in DI containers.
- **SHA-NI integration for SHA-256** [07:44] — PHP core now uses SHA-NI CPU instructions for SHA-256 hashing, making it 2.3 to 5.2 times faster. This is based on the tasn/lip library and makes SHA-256 faster than MD5.
- **get_browser performance improvement** [10:13] — The get_browser function got a performance boost (1.4-2.5x) but still slower than userland libraries like JBZoo/Crawler-Detect and Matomo Device Detector, which use precompiled PHP code.
- **DOM HTML5 parsing and serialization** [12:40] — New DOM HTML5 API using Lexbor library supports HTML5 parsing and CSS selectors. Parsing is ~1.5x faster and more correct than old DOMDocument.
- **Closure naming and stack traces** [15:25] — Closures now include their declaration location in stack traces and var_dump output, making debugging easier. Error tracking tools like Tideways can display this info.

### Conclusion

PHP 8.4 brings several under-the-radar improvements that can enhance performance and debugging. Developers should consider adopting these changes to optimize their applications.

## Transcript

largest spotlight in major PHP release announcements, but there is always a lot of improvements on the performance, debugging, and operations site that are mentioned as just a footnote or not at all. In this video, I'm going to show
you seven performance, debugging, and operations changes in PHP 8.4 that you have probably not heard about before. Mo, my name is Benjamin and I'm working on performance optimizations for PHP applications for the last 10 years,
helping thousands of developers along the way. The first change is the sprintf compiler optimization. Starting with PHP 8.4, before. If you use sprint f with only the percentage s or percentage d modifiers, then it compiles down as if
you were using string interpolation and it avoids the function call overhead of sprint f completely. This change I am truly proud of uh as uh my colleague Tim implemented it and put a lot of work into getting this as into
a lot of work into getting this as into core. Let's see how this works. So on our blog we show an example of how this works. Um if you have a function that um
concatenates strings in any way then you can use sprint f. Now here we used just the percent d modifiers to generate the string and with php 8.4 the php engine
and opc cache optimizes this to become this string interpolation code here instead. So the sprint f call is gone completely and with it also the slight
performance overhead of calling this function. So the benefit I see here is that you can modify a lot of string manipulation code to use sprint f manipulation code to use sprint f instead because um it is much easier to
read in my um experience and it allows you to like u make better use of this you to like u make better use of this function and don't um think about the overhead of that because PHP will optimize this away for you. So you end
up with a more readable code that manipulates strings and uh it doesn't even cause um this script to to run slower. The second change I want to talk
about is the deprecated attribute. A feature that my colleague Tim and I feature that my colleague Tim and I proposed and finalized for PHP 8.4. Originally when I worked on attribute support for PHP 8.0 zero in 2020. My
idea was to also include the deprecate attribute directly in this version to have one use case for people to immediately try this out and use for themselves. But sadly, I hadn't had the time to finish it. Now, this is
complete. It's an 8.4 4 and you can put it onto functions and methods and it onto functions and methods and starting with 8.5 also on constants and um maybe we will also add support for adding it on classes in the next version
of PHP. How does it work? Let's look at a simple code example. I have a calculator class uh with a method add uh that's working uh with a method add uh that's working on integer types and I want to add a new
method that allows to work on integers and floats. So I'm deprecating the old one using the attribute and if I run this code now you attribute and if I run this code now you can see PHP
error or deprecation message the function is deprecated and it's also using this alternative text here that I added above. You can also um specify a version since when. So I could say for example thins today this method is
deprecated. So um and this will include it in the message as well. well. So uh if I use the new method now not
the deprecated anymore um the engine will not run through this deprecation called will not trigger this deprecation. And uh this is a good way to replace deprecation code that you uh could do
deprecation code that you uh could do before using trigger error and then e user deprecated um and uh using the
to do them. The third feature that uh is included in PHP 8.4 for that I want to talk about is lazy objects and um Doctrine and Symfony are known for their use of lazy objects and proxies for a long time already but they implemented
long time already but they implemented it in userland using uh code generation and magic methods and finally this is now possible to uh use in the engine directly with this uh new functionality and it adds some hooks that make it
possible to completely skip code generation and other magic ways to like generation and other magic ways to like implementing lazy objects. In Athens, lazy objects allow you to defer constructing the object to the point
where any lazy properties are accessed on this object for the first time. Um there are there's a lot of nuance to it. It can be used in very advanced ways. But um I want to talk about a simple way how this works. I want to show you a
simple example how lazy objects work um in dependency injection. I have an expensive dependency class with a constructor calling the sleep function. It simulates expensive behavior in the constructor that we see in real world
applications as well. Not this critical here with the sleep, but doing work like here with the sleep, but doing work like connecting to um external services or performing some initial work um signing things or so opening files and this is
um not necessary in most cases when the object itself is then later not used. So the expensive dependency is injected into this my listener through the constructor and we have a public method on on that. So in PHP 8.3 and before you
on on that. So in PHP 8.3 and before you would uh create this dependency using new expensive dependency and at that point it would trigger the slow code. point it would trigger the slow code. With PHP 8.4 you can use the reflection
API to create a new lazy ghost object. So it looks like the real object but it's actually not initialized yet. And uh we have to pass the new lazy ghost an
initializer function. And this is triggered once the object is loaded. And for our case here we need to initialize the object. Um and we can do that by calling the constructor directly. So this looks a bit weird. Um but this is
the way you can use uh this because you can call the constructor u multiple can call the constructor u multiple times on objects and the lazy um API sort of circumvents calling the constructor.
So here we have the listener and now we have this uh lazy dependency and if we call this code here it will my listener with the expensive
dependency and um as you have seen the code exits very quickly so the sleep call hasn't been triggered by this. The fourth change I want to show is something that my colleague Tim worked on uh the SHA NI integration for SHA 256
functions. So cryptographic algorithms can be much faster when they are directly implemented on the CPU using CPU instructions and that is what the SHA extensions uh SHA-NI are for the SHA 256 functions the hash
are for the SHA 256 functions the hash algorithm PHP core now supports using these extensions in the hash algorithm basing it on the excellent work in the basing it on the excellent work in the tasknap lip persever a library. Um, so
this is something that existed before and now this library is used in PHP um to implement this functionality in his pull request. Tim also showed some benchmark work. So if we go down here, so he has some before and after
checks and a direct comparison at the bottom. You can see he runs his compile his changed PHP against um sort of the master version at that point. So the um
the PHP version binary that didn't have these changes and then he runs a very these changes and then he runs a very simple loop um with uh an algorithm and performing some work on data. So you can see here in the direct comparison uh for
see here in the direct comparison uh for the SHA 256 algorithm that it runs 2.3 the SHA 256 algorithm that it runs 2.3 times to 5.2 times faster than the times to 5.2 times faster than the original SHA 256 code. So it's um really
faster um much faster than before. It's even faster than um the implementation of the MD5 function in PHP. So if you have code that is generating a lot of have code that is generating a lot of hash hashes um to identify strings or
files or something like this um then it's worth looking into if you want to it's worth looking into if you want to change to SHA 256 um instead um using both a more cryptographically unique and secure function but um also um having
faster results for that. The fifth change I want to show is an individual performance improvement to the get browser function. This function can be used to detect crawlers and bots that are running on your website
and maybe to block them or to do some special handling. The way PHP implements special handling. The way PHP implements it is uh by passing an INI file called brow browser cap which includes a lot of definitions of uh brow um crawlers and
bots and um this file is updated regularly and in the PHP code when it runs it will pass this ini file and then match the pass this ini file and then match the user agent against it. So Neil Dashel
performed some performance work on that and he also included a benchmark where he shows that for different scenarios his changes improve the performance by his changes improve the performance by 1.4 to 2.5 times.
However, this is a special case that we need to talk about because there are also some userland fun um libraries that do the same thing. So J Bizzle crawler do the same thing. So J Bizzle crawler detect and Mtomo device uh detector and
previously we benchmarked them against get browser to see which one is faster and what you can use and the PHPbased implementations have one benefit. they use the browser cap file or a different input for uh user agents and code
input for uh user agents and code generate uh a PHP paraser that checks generate uh a PHP paraser that checks for this. And by doing so u the PHP pasa the code for that can already be um stored in op code and
stored in op code and it can already be stored in opcache and this makes it much faster than the get browser native function because it needs to pass the ini file. Uh when we benchmark this before um php 8.4 Before
we saw, you can see here that get browser is quite expensive and runs in browser is quite expensive and runs in the many seconds uh um time whereas uh the two PHP libraries are much faster and uh run in the sub 1 second um
performance range and for calling them only once also get browser is u slower than the matmo device detector or jbiz crawler detect. So this is the case
where um the performance improves for the PHP internal function but still there are userland implementations that are faster. Change number six that I are faster. Change number six that I want to talk about is the DOM HTML 5 uh
parsing and serialization RFC. parsing and serialization RFC. It uses a new library um called lexbore which is used to implement passing of HTML 5 code or co HTML 5 compatible um
code and this was previously not possible in PHP because the um DOM possible in PHP because the um DOM document pasa was based on older HTML document pasa was based on older HTML standards and now we have HTML 5 support
standards and now we have HTML 5 support in in PHP. This also includes uh uh performance improvements because the parsing of HTML 5 code is now faster
than the old parsing code and additionally the new API includes additionally the new API includes implementations for CSS selectors and uh previously you would uh need a PHPbased CSS selector library for that and that's
CSS selector library for that and that's now implemented in on the C level and uh if you're using CSS selectors a lot then this will also give you a performance benefit you would also don't need to convert it to X pass anymore so it's
easier to work with let's look at some code uh we see the old way of passing HTML uh code is using the old DOM document uh class uh calling the load HTML method and the new way is using a new HTML document class from the DOM
name case calling a static create from string method. So let's run this through a benchmarking tool. Uh we use hyperfine here to compare the call with an with
the old um code against um running it against the new code. And I'm using the HTML output from a news website a German one. one. They have like super big HTML nested uh
things. So it's very complex HTML and the passing takes quite a while. So let's run this against each other. We see We see um that for the old code 10 parsing runs
take 327 milliseconds milliseconds and for the new um it takes 200 uh 200 207 just so the difference really is about uh 1.5 times faster using the new
paraser. So if your PHP application passes HTML code a lot, you should change to this new um API for performance reasons, but also because it passes the HTML code more correctly. Change number seven and
the last change I want to show is closure naming and stack traces. When you re regularly use closures um and debug code with them, you might have come across the problem that in a stack
trace the closure is not uniquely identified. You see that there is a closure in the stack but you don't know where it was defined and if your application passes around closures a lot then maybe you
don't know what the code is that is being uh executed causing an error. So starting with PHP 8.4 this changes a little bit. So here we see um the old
way is rendering closure. So there's a closure that was declared in this name space here. But obviously this nameace could have tens of hundreds of closures.
could have tens of hundreds of closures. So with PHP 8.4 the change is uh that a closure defines uh where it was coming from. So you can see here that at that point in the stack trace we have a closure that was declared in the
storefront controller render front function on line 26. So now it's easier function on line 26. So now it's easier to identify um which was which specific closure is part of a stack trace. Um this is also true if you v dump closure
objects. They also include this information. Now and an additional information. Now and an additional benefit is that um this kind of things are now also visible in error tracking tools and um for example tideways um see
shows this now and um you have like an easier way of identifying uh which code was um run uh in an error. These were seven changes in PHP 8.4 that you might have not heard about in detail yet or at
have not heard about in detail yet or at all. And um PHP 8.4 is now already out for a few months, but migrating to it started like uh picking up recently. So maybe you are uh um in the process of migrating to 8.4 right now. And I hope
you found something that you can use to improve the uh performance of your application. Coming up on the channel next, a video on the performance uh next, a video on the performance uh between versions PHP 8.4, 8.3, 8.2, too
and why it's not changing a lot anymore in recent times. Also, if you want to watch PHP performance related topics in general, please subscribe to this channel or to the newsletter. The link is in the description. Bye.
