[0:00] PHP 8.5 will be released this week and [0:03] there's been a lot of work behind the [0:05] scenes on performance operations and [0:07] debugging related improvements which I [0:09] want to highlight in this video. You [0:12] cannot usually find these in new release [0:14] announcement post or other videos. Mo I [0:17] am Benjamin and I'm working on PHP [0:19] performance related topics for the past [0:21] 10 years helping thousands of developers [0:24] along the way. If you want to know if [0:27] PHP 8.5 is faster than previous versions [0:30] of PHP, then I have to disappoint you. [0:33] There have been no significant general [0:35] improvements to PHP 8.5. So that an [0:39] upgrade will unconditionally make your [0:41] application faster than running on PHP [0:43] 8.4. But I will release a video on the [0:46] PHP 8.5 performance benchmark and [0:49] comparison shortly. So subscribe to this [0:51] channel if you haven't yet to get [0:53] notified when it's out. [0:56] Instead, in this video, I'm going to [0:57] focus on changes that make individual [1:00] code faster. The first optimization I [1:03] want to talk about is an opcode [1:05] specialization for the is identical [1:08] array statement. What this means is um [1:12] in PHP you can write uh a few different [1:15] ways to think about comparing if an [1:18] array is empty or not. So, uh one way [1:21] would be to use the not operator. So say [1:24] not a variable. You can say count of the [1:28] array is zero. You can use the empty [1:31] function and you can use um this way [1:34] that is less common where you write the [1:37] is identical operator three equals and [1:39] then you write the empty uh array [1:42] declaration um and compare it to that. [1:45] And in PHP 8.4 and previously this was [1:48] the slowest way of doing it. You can see [1:51] my colleague Tim's benchmark here where [1:54] he uh connects the four different ways I [1:57] mentioned and empty using the empty um [2:01] construct is the fastest one then the [2:04] next is using the not operator then [2:06] count and the slowest one is using the [2:08] is identical statement. So the way it's [2:10] written here [2:12] and what you can do in the PHP engine is [2:15] if there is an op code and you come [2:17] across an op code for example the is [2:20] identical operator and the op code for [2:22] it you can write a specialized handling [2:25] if you have c certain conditions that [2:28] are true at compile time. So you at [2:30] compile time you already know that you [2:32] compare something against the empty [2:35] array and um uh Tim did that in his [2:39] patch. So he identified this case. You [2:42] can see here you can use a specialized [2:45] handler for the end is identical. And [2:48] then here are the conditions that need [2:51] to be true. And if that's true then he [2:53] writes specialized op code which is much [2:57] faster than the general op code for the [3:00] is identical operation. [3:02] And we are seeing the benefits in the [3:05] second benchmark where we see that um [3:09] the identical operation is the fastest [3:12] one with um the empty and not one being [3:15] 4% slower and using the count function [3:18] being 30% slower. So what this shows is [3:22] that using micro optimizations [3:25] over time can produce code that is not [3:28] even the fastest uh anymore because the [3:31] underlying engine changes things in the [3:34] functions change. So code changes [3:37] through using more modern PHP versions. [3:40] And what you can do or should do if like [3:43] a certain block of code is not really [3:45] critical and in the hot path, just use [3:48] the um most readable way of writing code [3:52] instead of hunting for always the best [3:55] and most fastest uh way of writing [3:57] something. The next optimization I want [3:59] to talk about is also um optimizing op [4:03] codes or generated op codes. This case [4:06] in this case for the match true [4:08] statement. So if you're using the the [4:10] match statement with a true as the [4:13] variable. So uh you want to use the [4:16] different cases to differentiate which [4:18] one is executed. Then uh with this pull [4:21] request um and change in PHP 8.5 the [4:25] generated op codes from that are [4:27] optimized um and this construct will be [4:31] faster. [4:32] So um you can see um uh Fulkar also my [4:37] colleague ran a small benchmark for this [4:39] example that um is included in this pull [4:42] request where there are four different [4:46] uh match statements being executed um in [4:49] this match true construct and he showed [4:52] that for 1 million iterations [4:55] um the new code is 20% faster just by [4:58] having a more optimized match construct. [5:01] The next optimization in PHP 8.5 is this [5:05] new curl share init persistent API that [5:08] was included through a RFC. And I've [5:11] talked about this in a previous video. [5:13] And this is going to have the most [5:15] significant impact on applications, but [5:18] it requires really that you change your [5:21] um the way you communicate with third [5:23] party APIs. [5:25] Um as you might know, PHP has a shared [5:28] nothing memory model. That means nothing [5:30] is shared between processes. This [5:32] includes if you do calls to third party [5:34] APIs, the connection, the DNS resolving [5:38] time and the SSL handshake time. And [5:41] with the share in it um API for curl, [5:44] you can now share this across multiple [5:47] PHP requests and uh processes. That [5:51] means you can only do the connection and [5:55] DNS and SSL handshanking to a third [5:58] party host once across the lifetime of [6:01] the whole PHP process and then all [6:03] subsequent requests will reuse that and [6:06] this can mean a lot of time um saved [6:11] if the third party API that you're [6:14] talking uh to is not really located [6:17] close to your uh servers And um once [6:22] this is spread across different HTTP [6:24] libraries like Gazle and Symfony HTTP [6:27] client and they expose this and we are [6:30] able to use this across our [6:32] applications, we will see a lot of [6:35] benefits uh from this change alone in [6:37] PHP 8.5. How can you use it? It's a [6:40] simple new API curl share in it. you [6:42] pass uh one of three constants or all of [6:45] them as an array DNS connect and SSL [6:48] handshake and then you use this share [6:51] resource and pass it to any curl handle [6:54] as an option and this automatically [6:57] makes this available across requests and [7:00] processes and shares this another [7:01] performance related change is uh [7:04] relating to the garbage collection and [7:07] previously in PHP 8.4 four and uh lower [7:10] versions if you used enums or static fay [7:14] closures then they were not specifically [7:18] marked as um that they are not using [7:21] cycles. So by definition an enum is not [7:24] pointing to another object and also a [7:28] static fake closure is not doing that. [7:30] So they can never be actually garbage [7:32] collected by the cycle collector because [7:35] when they're present they are still used [7:38] there's no cycle they cannot be [7:39] collected so checking if they should be [7:43] collected is already wasteful and with [7:45] this change by Ilia they are not [7:47] considered um for the cycle collection [7:50] anymore and this either makes the [7:54] garbage collection trigger much later [7:57] because you're using a lot of enums and [7:59] static factor closures or um it makes it [8:03] faster because it's not considering [8:05] these um additional objects that cannot [8:09] be collected by the garbage collection. [8:12] Anyways, [8:15] so um you can see in this pull request [8:18] here in the old way um for this example [8:21] code for 10 million static fake closures [8:25] um the garbage collection runs 44 times. [8:28] Application runtime is 1.8. 8 seconds [8:30] and after this change garbage collection [8:32] doesn't run at all anymore and [8:34] application time is 1.6 seconds. So 200 [8:38] milliseconds are saved uh by this [8:40] optimization not wastefully running the [8:42] garbage collector. [8:45] So one thing you might ask yourself is [8:47] what is a static fake closure? And in [8:50] this example you can see using this um [8:54] uh splat operator here the um to create [8:57] a closure from a function call um is [9:00] considered a st stat static fake closure [9:03] in the engine and there's also another [9:05] way to generate it using the closure [9:08] from callable function on reflection [9:11] closure from callable and um uh also a [9:14] few other ways of creating static fake [9:16] closures. Another change in PHP 8.5 is [9:19] that opcache is now a required [9:21] extension. It's a required part of PHP. [9:24] You cannot disable it anymore. That also [9:27] means opcache is not a shared object [9:29] anymore. It's compiled into the PHP [9:32] binary. And the only way to not have the [9:36] opache cache something is to use any [9:38] directives. OPC cache enable um to zero. [9:42] And uh for CLI scripts, opcache enable [9:46] CLI had to be enabled and still has to [9:49] be enabled explicitly to enable opcache. [9:53] The benefit of this change is that the [9:55] optimizer of the engine and the [9: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.