From a3b1160882daf181eddf50ef993cb2037d06bcd5 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sun, 27 Apr 2025 14:05:10 +0200 Subject: [PATCH 1/4] Improve performance of instantiating exceptions/errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The class structure is fixed, so it makes no sense to go through all the logic of looking up property info etc. This patch introduces a local function `zend_obj_prop_num_checked()` to help with that. For this benchmark: ```php for ($i = 0; $i < 1000000; $i++) new Error; ``` On an i7-4790: ``` Benchmark 1: ./sapi/cli/php x.php Time (mean ± σ): 141.6 ms ± 9.3 ms [User: 138.7 ms, System: 2.0 ms] Range (min … max): 135.4 ms … 177.7 ms 20 runs Benchmark 2: ../RELx64_old/sapi/cli/php x.php Time (mean ± σ): 214.1 ms ± 7.0 ms [User: 207.6 ms, System: 5.0 ms] Range (min … max): 206.6 ms … 230.9 ms 13 runs Summary ./sapi/cli/php x.php ran 1.51 ± 0.11 times faster than ../RELx64_old/sapi/cli/php x.php ``` For this benchmark: ```php for ($i = 0; $i < 1000000; $i++) new Exception("message", 0, null); ``` On an i7-4790: ``` Benchmark 1: ./sapi/cli/php x.php Time (mean ± σ): 184.3 ms ± 9.5 ms [User: 181.2 ms, System: 1.8 ms] Range (min … max): 173.8 ms … 205.1 ms 15 runs Benchmark 2: ../RELx64_old/sapi/cli/php x.php Time (mean ± σ): 253.7 ms ± 7.0 ms [User: 247.6 ms, System: 4.6 ms] Range (min … max): 245.7 ms … 263.7 ms 11 runs Summary ./sapi/cli/php x.php ran 1.38 ± 0.08 times faster than ../RELx64_old/sapi/cli/php x.php ``` For this benchmark: ```php for ($i = 0; $i < 1000000; $i++) new ErrorException("message", 0, 0, "xyz", 0, null); ``` On an i7-4790: ``` Benchmark 1: ./sapi/cli/php x.php Time (mean ± σ): 223.6 ms ± 7.7 ms [User: 220.1 ms, System: 2.4 ms] Range (min … max): 216.9 ms … 242.5 ms 12 runs Benchmark 2: ../RELx64_old/sapi/cli/php x.php Time (mean ± σ): 343.5 ms ± 8.1 ms [User: 337.1 ms, System: 4.6 ms] Range (min … max): 337.3 ms … 362.8 ms 10 runs Summary ./sapi/cli/php x.php ran 1.54 ± 0.06 times faster than ../RELx64_old/sapi/cli/php x.php ``` --- UPGRADING | 1 + Zend/zend_exceptions.c | 96 ++++++++++++++++++++++++------------------ 2 files changed, 55 insertions(+), 42 deletions(-) diff --git a/UPGRADING b/UPGRADING index 04bc66c4890c4..40ee67903682a 100644 --- a/UPGRADING +++ b/UPGRADING @@ -502,6 +502,7 @@ PHP 8.5 UPGRADE NOTES - Core: . Remove OPcodes for identity comparisons against booleans, particularly for the match(true) pattern. + . Creating exceptions objects is now much faster. - ReflectionProperty: . Improved performance of the following methods: getValue(), getRawValue(), diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index f9d0ae8ea8173..38145aca215b4 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -254,41 +254,45 @@ ZEND_API void zend_clear_exception(void) /* {{{ */ } /* }}} */ +/* Same as OBJ_PROP_NUM(), but checks the offset is correct when Zend is built in debug mode. */ +static zend_always_inline zval *zend_obj_prop_num_checked(zend_object *object, uint32_t prop_num, zend_string *str) +{ +#if ZEND_DEBUG + zend_class_entry *old_scope = EG(fake_scope); + EG(fake_scope) = i_get_exception_base(object); + const zend_property_info *prop_info = zend_get_property_info(object->ce, str, true); + ZEND_ASSERT(OBJ_PROP_TO_NUM(prop_info->offset) == prop_num); + EG(fake_scope) = old_scope; +#else + ZEND_IGNORE_VALUE(str); +#endif + return OBJ_PROP_NUM(object, prop_num); +} + static zend_object *zend_default_exception_new(zend_class_entry *class_type) /* {{{ */ { - zval tmp; - zval trace; - zend_class_entry *base_ce; zend_string *filename; zend_object *object = zend_objects_new(class_type); object_properties_init(object, class_type); + zval *trace = zend_obj_prop_num_checked(object, 5, ZSTR_KNOWN(ZEND_STR_TRACE)); if (EG(current_execute_data)) { - zend_fetch_debug_backtrace(&trace, + zend_fetch_debug_backtrace(trace, 0, EG(exception_ignore_args) ? DEBUG_BACKTRACE_IGNORE_ARGS : 0, 0); } else { - array_init(&trace); + ZVAL_EMPTY_ARRAY(trace); } - Z_SET_REFCOUNT(trace, 0); - - base_ce = i_get_exception_base(object); if (EXPECTED((class_type != zend_ce_parse_error && class_type != zend_ce_compile_error) || !(filename = zend_get_compiled_filename()))) { - ZVAL_STRING(&tmp, zend_get_executed_filename()); - zend_update_property_ex(base_ce, object, ZSTR_KNOWN(ZEND_STR_FILE), &tmp); - zval_ptr_dtor(&tmp); - ZVAL_LONG(&tmp, zend_get_executed_lineno()); - zend_update_property_ex(base_ce, object, ZSTR_KNOWN(ZEND_STR_LINE), &tmp); + ZVAL_STRING(zend_obj_prop_num_checked(object, 3, ZSTR_KNOWN(ZEND_STR_FILE)), zend_get_executed_filename()); + ZVAL_LONG(zend_obj_prop_num_checked(object, 4, ZSTR_KNOWN(ZEND_STR_LINE)), zend_get_executed_lineno()); } else { - ZVAL_STR(&tmp, filename); - zend_update_property_ex(base_ce, object, ZSTR_KNOWN(ZEND_STR_FILE), &tmp); - ZVAL_LONG(&tmp, zend_get_compiled_lineno()); - zend_update_property_ex(base_ce, object, ZSTR_KNOWN(ZEND_STR_LINE), &tmp); + ZVAL_STR_COPY(zend_obj_prop_num_checked(object, 3, ZSTR_KNOWN(ZEND_STR_FILE)), filename); + ZVAL_LONG(zend_obj_prop_num_checked(object, 4, ZSTR_KNOWN(ZEND_STR_LINE)), zend_get_compiled_lineno()); } - zend_update_property_ex(base_ce, object, ZSTR_KNOWN(ZEND_STR_TRACE), &trace); return object; } @@ -307,28 +311,30 @@ ZEND_METHOD(Exception, __construct) { zend_string *message = NULL; zend_long code = 0; - zval tmp, *object, *previous = NULL; - zend_class_entry *base_ce; + zval *object, *previous = NULL; object = ZEND_THIS; - base_ce = i_get_exception_base(Z_OBJ_P(object)); if (zend_parse_parameters(ZEND_NUM_ARGS(), "|SlO!", &message, &code, &previous, zend_ce_throwable) == FAILURE) { RETURN_THROWS(); } if (message) { - ZVAL_STR(&tmp, message); - zend_update_property_ex(base_ce, Z_OBJ_P(object), ZSTR_KNOWN(ZEND_STR_MESSAGE), &tmp); + zval *tmp = zend_obj_prop_num_checked(Z_OBJ_P(object), 0, ZSTR_KNOWN(ZEND_STR_MESSAGE)); + zval_ptr_dtor(tmp); + ZVAL_STR_COPY(tmp, message); } if (code) { - ZVAL_LONG(&tmp, code); - zend_update_property_ex(base_ce, Z_OBJ_P(object), ZSTR_KNOWN(ZEND_STR_CODE), &tmp); + zval *tmp = zend_obj_prop_num_checked(Z_OBJ_P(object), 2, ZSTR_KNOWN(ZEND_STR_CODE)); + zval_ptr_dtor(tmp); + ZVAL_LONG(tmp, code); } if (previous) { - zend_update_property_ex(base_ce, Z_OBJ_P(object), ZSTR_KNOWN(ZEND_STR_PREVIOUS), previous); + zval *tmp = zend_obj_prop_num_checked(Z_OBJ_P(object), 6, ZSTR_KNOWN(ZEND_STR_PREVIOUS)); + zval_ptr_dtor(tmp); + ZVAL_COPY(tmp, previous); } } /* }}} */ @@ -358,7 +364,7 @@ ZEND_METHOD(ErrorException, __construct) zend_string *message = NULL, *filename = NULL; zend_long code = 0, severity = E_ERROR, lineno; bool lineno_is_null = 1; - zval tmp, *object, *previous = NULL; + zval *object, *previous = NULL; if (zend_parse_parameters(ZEND_NUM_ARGS(), "|SllS!l!O!", &message, &code, &severity, &filename, &lineno, &lineno_is_null, &previous, zend_ce_throwable) == FAILURE) { RETURN_THROWS(); @@ -367,35 +373,41 @@ ZEND_METHOD(ErrorException, __construct) object = ZEND_THIS; if (message) { - ZVAL_STR_COPY(&tmp, message); - zend_update_property_ex(zend_ce_exception, Z_OBJ_P(object), ZSTR_KNOWN(ZEND_STR_MESSAGE), &tmp); - zval_ptr_dtor(&tmp); + zval *tmp = zend_obj_prop_num_checked(Z_OBJ_P(object), 0, ZSTR_KNOWN(ZEND_STR_MESSAGE)); + zval_ptr_dtor(tmp); + ZVAL_STR_COPY(tmp, message); } if (code) { - ZVAL_LONG(&tmp, code); - zend_update_property_ex(zend_ce_exception, Z_OBJ_P(object), ZSTR_KNOWN(ZEND_STR_CODE), &tmp); + zval *tmp = zend_obj_prop_num_checked(Z_OBJ_P(object), 2, ZSTR_KNOWN(ZEND_STR_CODE)); + zval_ptr_dtor(tmp); + ZVAL_LONG(tmp, code); } if (previous) { - zend_update_property_ex(zend_ce_exception, Z_OBJ_P(object), ZSTR_KNOWN(ZEND_STR_PREVIOUS), previous); + zval *tmp = zend_obj_prop_num_checked(Z_OBJ_P(object), 6, ZSTR_KNOWN(ZEND_STR_PREVIOUS)); + zval_ptr_dtor(tmp); + ZVAL_COPY(tmp, previous); } - ZVAL_LONG(&tmp, severity); - zend_update_property_ex(zend_ce_exception, Z_OBJ_P(object), ZSTR_KNOWN(ZEND_STR_SEVERITY), &tmp); + { + zval *tmp = zend_obj_prop_num_checked(Z_OBJ_P(object), 7, ZSTR_KNOWN(ZEND_STR_SEVERITY)); + zval_ptr_dtor(tmp); + ZVAL_LONG(tmp, severity); + } if (filename) { - ZVAL_STR_COPY(&tmp, filename); - zend_update_property_ex(zend_ce_exception, Z_OBJ_P(object), ZSTR_KNOWN(ZEND_STR_FILE), &tmp); - zval_ptr_dtor(&tmp); + zval *tmp = zend_obj_prop_num_checked(Z_OBJ_P(object), 3, ZSTR_KNOWN(ZEND_STR_FILE)); + zval_ptr_dtor(tmp); + ZVAL_STR_COPY(tmp, filename); } + zval *tmp = zend_obj_prop_num_checked(Z_OBJ_P(object), 4, ZSTR_KNOWN(ZEND_STR_LINE)); + zval_ptr_dtor(tmp); if (!lineno_is_null) { - ZVAL_LONG(&tmp, lineno); - zend_update_property_ex(zend_ce_exception, Z_OBJ_P(object), ZSTR_KNOWN(ZEND_STR_LINE), &tmp); + ZVAL_LONG(tmp, lineno); } else if (filename) { - ZVAL_LONG(&tmp, 0); - zend_update_property_ex(zend_ce_exception, Z_OBJ_P(object), ZSTR_KNOWN(ZEND_STR_LINE), &tmp); + ZVAL_LONG(tmp, 0); } } /* }}} */ From 88e2844bd757f880cc66996268f930475d74b091 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Tue, 6 May 2025 20:49:27 +0200 Subject: [PATCH 2/4] Use safe dtor for previous and message --- Zend/zend_exceptions.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index 38145aca215b4..0da7cb44c3895 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -321,7 +321,7 @@ ZEND_METHOD(Exception, __construct) if (message) { zval *tmp = zend_obj_prop_num_checked(Z_OBJ_P(object), 0, ZSTR_KNOWN(ZEND_STR_MESSAGE)); - zval_ptr_dtor(tmp); + zval_ptr_safe_dtor(tmp); ZVAL_STR_COPY(tmp, message); } @@ -333,7 +333,7 @@ ZEND_METHOD(Exception, __construct) if (previous) { zval *tmp = zend_obj_prop_num_checked(Z_OBJ_P(object), 6, ZSTR_KNOWN(ZEND_STR_PREVIOUS)); - zval_ptr_dtor(tmp); + zval_ptr_safe_dtor(tmp); ZVAL_COPY(tmp, previous); } } @@ -374,7 +374,7 @@ ZEND_METHOD(ErrorException, __construct) if (message) { zval *tmp = zend_obj_prop_num_checked(Z_OBJ_P(object), 0, ZSTR_KNOWN(ZEND_STR_MESSAGE)); - zval_ptr_dtor(tmp); + zval_ptr_safe_dtor(tmp); ZVAL_STR_COPY(tmp, message); } @@ -386,7 +386,7 @@ ZEND_METHOD(ErrorException, __construct) if (previous) { zval *tmp = zend_obj_prop_num_checked(Z_OBJ_P(object), 6, ZSTR_KNOWN(ZEND_STR_PREVIOUS)); - zval_ptr_dtor(tmp); + zval_ptr_safe_dtor(tmp); ZVAL_COPY(tmp, previous); } From 019cdd02bace9e5302d7a6fe67fddff143deba73 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Tue, 6 May 2025 21:07:58 +0200 Subject: [PATCH 3/4] Changes for hooks --- Zend/zend_exceptions.c | 95 ++++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 45 deletions(-) diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index 0da7cb44c3895..50ae8789e52f6 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -254,44 +254,59 @@ ZEND_API void zend_clear_exception(void) /* {{{ */ } /* }}} */ -/* Same as OBJ_PROP_NUM(), but checks the offset is correct when Zend is built in debug mode. */ -static zend_always_inline zval *zend_obj_prop_num_checked(zend_object *object, uint32_t prop_num, zend_string *str) +/* Same as writing to OBJ_PROP_NUM() when there are no hooks, + * but checks the offset is correct when Zend is built in debug mode. + * This is faster than going through the regular property write routine when the offset is known at compile time. */ +static void zend_update_property_num_checked(zend_object *object, uint32_t prop_num, zend_string *member, zval *value) { + if (UNEXPECTED(object->ce->num_hooked_props > 0)) { + /* Property may have been overridden with a hook. */ + zend_update_property_ex(object->ce, object, member, value); + zval_ptr_dtor(value); + return; + } #if ZEND_DEBUG zend_class_entry *old_scope = EG(fake_scope); EG(fake_scope) = i_get_exception_base(object); - const zend_property_info *prop_info = zend_get_property_info(object->ce, str, true); + const zend_property_info *prop_info = zend_get_property_info(object->ce, member, true); ZEND_ASSERT(OBJ_PROP_TO_NUM(prop_info->offset) == prop_num); EG(fake_scope) = old_scope; -#else - ZEND_IGNORE_VALUE(str); #endif - return OBJ_PROP_NUM(object, prop_num); + zval *zv = OBJ_PROP_NUM(object, prop_num); + zval_ptr_safe_dtor(zv); + ZVAL_COPY_VALUE(zv, value); } static zend_object *zend_default_exception_new(zend_class_entry *class_type) /* {{{ */ { + zval tmp; + zval trace; zend_string *filename; zend_object *object = zend_objects_new(class_type); object_properties_init(object, class_type); - zval *trace = zend_obj_prop_num_checked(object, 5, ZSTR_KNOWN(ZEND_STR_TRACE)); if (EG(current_execute_data)) { - zend_fetch_debug_backtrace(trace, + zend_fetch_debug_backtrace(&trace, 0, EG(exception_ignore_args) ? DEBUG_BACKTRACE_IGNORE_ARGS : 0, 0); } else { - ZVAL_EMPTY_ARRAY(trace); + ZVAL_EMPTY_ARRAY(&trace); } + zend_update_property_num_checked(object, 5, ZSTR_KNOWN(ZEND_STR_TRACE), &trace); + if (EXPECTED((class_type != zend_ce_parse_error && class_type != zend_ce_compile_error) || !(filename = zend_get_compiled_filename()))) { - ZVAL_STRING(zend_obj_prop_num_checked(object, 3, ZSTR_KNOWN(ZEND_STR_FILE)), zend_get_executed_filename()); - ZVAL_LONG(zend_obj_prop_num_checked(object, 4, ZSTR_KNOWN(ZEND_STR_LINE)), zend_get_executed_lineno()); + ZVAL_STRING(&tmp, zend_get_executed_filename()); + zend_update_property_num_checked(object, 3, ZSTR_KNOWN(ZEND_STR_FILE), &tmp); + ZVAL_LONG(&tmp, zend_get_executed_lineno()); + zend_update_property_num_checked(object, 4, ZSTR_KNOWN(ZEND_STR_LINE), &tmp); } else { - ZVAL_STR_COPY(zend_obj_prop_num_checked(object, 3, ZSTR_KNOWN(ZEND_STR_FILE)), filename); - ZVAL_LONG(zend_obj_prop_num_checked(object, 4, ZSTR_KNOWN(ZEND_STR_LINE)), zend_get_compiled_lineno()); + ZVAL_STR_COPY(&tmp, filename); + zend_update_property_num_checked(object, 3, ZSTR_KNOWN(ZEND_STR_FILE), &tmp); + ZVAL_LONG(&tmp, zend_get_compiled_lineno()); + zend_update_property_num_checked(object, 4, ZSTR_KNOWN(ZEND_STR_LINE), &tmp); } return object; @@ -311,7 +326,7 @@ ZEND_METHOD(Exception, __construct) { zend_string *message = NULL; zend_long code = 0; - zval *object, *previous = NULL; + zval tmp, *object, *previous = NULL; object = ZEND_THIS; @@ -320,21 +335,18 @@ ZEND_METHOD(Exception, __construct) } if (message) { - zval *tmp = zend_obj_prop_num_checked(Z_OBJ_P(object), 0, ZSTR_KNOWN(ZEND_STR_MESSAGE)); - zval_ptr_safe_dtor(tmp); - ZVAL_STR_COPY(tmp, message); + ZVAL_STR_COPY(&tmp, message); + zend_update_property_num_checked(Z_OBJ_P(object), 0, ZSTR_KNOWN(ZEND_STR_MESSAGE), &tmp); } if (code) { - zval *tmp = zend_obj_prop_num_checked(Z_OBJ_P(object), 2, ZSTR_KNOWN(ZEND_STR_CODE)); - zval_ptr_dtor(tmp); - ZVAL_LONG(tmp, code); + ZVAL_LONG(&tmp, code); + zend_update_property_num_checked(Z_OBJ_P(object), 2, ZSTR_KNOWN(ZEND_STR_CODE), &tmp); } if (previous) { - zval *tmp = zend_obj_prop_num_checked(Z_OBJ_P(object), 6, ZSTR_KNOWN(ZEND_STR_PREVIOUS)); - zval_ptr_safe_dtor(tmp); - ZVAL_COPY(tmp, previous); + Z_ADDREF_P(previous); + zend_update_property_num_checked(Z_OBJ_P(object), 6, ZSTR_KNOWN(ZEND_STR_PREVIOUS), previous); } } /* }}} */ @@ -364,7 +376,7 @@ ZEND_METHOD(ErrorException, __construct) zend_string *message = NULL, *filename = NULL; zend_long code = 0, severity = E_ERROR, lineno; bool lineno_is_null = 1; - zval *object, *previous = NULL; + zval tmp, *object, *previous = NULL; if (zend_parse_parameters(ZEND_NUM_ARGS(), "|SllS!l!O!", &message, &code, &severity, &filename, &lineno, &lineno_is_null, &previous, zend_ce_throwable) == FAILURE) { RETURN_THROWS(); @@ -373,41 +385,34 @@ ZEND_METHOD(ErrorException, __construct) object = ZEND_THIS; if (message) { - zval *tmp = zend_obj_prop_num_checked(Z_OBJ_P(object), 0, ZSTR_KNOWN(ZEND_STR_MESSAGE)); - zval_ptr_safe_dtor(tmp); - ZVAL_STR_COPY(tmp, message); + ZVAL_STR_COPY(&tmp, message); + zend_update_property_num_checked(Z_OBJ_P(object), 0, ZSTR_KNOWN(ZEND_STR_MESSAGE), &tmp); } if (code) { - zval *tmp = zend_obj_prop_num_checked(Z_OBJ_P(object), 2, ZSTR_KNOWN(ZEND_STR_CODE)); - zval_ptr_dtor(tmp); - ZVAL_LONG(tmp, code); + ZVAL_LONG(&tmp, code); + zend_update_property_num_checked(Z_OBJ_P(object), 2, ZSTR_KNOWN(ZEND_STR_CODE), &tmp); } if (previous) { - zval *tmp = zend_obj_prop_num_checked(Z_OBJ_P(object), 6, ZSTR_KNOWN(ZEND_STR_PREVIOUS)); - zval_ptr_safe_dtor(tmp); - ZVAL_COPY(tmp, previous); + Z_ADDREF_P(previous); + zend_update_property_num_checked(Z_OBJ_P(object), 6, ZSTR_KNOWN(ZEND_STR_PREVIOUS), previous); } - { - zval *tmp = zend_obj_prop_num_checked(Z_OBJ_P(object), 7, ZSTR_KNOWN(ZEND_STR_SEVERITY)); - zval_ptr_dtor(tmp); - ZVAL_LONG(tmp, severity); - } + ZVAL_LONG(&tmp, severity); + zend_update_property_num_checked(Z_OBJ_P(object), 7, ZSTR_KNOWN(ZEND_STR_SEVERITY), &tmp); if (filename) { - zval *tmp = zend_obj_prop_num_checked(Z_OBJ_P(object), 3, ZSTR_KNOWN(ZEND_STR_FILE)); - zval_ptr_dtor(tmp); - ZVAL_STR_COPY(tmp, filename); + ZVAL_STR_COPY(&tmp, filename); + zend_update_property_num_checked(Z_OBJ_P(object), 3, ZSTR_KNOWN(ZEND_STR_FILE), &tmp); } - zval *tmp = zend_obj_prop_num_checked(Z_OBJ_P(object), 4, ZSTR_KNOWN(ZEND_STR_LINE)); - zval_ptr_dtor(tmp); if (!lineno_is_null) { - ZVAL_LONG(tmp, lineno); + ZVAL_LONG(&tmp, lineno); + zend_update_property_num_checked(Z_OBJ_P(object), 4, ZSTR_KNOWN(ZEND_STR_LINE), &tmp); } else if (filename) { - ZVAL_LONG(tmp, 0); + ZVAL_LONG(&tmp, 0); + zend_update_property_num_checked(Z_OBJ_P(object), 4, ZSTR_KNOWN(ZEND_STR_LINE), &tmp); } } /* }}} */ From b29b9e58c9f75e4ae9e81b4b07519d1329a39241 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Tue, 6 May 2025 21:32:00 +0200 Subject: [PATCH 4/4] wording --- UPGRADING | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UPGRADING b/UPGRADING index 40ee67903682a..863e24bef650c 100644 --- a/UPGRADING +++ b/UPGRADING @@ -502,7 +502,7 @@ PHP 8.5 UPGRADE NOTES - Core: . Remove OPcodes for identity comparisons against booleans, particularly for the match(true) pattern. - . Creating exceptions objects is now much faster. + . Creating exception objects is now much faster. - ReflectionProperty: . Improved performance of the following methods: getValue(), getRawValue(),