PHP 8.5: No General Speed Boost?
45sSurprises viewers by stating PHP 8.5 isn't universally faster, challenging expectations.
▶ Play ClipPHP 8.5 introduces several performance, debugging, and operations improvements. While there are no general speedups, optimizations like opcode specialization for empty array checks and match true statements, a new cURL share init persistent API, and garbage collection improvements for enums and static fake closures can make specific code faster. Opcache is now required and compiled into PHP, and new debugging features include enhanced backtraces for fatal errors and new functions to retrieve error/exception handlers.
PHP 8.5 does not unconditionally make applications faster than 8.4; a separate benchmark video will be released.
The `$array === []` check is now optimized to be the fastest method, outperforming `empty()`, `!$array`, and `count($array) === 0`.
The `match(true)` construct generates optimized opcodes, resulting in 20% faster execution for 1 million iterations.
New API allows sharing DNS, connection, and SSL handshake across PHP requests and processes, reducing latency for third-party API calls.
Enums and static fake closures are no longer considered for cycle collection, reducing GC runs and saving time (e.g., 200ms for 10 million closures).
Opcache is compiled into PHP binary and cannot be disabled; only `opcache.enable=0` can turn it off. This reduces maintenance and errors.
New ini setting allows generating opcache file cache during build step, reducing cold start times by 100-150ms for serverless environments like Bref.
A new constant compiled into PHP binary identifies the build provider (e.g., Homebrew, Debian), available at runtime.
The `-d ini=diff` flag outputs only changed ini settings, aiding bug reporting.
New `max_memory_limit` ini setting prevents runtime from increasing memory beyond a set value, enhancing operator control.
The `ZEND_MM_DEBUG` environment variable provides additional memory debugging info without recompiling PHP.
Fatal errors now include a stack trace when `display_errors` is on, improving debugging.
These functions simplify retrieving the current error/exception handlers, with polyfills available for older versions.
PHP 8.5 brings targeted performance optimizations, operational improvements like required opcache and read-only file cache support, and enhanced debugging capabilities including stack traces for fatal errors and new helper functions.
"Title accurately reflects content: performance, debugging, and operations improvements are covered in detail."
What is the fastest way to check if an array is empty in PHP 8.5?
Using the identical operator: `$array === []`
03:02
How much faster is the optimized `match(true)` construct in PHP 8.5?
20% faster for 1 million iterations.
04:55
What does the new cURL share init persistent API allow sharing across PHP requests?
DNS, connection, and SSL handshake.
05:38
Why are enums and static fake closures no longer considered for cycle collection?
Because they cannot create cycles (they never point to other objects).
07:24
What is the effect of the garbage collection improvement for 10 million static fake closures?
GC runs reduced from 44 times to 0, saving 200ms.
08:25
How can opcache be disabled in PHP 8.5?
By setting `opcache.enable=0`.
09:38
What is the benefit of opcache being compiled into the PHP binary?
Reduced maintenance cost, fewer errors, and easier interaction between optimizer and opcache.
09:55
How much can the opcache file cache reduce cold start time for serverless containers?
100 to 150 milliseconds.
12:14
What does the `PHP_BUILD_PROVIDER` constant do?
It identifies the build provider (e.g., Homebrew, Debian) at runtime.
12:42
What does the `-d ini=diff` flag do in PHP 8.5?
It outputs only the ini settings that have changed from defaults.
13:50
What is the purpose of the `max_memory_limit` ini setting?
It prevents runtime from increasing memory beyond a set value.
15:00
How can you get additional memory debugging information without recompiling PHP?
By setting the `ZEND_MM_DEBUG` environment variable.
16:30
What improvement was made to fatal error handling in PHP 8.5?
Fatal errors now include a stack trace when `display_errors` is on.
17:30
What two new functions were introduced for error handling?
`get_error_handler()` and `get_exception_handler()`.
18:17
Empty array check optimization
Shows how micro-optimizations can change best practices; the previously slowest method becomes fastest.
03:02cURL share init persistent API
Most impactful performance change for applications using third-party APIs, reducing latency significantly.
05:05Garbage collection improvement for enums and static fake closures
Demonstrates a practical optimization that reduces GC overhead for common patterns.
07:04Opcache now required
Simplifies PHP deployment and prevents accidental performance loss from missing opcache.
09:19Max memory limit for operators
Provides operators with control to prevent runaway memory usage in production.
14:27[00:00] PHP 8.5 will be released this week and
[00:03] there's been a lot of work behind the
[00:05] scenes on performance operations and
[00:07] debugging related improvements which I
[00:09] want to highlight in this video. You
[00:12] cannot usually find these in new release
[00:14] announcement post or other videos. Mo I
[00:17] am Benjamin and I'm working on PHP
[00:19] performance related topics for the past
[00:21] 10 years helping thousands of developers
[00:24] along the way. If you want to know if
[00:27] PHP 8.5 is faster than previous versions
[00:30] of PHP, then I have to disappoint you.
[00:33] There have been no significant general
[00:35] improvements to PHP 8.5. So that an
[00:39] upgrade will unconditionally make your
[00:41] application faster than running on PHP
[00:43] 8.4. But I will release a video on the
[00:46] PHP 8.5 performance benchmark and
[00:49] comparison shortly. So subscribe to this
[00:51] channel if you haven't yet to get
[00:53] notified when it's out.
[00:56] Instead, in this video, I'm going to
[00:57] focus on changes that make individual
[01:00] code faster. The first optimization I
[01:03] want to talk about is an opcode
[01:05] specialization for the is identical
[01:08] array statement. What this means is um
[01:12] in PHP you can write uh a few different
[01:15] ways to think about comparing if an
[01:18] array is empty or not. So, uh one way
[01:21] would be to use the not operator. So say
[01:24] not a variable. You can say count of the
[01:28] array is zero. You can use the empty
[01:31] function and you can use um this way
[01:34] that is less common where you write the
[01:37] is identical operator three equals and
[01:39] then you write the empty uh array
[01:42] declaration um and compare it to that.
[01:45] And in PHP 8.4 and previously this was
[01:48] the slowest way of doing it. You can see
[01:51] my colleague Tim's benchmark here where
[01:54] he uh connects the four different ways I
[01:57] mentioned and empty using the empty um
[02:01] construct is the fastest one then the
[02:04] next is using the not operator then
[02:06] count and the slowest one is using the
[02:08] is identical statement. So the way it's
[02:10] written here
[02:12] and what you can do in the PHP engine is
[02:15] if there is an op code and you come
[02:17] across an op code for example the is
[02:20] identical operator and the op code for
[02:22] it you can write a specialized handling
[02:25] if you have c certain conditions that
[02:28] are true at compile time. So you at
[02:30] compile time you already know that you
[02:32] compare something against the empty
[02:35] array and um uh Tim did that in his
[02:39] patch. So he identified this case. You
[02:42] can see here you can use a specialized
[02:45] handler for the end is identical. And
[02:48] then here are the conditions that need
[02:51] to be true. And if that's true then he
[02:53] writes specialized op code which is much
[02:57] faster than the general op code for the
[03:00] is identical operation.
[03:02] And we are seeing the benefits in the
[03:05] second benchmark where we see that um
[03:09] the identical operation is the fastest
[03:12] one with um the empty and not one being
[03:15] 4% slower and using the count function
[03:18] being 30% slower. So what this shows is
[03:22] that using micro optimizations
[03:25] over time can produce code that is not
[03:28] even the fastest uh anymore because the
[03:31] underlying engine changes things in the
[03:34] functions change. So code changes
[03:37] through using more modern PHP versions.
[03:40] And what you can do or should do if like
[03:43] a certain block of code is not really
[03:45] critical and in the hot path, just use
[03:48] the um most readable way of writing code
[03:52] instead of hunting for always the best
[03:55] and most fastest uh way of writing
[03:57] something. The next optimization I want
[03:59] to talk about is also um optimizing op
[04:03] codes or generated op codes. This case
[04:06] in this case for the match true
[04:08] statement. So if you're using the the
[04:10] match statement with a true as the
[04:13] variable. So uh you want to use the
[04:16] different cases to differentiate which
[04:18] one is executed. Then uh with this pull
[04:21] request um and change in PHP 8.5 the
[04:25] generated op codes from that are
[04:27] optimized um and this construct will be
[04:31] faster.
[04:32] So um you can see um uh Fulkar also my
[04:37] colleague ran a small benchmark for this
[04:39] example that um is included in this pull
[04:42] request where there are four different
[04:46] uh match statements being executed um in
[04:49] this match true construct and he showed
[04:52] that for 1 million iterations
[04:55] um the new code is 20% faster just by
[04:58] having a more optimized match construct.
[05:01] The next optimization in PHP 8.5 is this
[05:05] new curl share init persistent API that
[05:08] was included through a RFC. And I've
[05:11] talked about this in a previous video.
[05:13] And this is going to have the most
[05:15] significant impact on applications, but
[05:18] it requires really that you change your
[05:21] um the way you communicate with third
[05:23] party APIs.
[05:25] Um as you might know, PHP has a shared
[05:28] nothing memory model. That means nothing
[05:30] is shared between processes. This
[05:32] includes if you do calls to third party
[05:34] APIs, the connection, the DNS resolving
[05:38] time and the SSL handshake time. And
[05:41] with the share in it um API for curl,
[05:44] you can now share this across multiple
[05:47] PHP requests and uh processes. That
[05:51] means you can only do the connection and
[05:55] DNS and SSL handshanking to a third
[05:58] party host once across the lifetime of
[06:01] the whole PHP process and then all
[06:03] subsequent requests will reuse that and
[06:06] this can mean a lot of time um saved
[06:11] if the third party API that you're
[06:14] talking uh to is not really located
[06:17] close to your uh servers And um once
[06:22] this is spread across different HTTP
[06:24] libraries like Gazle and Symfony HTTP
[06:27] client and they expose this and we are
[06:30] able to use this across our
[06:32] applications, we will see a lot of
[06:35] benefits uh from this change alone in
[06:37] PHP 8.5. How can you use it? It's a
[06:40] simple new API curl share in it. you
[06:42] pass uh one of three constants or all of
[06:45] them as an array DNS connect and SSL
[06:48] handshake and then you use this share
[06:51] resource and pass it to any curl handle
[06:54] as an option and this automatically
[06:57] makes this available across requests and
[07:00] processes and shares this another
[07:01] performance related change is uh
[07:04] relating to the garbage collection and
[07:07] previously in PHP 8.4 four and uh lower
[07:10] versions if you used enums or static fay
[07:14] closures then they were not specifically
[07:18] marked as um that they are not using
[07:21] cycles. So by definition an enum is not
[07:24] pointing to another object and also a
[07:28] static fake closure is not doing that.
[07:30] So they can never be actually garbage
[07:32] collected by the cycle collector because
[07:35] when they're present they are still used
[07:38] there's no cycle they cannot be
[07:39] collected so checking if they should be
[07:43] collected is already wasteful and with
[07:45] this change by Ilia they are not
[07:47] considered um for the cycle collection
[07:50] anymore and this either makes the
[07:54] garbage collection trigger much later
[07:57] because you're using a lot of enums and
[07:59] static factor closures or um it makes it
[08:03] faster because it's not considering
[08:05] these um additional objects that cannot
[08:09] be collected by the garbage collection.
[08:12] Anyways,
[08:15] so um you can see in this pull request
[08:18] here in the old way um for this example
[08:21] code for 10 million static fake closures
[08:25] um the garbage collection runs 44 times.
[08:28] Application runtime is 1.8. 8 seconds
[08:30] and after this change garbage collection
[08:32] doesn't run at all anymore and
[08:34] application time is 1.6 seconds. So 200
[08:38] milliseconds are saved uh by this
[08:40] optimization not wastefully running the
[08:42] garbage collector.
[08:45] So one thing you might ask yourself is
[08:47] what is a static fake closure? And in
[08:50] this example you can see using this um
[08:54] uh splat operator here the um to create
[08:57] a closure from a function call um is
[09:00] considered a st stat static fake closure
[09:03] in the engine and there's also another
[09:05] way to generate it using the closure
[09:08] from callable function on reflection
[09:11] closure from callable and um uh also a
[09:14] few other ways of creating static fake
[09:16] closures. Another change in PHP 8.5 is
[09:19] that opcache is now a required
[09:21] extension. It's a required part of PHP.
[09:24] You cannot disable it anymore. That also
[09:27] means opcache is not a shared object
[09:29] anymore. It's compiled into the PHP
[09:32] binary. And the only way to not have the
[09:36] opache cache something is to use any
[09:38] directives. OPC cache enable um to zero.
[09:42] And uh for CLI scripts, opcache enable
[09:46] CLI had to be enabled and still has to
[09:49] be enabled explicitly to enable opcache.
[09:53] The benefit of this change is that the
[09:55] optimizer of the engine and the
[09:57] optimizations that happen in opcache can
[10:00] now more easily interact with each
[10:02] other. It might be easier to write this
[10:04] code. It might be easier to move some
[10:07] code from op uh from the opcache
[10:09] extensions into the engine. It will
[10:12] reduce the maintenance cost and it will
[10:14] also reduce a source of errors. For
[10:17] example, it's still necessary in the
[10:19] official Docker PHP images to explicitly
[10:22] enable Docker and if you forget that
[10:25] then uh your Docker containers will not
[10:27] contain Docker at all uh op um cache at
[10:31] all. And this is a performance problem
[10:34] that we see occasionally from with
[10:36] customers using docker and kubernetus
[10:39] for example where their application is
[10:41] not using op uh cache at all because
[10:45] they forgot to include that in their php
[10:47] container. Another op uh cache related
[10:50] change is uh also going to be making
[10:54] docker container users
[10:57] uh lambda users for example through bre
[11:00] or through laravel um uh happy because
[11:04] there's now a way to generate the
[11:07] opcache file cache. So generating the
[11:10] opcache optimizations during a build
[11:12] step into files and then uh specifying
[11:16] that the file system of the running
[11:19] applicant
[11:31] that um with a readonly file system you
[11:34] couldn't use the the the file cache of
[11:37] opcache because it would just um perform
[11:41] uh delete operations and crash the
[11:44] process lead to errors and stuff. So
[11:46] this is now possible using an through an
[11:50] uh any setting you can specify that the
[11:54] file system of the cache is read only
[11:56] and this will uh make it possible to use
[11:59] it with breath. For example,
[12:02] you can see in the pull request also
[12:04] that the breath author Matthew Napoli um
[12:08] responded to this change and tested this
[12:10] and he saw um the cold start time of a
[12:14] container reduce by 100 to 150
[12:18] milliseconds um by using this and you
[12:21] can see his blog post uh on the topic.
[12:23] Uh I think this is a great thing uh um
[12:26] for these kind of deployment scenarios
[12:28] and I hope to see like uh these kind of
[12:31] big of improvements benefiting uh the
[12:34] whole community. Another operations
[12:36] related change is the introduction of
[12:38] the u PHP build provider constant. This
[12:42] constant is now compiled into the PHP
[12:45] binary if the um an if the environment
[12:49] variable PHP build provider is set
[12:52] during the compilation step. And this
[12:54] allows um a build provider for PHP to
[12:57] specify who they are. Gives some more
[13:00] context and the community already would
[13:03] work into individual build providers
[13:06] setting this. So, homebrew, dbian,
[13:08] fedora and the official docker images
[13:11] will set this value. You have this
[13:13] constant in PHP code available in this
[13:16] case. So, it's defined. You can echo it.
[13:19] And this information was already shown
[13:21] in the PHP info output and in the PHP-
[13:26] version output um of the binary and now
[13:29] is available at runtime. Another um
[13:32] change in PHP 8.5 is also reg uh
[13:36] regarding debugging capabilities. Um it
[13:39] will be especially helpful when
[13:41] providing error reports to the PHP
[13:43] projects or to open source projects. um
[13:46] you can specify this um d-ini
[13:50] equals diff um flag to the php binary
[13:55] and it will output all the ini settings
[13:58] that have changed compared to the
[14:01] default values. So it will only output
[14:04] the changed variables.
[14:06] And with this information, you can um uh
[14:09] attach it to a a buck report or
[14:11] something like that. And then a
[14:13] contributor can more easily see what you
[14:15] changed compared to the defaults. And it
[14:18] will make it much easier to uh to figure
[14:22] out the changes that potentially are
[14:25] causing problems um for maintainers.
[14:27] before PHP 8.5 um the memory limit uh
[14:32] variable that you can specify in PHP INI
[14:36] could always be overwritten at runtime
[14:38] by writing some code uh writing any set
[14:42] memory limit increasing it to 2 GB 4 GB
[14:46] whatever high value you want. However,
[14:49] in certain scenarios, the operator of a
[14:51] system may want to restrict uh and dis
[14:54] disallow the runtime to increase the
[14:57] memory indefinitely. And this is now uh
[15:00] possible in PHP 8.5. You can specify a
[15:04] maximum memory uh limit that um the
[15:08] runtime cannot increase above. So if you
[15:11] set the max memory limit for example to
[15:13] 200 mgabytes, runtime can never change
[15:16] it to be higher. If you try to attempt
[15:19] to set it higher then it will set it to
[15:22] the max memory limit and um this is
[15:25] giving additional safety to operators of
[15:29] PHP and um preventing developers of the
[15:33] system to increase the memory um across
[15:36] certain or above certain allowed limits.
[15:40] If you had memory related problems in
[15:42] PHP itself, crashes, uh anything related
[15:46] to the memory allocation, it was quite
[15:49] difficult to find these bugs without
[15:51] like recompiling PHP, adding additional
[15:54] memory protections, attaching a debugger
[15:57] um that allows this. All of this was
[16:00] quite difficult uh before and uh we at
[16:03] Tideways uh shipping a PHP extension to
[16:07] thirdparty people our customers using
[16:10] tideways sometimes if there's a problem
[16:12] in memory it was very hard debugging
[16:15] this with this change in PHP 8.4 four
[16:18] that are no addit. Um there's actually a
[16:22] way to increase the output um and have
[16:25] some additional memory debugging
[16:27] information just by setting an
[16:30] environment variable to the already
[16:32] compiled PHP binary. You can see in his
[16:35] pull request description the zen mm
[16:38] debug environment variable can get a
[16:41] bunch of different information here and
[16:43] with that you get additional debugging
[16:46] capabilities. And if you run like across
[16:49] a memory related sack fault in your PHP
[16:52] on production um you now have some
[16:56] additional capabilities of finding out
[16:58] why this happens. Arguably this is very
[17:01] advanced however like it will help
[17:04] across the community. another RFC that
[17:08] uh went into PHP 8.5 uh um improves
[17:11] debugging capabilities and it's um a new
[17:16] like an improvement to how back traces
[17:18] work with fatal errors or at least sort
[17:21] of now they are rendered with fatal
[17:24] errors. Previously, if you ran a PHP
[17:27] script and it uh ran into a fatal error,
[17:30] then there was actually no stack trace
[17:32] printed um with that error. So, if
[17:36] you're running a script on the CLI, for
[17:38] example, a fatal error occurred, maximum
[17:41] execution time of 1 second reached, you
[17:43] wouldn't have know like where this
[17:45] happened. And with PHP 8.5, we now
[17:48] automatically see the text stack trace
[17:50] attached to that. And this is also tied
[17:53] into the display error setting. So when
[17:56] you set display errors to on, you will
[17:58] see this. When it's to off, you won't
[18:00] see it. Uh so it's some additional
[18:02] information that helps you debug in your
[18:04] development system. When you show
[18:06] errors, um you will be able to see where
[18:09] they happened. The last change is also
[18:12] related to error handling and it's the
[18:14] introduction of two new functions, get
[18:17] error handler and get exception handler.
[18:20] It was previously possible to get access
[18:22] to these through some obscure way of
[18:26] using restore and set handler but it was
[18:29] not obvious to like new users of PHP how
[18:33] they are able to obtain u the reference
[18:37] to the current error and uh exception
[18:39] handler and with these two new functions
[18:42] it's now easier to write this kind of
[18:44] code there's are polyfills available to
[18:46] use it in lower versions but with PHP
[18:49] 8.5 five, you can now rely on these
[18:51] functions to be available and uh it's
[18:53] easier to write more complex um error
[18:56] handling and exception handling code uh
[18:58] using those two functions.
[19:00] I hope you can see there are some really
[19:02] great additions to PHP performance to uh
[19:05] operations and to debugging capabilities
[19:08] in PHP 8.5. I'm really excited about it.
[19:12] I'm also quite proud that uh my
[19:14] colleagues Tim and Fulkar did a lot of
[19:16] work on this release. Tim did like quite
[19:19] a few changes and Fula will be the
[19:22] release master of the 8.4 um branch and
[19:25] we as Tideways sort of like contributed
[19:28] to this version in this big regard. I
[19:31] hope uh that you find these changes
[19:34] interesting as well um and that you find
[19:37] they are a great addition um on top of
[19:41] the new features that PHP 8.5 will
[19:43] include. If you're interested in
[19:45] additional videos about PHP performance
[19:47] related topics, please subscribe to this
[19:50] channel or subscribe to the newsletter
[19:52] that is linked in the description as
[19:54] well. We and we will get in touch with
[19:56] you when something new is coming up.
[19:58] Bye.
⚡ Saved you time reading this? Transcribe any YouTube video for free — no signup needed.