diff --git a/NEWS b/NEWS index 9690787e59bf..2e921b6c26f8 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,8 @@ PHP NEWS . Fixed GH-10497 (Allow direct mutation of objects stored in constants or class constants via OBJ->prop = $val). (Khaled Alam) . Reverted GH-22833, which attempted to fix bug GH-18985. (ilutov) + . Using the return statement in a finally block is now deprecated. + (aldemeery) - Curl: . Set content length using CURLOPT_POSTFIELDSIZE_LARGE instead of @@ -21,6 +23,10 @@ PHP NEWS DOMDocument::xinclude(). (iliaal) . Fixed a crash in DOMXPath when a php:function callback receives a nodeset and a later callback returns a node from another document. (iliaal) + . Fixed bug GH-23331 (UAF when node_list_unlink() skips attribute children + that still have a live wrapper). (iliaal) + . Fixed a use-after-free when Dom\Element::setAttributeNS() replaces the + value of an attribute whose child still has a live wrapper. (iliaal) - PDO_PGSQL: . Fixed several lazy fetch (PDO::ATTR_PREFETCH => 0) defects: an infinite @@ -36,6 +42,9 @@ PHP NEWS the ICU constructor adopts the TimeZone. (iliaal) . Fixed bug GH-23094 (NumberFormatter parsing offsets use UTF-16 positions for UTF-8 strings). (ColumbusLabs) + . Fixed Locale::parseLocale() reading past a trailing '-' or '_'. + (iliaal, Xuyang Zhang) + . Fixed grapheme_str_split() treating UBRK_DONE as a byte index. (iliaal) - Phar: . Fixed Phar archives being automatically detected when ".phar" only occurs @@ -45,6 +54,10 @@ PHP NEWS - Readline: . Fixed class constant completion in the interactive shell. (Weilin Du) +- Session: + . Fixed bug GH-23056 (missing handler name in session write warning). + (lazerg) + - Zip: . Fixed bug GH-17787 (ZipArchive stream stops reading early when the archive is freed while the stream is still open). (Eyüp Can Akman) diff --git a/UPGRADING b/UPGRADING index e32c1fe55748..e8eec0d0bbdd 100644 --- a/UPGRADING +++ b/UPGRADING @@ -454,6 +454,8 @@ PHP 8.6 UPGRADE NOTES - Core: . Using "namespace" as a class constant name is deprecated. + . Using the return statement in a finally block is now deprecated. + RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_returning_from_a_finally_block . Specifying a return type of array|null / ?array for __debugInfo() is now deprecated. Specify array instead. . Returning values from __construct() and __destruct() is now deprecated. diff --git a/Zend/tests/exit_finally_3.phpt b/Zend/tests/exit_finally_3.phpt index 12d7747adea9..a2ae2429b28e 100644 --- a/Zend/tests/exit_finally_3.phpt +++ b/Zend/tests/exit_finally_3.phpt @@ -15,5 +15,6 @@ function test() { var_dump(test()); ?> ---EXPECT-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d Exit diff --git a/Zend/tests/gc/gc_050.phpt b/Zend/tests/gc/gc_050.phpt index 0bedc7220fd4..cf30776d9de9 100644 --- a/Zend/tests/gc/gc_050.phpt +++ b/Zend/tests/gc/gc_050.phpt @@ -36,5 +36,6 @@ for ($i = 0; $i < 100000; $i++) { } echo "OK\n"; ?> ---EXPECT-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d OK diff --git a/Zend/tests/generators/finally/return_return.phpt b/Zend/tests/generators/finally/return_return.phpt index 194fc93de7c2..895adc37cce3 100644 --- a/Zend/tests/generators/finally/return_return.phpt +++ b/Zend/tests/generators/finally/return_return.phpt @@ -27,7 +27,8 @@ $gen = gen(); $gen->rewind(); // force run ?> ---EXPECT-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d before return before return in inner finally outer finally run diff --git a/Zend/tests/generators/finally/yield_return.phpt b/Zend/tests/generators/finally/yield_return.phpt index 6191f389e53e..dbfabea50889 100644 --- a/Zend/tests/generators/finally/yield_return.phpt +++ b/Zend/tests/generators/finally/yield_return.phpt @@ -15,5 +15,6 @@ foreach (foo(1, 5) as $x) { echo $x, "\n"; } ?> ---EXPECT-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d 1 diff --git a/Zend/tests/generators/get_return_and_finally.phpt b/Zend/tests/generators/get_return_and_finally.phpt index 150e5b83c4db..8ced4d0008b5 100644 --- a/Zend/tests/generators/get_return_and_finally.phpt +++ b/Zend/tests/generators/get_return_and_finally.phpt @@ -41,7 +41,8 @@ try { } ?> ---EXPECT-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d int(42) gen2() throw Cannot get return value of a generator that hasn't returned diff --git a/Zend/tests/generators/gh11028_1.phpt b/Zend/tests/generators/gh11028_1.phpt index e1e7aa5019e5..d1c07dc9de66 100644 --- a/Zend/tests/generators/gh11028_1.phpt +++ b/Zend/tests/generators/gh11028_1.phpt @@ -24,7 +24,8 @@ test("false", false); test("true", true); test("object", new stdClass); ?> ---EXPECT-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d yield null Keys must be of type int|string during array unpacking yield false diff --git a/Zend/tests/generators/gh11028_2.phpt b/Zend/tests/generators/gh11028_2.phpt index ddc9618e8ed8..bf364329849f 100644 --- a/Zend/tests/generators/gh11028_2.phpt +++ b/Zend/tests/generators/gh11028_2.phpt @@ -15,6 +15,8 @@ $c = (function () { })()[0]; ?> --EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d + Warning: Undefined variable $a in %s on line %d Fatal error: Uncaught Error: Keys must be of type int|string during array unpacking in %s:%d diff --git a/Zend/tests/generators/gh11028_3.phpt b/Zend/tests/generators/gh11028_3.phpt index 7ea1aac6f6cf..c58e00dc09b1 100644 --- a/Zend/tests/generators/gh11028_3.phpt +++ b/Zend/tests/generators/gh11028_3.phpt @@ -17,5 +17,6 @@ try { echo $e->getMessage(), "\n"; } ?> ---EXPECT-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d exception diff --git a/Zend/tests/generators/yield_in_finally_cleanup.phpt b/Zend/tests/generators/yield_in_finally_cleanup.phpt index 9a76261e0d5e..538c14bdb774 100644 --- a/Zend/tests/generators/yield_in_finally_cleanup.phpt +++ b/Zend/tests/generators/yield_in_finally_cleanup.phpt @@ -47,5 +47,6 @@ gen4()->rewind(); ?> ===DONE=== ---EXPECT-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d ===DONE=== diff --git a/Zend/tests/oss_fuzz_438780145.phpt b/Zend/tests/oss_fuzz_438780145.phpt index 4c6936a69a01..11797fcce999 100644 --- a/Zend/tests/oss_fuzz_438780145.phpt +++ b/Zend/tests/oss_fuzz_438780145.phpt @@ -20,6 +20,8 @@ test(); ?> --EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d + Fatal error: Uncaught TypeError: test(): Return value must be of type int, string returned in %s:%d Stack trace: #0 %s(%d): test() diff --git a/Zend/tests/return_types/029.phpt b/Zend/tests/return_types/029.phpt index c6fb4432158c..8711df828fff 100644 --- a/Zend/tests/return_types/029.phpt +++ b/Zend/tests/return_types/029.phpt @@ -14,6 +14,8 @@ function foo() : array { foo(); ?> --EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d + Fatal error: Uncaught Exception: xxxx in %s:%d Stack trace: #0 %s(%d): foo() diff --git a/Zend/tests/return_types/never_finally_return.phpt b/Zend/tests/return_types/never_finally_return.phpt index b03859710276..2a6af6923eef 100644 --- a/Zend/tests/return_types/never_finally_return.phpt +++ b/Zend/tests/return_types/never_finally_return.phpt @@ -14,4 +14,6 @@ function foo() : never { // Note the lack of function call: function validated at compile-time ?> --EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d + Fatal error: A never-returning function must not return in %s on line %d diff --git a/Zend/tests/try/bug70228.phpt b/Zend/tests/try/bug70228.phpt index 8b812517a305..b69034da8a6c 100644 --- a/Zend/tests/try/bug70228.phpt +++ b/Zend/tests/try/bug70228.phpt @@ -10,5 +10,6 @@ function foo() { var_dump(foo()); ?> ---EXPECT-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d string(2) "bb" diff --git a/Zend/tests/try/bug70228_2.phpt b/Zend/tests/try/bug70228_2.phpt index c988e706ce47..bbb44bcd6a42 100644 --- a/Zend/tests/try/bug70228_2.phpt +++ b/Zend/tests/try/bug70228_2.phpt @@ -16,5 +16,6 @@ function test() { var_dump(test()); ?> ---EXPECT-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d int(42) diff --git a/Zend/tests/try/bug70228_3.phpt b/Zend/tests/try/bug70228_3.phpt index 55dbe4f8914a..80a0f379765b 100644 --- a/Zend/tests/try/bug70228_3.phpt +++ b/Zend/tests/try/bug70228_3.phpt @@ -26,6 +26,7 @@ try { } while ($e); } ?> ---EXPECT-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d 2 1 diff --git a/Zend/tests/try/bug70228_4.phpt b/Zend/tests/try/bug70228_4.phpt index f0ab3b0c2c11..7e0fd78707d7 100644 --- a/Zend/tests/try/bug70228_4.phpt +++ b/Zend/tests/try/bug70228_4.phpt @@ -28,5 +28,6 @@ try { } while ($e); } ?> ---EXPECT-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d 1 diff --git a/Zend/tests/try/bug70228_6.phpt b/Zend/tests/try/bug70228_6.phpt index fc68657f4c15..5bc3a70bdcfe 100644 --- a/Zend/tests/try/bug70228_6.phpt +++ b/Zend/tests/try/bug70228_6.phpt @@ -14,5 +14,6 @@ function test($x) { var_dump(test([1])); ?> ---EXPECT-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d int(42) diff --git a/Zend/tests/try/catch_finally_003.phpt b/Zend/tests/try/catch_finally_003.phpt index 610d701872b1..3cfb4fd6c5a1 100644 --- a/Zend/tests/try/catch_finally_003.phpt +++ b/Zend/tests/try/catch_finally_003.phpt @@ -32,7 +32,10 @@ function &bar($a) { var_dump(foo("para")); var_dump(bar("para")); ?> ---EXPECT-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d + +Deprecated: Returning from a finally block is deprecated in %s on line %d string(3) "try" string(7) "finally" string(7) "finally" diff --git a/Zend/tests/try/catch_finally_005.phpt b/Zend/tests/try/catch_finally_005.phpt index 7671d05df582..bc4a72155bf6 100644 --- a/Zend/tests/try/catch_finally_005.phpt +++ b/Zend/tests/try/catch_finally_005.phpt @@ -17,5 +17,6 @@ function foo ($a) { var_dump(foo("para")); ?> ---EXPECT-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d int(3) diff --git a/Zend/tests/try/catch_finally_006.phpt b/Zend/tests/try/catch_finally_006.phpt index 216219b6a5b3..463ce377f0a3 100644 --- a/Zend/tests/try/catch_finally_006.phpt +++ b/Zend/tests/try/catch_finally_006.phpt @@ -22,7 +22,8 @@ try { var_dump($e->getMessage()); } ?> ---EXPECT-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d string(4) "para" string(7) "finally" string(6) "return" diff --git a/Zend/tests/try/finally_goto_005.phpt b/Zend/tests/try/finally_goto_005.phpt index ffb0e68be103..0cb38a502993 100644 --- a/Zend/tests/try/finally_goto_005.phpt +++ b/Zend/tests/try/finally_goto_005.phpt @@ -11,5 +11,6 @@ label: try { } ?> ---EXPECT-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d success diff --git a/Zend/tests/try/finally_return_deprecation.phpt b/Zend/tests/try/finally_return_deprecation.phpt new file mode 100644 index 000000000000..86cc07e59481 --- /dev/null +++ b/Zend/tests/try/finally_return_deprecation.phpt @@ -0,0 +1,86 @@ +--TEST-- +Returning from a finally block is deprecated +--FILE-- + +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d + +Deprecated: Returning from a finally block is deprecated in %s on line %d + +Deprecated: Returning from a finally block is deprecated in %s on line %d + +Deprecated: Returning from a finally block is deprecated in %s on line %d + +Deprecated: Returning from a finally block is deprecated in %s on line %d diff --git a/Zend/tests/try/try_catch_finally_003.phpt b/Zend/tests/try/try_catch_finally_003.phpt index 4d285eedb8da..3e37256837b0 100644 --- a/Zend/tests/try/try_catch_finally_003.phpt +++ b/Zend/tests/try/try_catch_finally_003.phpt @@ -32,5 +32,6 @@ function foo () { var_dump(foo()); ?> ---EXPECT-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d 1234int(4) diff --git a/Zend/tests/try/try_finally_013.phpt b/Zend/tests/try/try_finally_013.phpt index 0e82dcbb4cf4..1f0e044a1285 100644 --- a/Zend/tests/try/try_finally_013.phpt +++ b/Zend/tests/try/try_finally_013.phpt @@ -18,6 +18,7 @@ function foo() { foo(); ?> ---EXPECT-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d try finally diff --git a/Zend/tests/try/try_finally_014.phpt b/Zend/tests/try/try_finally_014.phpt index a45f63f1f3d4..0cdc8ddffc8a 100644 --- a/Zend/tests/try/try_finally_014.phpt +++ b/Zend/tests/try/try_finally_014.phpt @@ -20,6 +20,7 @@ function foo() { foo(); ?> ---EXPECT-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d try finally diff --git a/Zend/tests/try/try_finally_021.phpt b/Zend/tests/try/try_finally_021.phpt index d25f393be1f0..f624eeb5c6fb 100644 --- a/Zend/tests/try/try_finally_021.phpt +++ b/Zend/tests/try/try_finally_021.phpt @@ -15,6 +15,7 @@ foreach ([0] as $_) { } } ?> ---EXPECT-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d ok ok diff --git a/Zend/tests/try/try_finally_023.phpt b/Zend/tests/try/try_finally_023.phpt index e88eddb3b236..305684e3111b 100644 --- a/Zend/tests/try/try_finally_023.phpt +++ b/Zend/tests/try/try_finally_023.phpt @@ -31,6 +31,7 @@ try { ?> --EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d Exception: 1 in %s:%d Stack trace: #0 %s(%d): test() diff --git a/Zend/tests/try/try_finally_027.phpt b/Zend/tests/try/try_finally_027.phpt index 1e66479eb09b..059a16a977f1 100644 --- a/Zend/tests/try/try_finally_027.phpt +++ b/Zend/tests/try/try_finally_027.phpt @@ -23,6 +23,7 @@ try { ?> --EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d Exception: 1 in %s:%d Stack trace: #0 %s(%d): test() diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index c7ac93f8d34e..f3527330a2c9 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -348,6 +348,7 @@ void zend_oparray_context_begin(zend_oparray_context *prev_context, zend_op_arra CG(context).brk_cont_array = NULL; CG(context).labels = NULL; CG(context).in_jmp_frameless_branch = false; + CG(context).in_finally = false; CG(context).active_property_info_name = NULL; CG(context).active_property_hook_kind = (zend_property_hook_kind)-1; } @@ -6164,6 +6165,10 @@ static void zend_compile_return(const zend_ast *ast) /* {{{ */ } } + if (CG(context).in_finally) { + zend_error(E_DEPRECATED, "Returning from a finally block is deprecated"); + } + if ((CG(active_op_array)->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK) && (expr_node.op_type == IS_CV || (by_ref && expr_node.op_type == IS_VAR)) && zend_has_finally()) { @@ -7410,7 +7415,10 @@ static void zend_compile_try(const zend_ast *ast) /* {{{ */ zend_emit_op(NULL, ZEND_JMP, NULL, NULL); + bool orig_in_finally = CG(context).in_finally; + CG(context).in_finally = true; zend_compile_stmt(finally_ast); + CG(context).in_finally = orig_in_finally; CG(active_op_array)->try_catch_array[try_catch_offset].finally_op = opnum_jmp + 1; CG(active_op_array)->try_catch_array[try_catch_offset].finally_end diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 3d4e6f3c3f9f..34a91183b2a9 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -207,6 +207,7 @@ typedef struct _zend_oparray_context { zend_string *active_property_info_name; zend_property_hook_kind active_property_hook_kind; bool in_jmp_frameless_branch; + bool in_finally; bool has_assigned_to_http_response_header; } zend_oparray_context; diff --git a/ext/date/tests/DatePeriod_createFromISO8601String_static_return.phpt b/ext/date/tests/DatePeriod_createFromISO8601String_static_return.phpt index f8b1e1cffe43..a5ae7e11b29f 100644 --- a/ext/date/tests/DatePeriod_createFromISO8601String_static_return.phpt +++ b/ext/date/tests/DatePeriod_createFromISO8601String_static_return.phpt @@ -10,13 +10,13 @@ var_dump(MyDatePeriod::createFromISO8601String("R4/2012-07-01T00:00:00Z/P7D")); try { MyDatePeriod::createFromISO8601String("R4/2012-07-01T00:/P7D"); } catch (DateMalformedPeriodStringException $e) { - echo $e->getMessage() . "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { MyDatePeriod::createFromISO8601String("R4/2012-07-01T00:00:00Z"); } catch (DateMalformedPeriodStringException $e) { - echo $e->getMessage() . "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> @@ -65,5 +65,5 @@ object(MyDatePeriod)#1 (7) { ["include_end_date"]=> bool(false) } -Unknown or bad format (R4/2012-07-01T00:/P7D) -DatePeriod::createFromISO8601String(): ISO interval must contain an interval, "R4/2012-07-01T00:00:00Z" given +DateMalformedPeriodStringException: Unknown or bad format (R4/2012-07-01T00:/P7D) +DateMalformedPeriodStringException: DatePeriod::createFromISO8601String(): ISO interval must contain an interval, "R4/2012-07-01T00:00:00Z" given diff --git a/ext/date/tests/DatePeriod_wrong_constructor.phpt b/ext/date/tests/DatePeriod_wrong_constructor.phpt index 45f99bdb7270..eaf326f842ef 100644 --- a/ext/date/tests/DatePeriod_wrong_constructor.phpt +++ b/ext/date/tests/DatePeriod_wrong_constructor.phpt @@ -11,8 +11,8 @@ date.timezone=UTC try { new DatePeriod(); } catch (TypeError $exception) { - echo $exception->getMessage() . "\n"; + echo $exception::class, ': ', $exception->getMessage(), "\n"; } ?> --EXPECT-- -DatePeriod::__construct() accepts (DateTimeInterface, DateInterval, int [, int]), or (DateTimeInterface, DateInterval, DateTime [, int]), or (string [, int]) as arguments +TypeError: DatePeriod::__construct() accepts (DateTimeInterface, DateInterval, int [, int]), or (DateTimeInterface, DateInterval, DateTime [, int]), or (string [, int]) as arguments diff --git a/ext/date/tests/DatePeriod_wrong_recurrence_on_constructor.phpt b/ext/date/tests/DatePeriod_wrong_recurrence_on_constructor.phpt index 31c6868d67fb..8e7a57fefe03 100644 --- a/ext/date/tests/DatePeriod_wrong_recurrence_on_constructor.phpt +++ b/ext/date/tests/DatePeriod_wrong_recurrence_on_constructor.phpt @@ -5,16 +5,16 @@ DatePeriod: Test wrong recurrence parameter on __construct try { new DatePeriod(new DateTime('yesterday'), new DateInterval('P1D'), 0); } catch (Exception $exception) { - echo $exception->getMessage(), "\n"; + echo $exception::class, ': ', $exception->getMessage(), "\n"; } try { new DatePeriod(new DateTime('yesterday'), new DateInterval('P1D'), -1); } catch (Exception $exception) { - echo $exception->getMessage(), "\n"; + echo $exception::class, ': ', $exception->getMessage(), "\n"; } ?> --EXPECTF-- -DatePeriod::__construct(): Recurrence count must be greater or equal to 1 and lower than %d -DatePeriod::__construct(): Recurrence count must be greater or equal to 1 and lower than %d +DateMalformedPeriodStringException: DatePeriod::__construct(): Recurrence count must be greater or equal to 1 and lower than %d +DateMalformedPeriodStringException: DatePeriod::__construct(): Recurrence count must be greater or equal to 1 and lower than %d diff --git a/ext/date/tests/bug-gh11416.phpt b/ext/date/tests/bug-gh11416.phpt index 546867924cb4..ab8452d5897f 100644 --- a/ext/date/tests/bug-gh11416.phpt +++ b/ext/date/tests/bug-gh11416.phpt @@ -11,14 +11,14 @@ $date = (new ReflectionClass(DateTime::class))->newInstanceWithoutConstructor(); try { new DatePeriod($date, new DateInterval('P1D'), 2); } catch (Error $e) { - echo get_class($e), ': ', $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } $date = (new ReflectionClass(DateTime::class))->newInstanceWithoutConstructor(); try { new DatePeriod($now, new DateInterval('P1D'), $date); } catch (Error $e) { - echo get_class($e), ': ', $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } $date = (new ReflectionClass(DateTime::class))->newInstanceWithoutConstructor(); @@ -27,25 +27,25 @@ $dateinterval = (new ReflectionClass(DateInterval::class))->newInstanceWithoutCo try { $dateperiod->__unserialize(['start' => $date]); } catch (Error $e) { - echo get_class($e), ': ', $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { $dateperiod->__unserialize(['start' => $now, 'end' => $date]); } catch (Error $e) { - echo get_class($e), ': ', $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { $dateperiod->__unserialize(['start' => $now, 'end' => $now, 'current' => $date]); } catch (Error $e) { - echo get_class($e), ': ', $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { $dateperiod->__unserialize(['start' => $now, 'end' => $now, 'current' => $now, 'interval' => $dateinterval]); } catch (Error $e) { - echo get_class($e), ': ', $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { @@ -55,7 +55,7 @@ try { ]); echo "DatePeriod::__unserialize: SUCCESS\n"; } catch (Error $e) { - echo get_class($e), ': ', $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } echo "OK\n"; ?> diff --git a/ext/date/tests/bug-gh15582.phpt b/ext/date/tests/bug-gh15582.phpt index ab03e190e4bc..2dd6ec59b8f2 100644 --- a/ext/date/tests/bug-gh15582.phpt +++ b/ext/date/tests/bug-gh15582.phpt @@ -14,7 +14,7 @@ $fusion = $mdtz; try { date_create("2005-07-14 22:30:41", $fusion); } catch (Error $e) { - echo get_class($e), ': ', $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECT-- diff --git a/ext/date/tests/bug-gh8471.phpt b/ext/date/tests/bug-gh8471.phpt index 2f6656849f6c..0c1c69418692 100644 --- a/ext/date/tests/bug-gh8471.phpt +++ b/ext/date/tests/bug-gh8471.phpt @@ -8,7 +8,7 @@ $mutable = $reflection->newInstanceWithoutConstructor(); try { $immutable = \DateTimeImmutable::createFromMutable($mutable); } catch (Throwable $t) { - echo $t->getMessage(), "\n"; + echo $t::class, ': ', $t->getMessage(), "\n"; } @@ -18,7 +18,7 @@ $mutable = $reflection->newInstanceWithoutConstructor(); try { $immutable = \DateTimeImmutable::createFromInterface($mutable); } catch (Throwable $t) { - echo $t->getMessage(), "\n"; + echo $t::class, ': ', $t->getMessage(), "\n"; } @@ -28,7 +28,7 @@ $immutable = $reflection->newInstanceWithoutConstructor(); try { $mutable = \DateTime::createFromImmutable($immutable); } catch (Throwable $t) { - echo $t->getMessage(), "\n"; + echo $t::class, ': ', $t->getMessage(), "\n"; } @@ -38,13 +38,13 @@ $immutable = $reflection->newInstanceWithoutConstructor(); try { $mutable = \DateTime::createFromInterface($immutable); } catch (Throwable $t) { - echo $t->getMessage(), "\n"; + echo $t::class, ': ', $t->getMessage(), "\n"; } ?> --EXPECTF-- -Object of type DateTime has not been correctly initialized by calling parent::__construct() in its constructor -Object of type DateTime has not been correctly initialized by calling parent::__construct() in its constructor -Object of type DateTimeImmutable has not been correctly initialized by calling parent::__construct() in its constructor -Object of type DateTimeImmutable has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type DateTime has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type DateTime has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type DateTimeImmutable has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type DateTimeImmutable has not been correctly initialized by calling parent::__construct() in its constructor diff --git a/ext/date/tests/bug51819.phpt b/ext/date/tests/bug51819.phpt index a5f21abf859e..21db1e774542 100644 --- a/ext/date/tests/bug51819.phpt +++ b/ext/date/tests/bug51819.phpt @@ -23,7 +23,7 @@ foreach ($aTz as $sTz) { try { $oDateTime = new DateTime($sDate); } catch (Exception $oException) { - var_dump($oException->getMessage()); + echo $oException::class, ': ', $oException->getMessage(), "\n"; print_r(DateTime::getLastErrors()); } } diff --git a/ext/date/tests/bug54283.phpt b/ext/date/tests/bug54283.phpt index 6acf6e5c8806..c6c303a4d0cc 100644 --- a/ext/date/tests/bug54283.phpt +++ b/ext/date/tests/bug54283.phpt @@ -6,7 +6,7 @@ Bug #54283 (new DatePeriod(NULL) causes crash) try { var_dump(new DatePeriod(NULL)); } catch (Exception $e) { - var_dump($e->getMessage()); + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> @@ -14,4 +14,4 @@ try { Deprecated: DatePeriod::__construct(): Passing null to parameter #1 ($start) of type string is deprecated in %s on line %d Deprecated: Calling DatePeriod::__construct(string $isostr, int $options = 0) is deprecated, use DatePeriod::createFromISO8601String() instead in %s on line %d -string(24) "Unknown or bad format ()" +DateMalformedPeriodStringException: Unknown or bad format () diff --git a/ext/date/tests/bug62500.phpt b/ext/date/tests/bug62500.phpt index e3a133fb63f5..39ea74cf86c9 100644 --- a/ext/date/tests/bug62500.phpt +++ b/ext/date/tests/bug62500.phpt @@ -17,7 +17,7 @@ class Crasher extends DateInterval { try { $c = new Crasher('blah'); } catch (Exception $e) { - var_dump($e->getMessage()); + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECTF-- @@ -26,4 +26,4 @@ int(3) Warning: Undefined property: Crasher::$2 in %s on line %d NULL -string(28) "Unknown or bad format (blah)" +DateMalformedIntervalStringException: Unknown or bad format (blah) diff --git a/ext/date/tests/bug71826.phpt b/ext/date/tests/bug71826.phpt index 1a4d8ff49f7e..42b0cbf346d3 100644 --- a/ext/date/tests/bug71826.phpt +++ b/ext/date/tests/bug71826.phpt @@ -29,4 +29,3 @@ int(28) c(Asia/Tokyo): 2015-4-1 <--> 2015-4-29 int(0) int(28) - diff --git a/ext/date/tests/bug72963.phpt b/ext/date/tests/bug72963.phpt index 0fd01808a844..53327f367003 100644 --- a/ext/date/tests/bug72963.phpt +++ b/ext/date/tests/bug72963.phpt @@ -16,19 +16,19 @@ foreach ($strings as $string) { try { $d1 = DateTime::createFromFormat('!m/d/Y', $string); } catch (ValueError $v) { - echo $v->getMessage(), "\n"; + echo $v::class, ': ', $v->getMessage(), "\n"; } try { $d2 = DateTimeImmutable::createFromFormat('!m/d/Y', $string); } catch (ValueError $v) { - echo $v->getMessage(), "\n"; + echo $v::class, ': ', $v->getMessage(), "\n"; } try { $d3 = date_parse_from_format('m/d/Y', $string); } catch (ValueError $v) { - echo $v->getMessage(), "\n"; + echo $v::class, ': ', $v->getMessage(), "\n"; } var_dump($d1, $d2, $d3); @@ -84,9 +84,9 @@ array(12) { Covering string: 8/8/2016\0asf -DateTime::createFromFormat(): Argument #2 ($datetime) must not contain any null bytes -DateTimeImmutable::createFromFormat(): Argument #2 ($datetime) must not contain any null bytes -date_parse_from_format(): Argument #2 ($datetime) must not contain any null bytes +ValueError: DateTime::createFromFormat(): Argument #2 ($datetime) must not contain any null bytes +ValueError: DateTimeImmutable::createFromFormat(): Argument #2 ($datetime) must not contain any null bytes +ValueError: date_parse_from_format(): Argument #2 ($datetime) must not contain any null bytes NULL NULL NULL diff --git a/ext/date/tests/bug77097.phpt b/ext/date/tests/bug77097.phpt index 080982d68169..c92fc5d01725 100644 --- a/ext/date/tests/bug77097.phpt +++ b/ext/date/tests/bug77097.phpt @@ -30,4 +30,3 @@ float(0.781751) int(0) int(0) float(0.781751) - diff --git a/ext/date/tests/bug78139.phpt b/ext/date/tests/bug78139.phpt index 47e5536cbaad..bd5d07066e5f 100644 --- a/ext/date/tests/bug78139.phpt +++ b/ext/date/tests/bug78139.phpt @@ -70,4 +70,3 @@ Parsing 'UTC xx': Warning: timezone_open(): Unknown or bad timezone (UTC xx) in %sbug78139.php on line %d bool(false) DateInvalidTimeZoneException: DateTimeZone::__construct(): Unknown or bad timezone (UTC xx) - diff --git a/ext/date/tests/createFromTimestamp.phpt b/ext/date/tests/createFromTimestamp.phpt index f31aeae11854..cf6c753110b8 100644 --- a/ext/date/tests/createFromTimestamp.phpt +++ b/ext/date/tests/createFromTimestamp.phpt @@ -32,14 +32,14 @@ foreach ($timestamps as $ts) { try { var_dump(DateTime::createFromTimestamp($ts)); } catch (Throwable $e) { - echo get_class($e) . ': ' . $e->getMessage() . "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } echo 'DateTimeImmutable::createFromTimestamp(' . var_export($ts, true) . '): '; try { var_dump(DateTimeImmutable::createFromTimestamp($ts)); } catch (Throwable $e) { - echo get_class($e) . ': ' . $e->getMessage() . "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } } @@ -47,14 +47,14 @@ echo 'MyDateTime::createFromTimestamp(' . var_export(0, true) . '): '; try { var_dump(MyDateTime::createFromTimestamp(0)); } catch (Throwable $e) { - echo get_class($e) . ': ' . $e->getMessage() . "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } echo 'MyDateTimeImmutable::createFromTimestamp(' . var_export(0, true) . '): '; try { var_dump(MyDateTimeImmutable::createFromTimestamp(0)); } catch (Throwable $e) { - echo get_class($e) . ': ' . $e->getMessage() . "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> diff --git a/ext/date/tests/date_interval_set_state_error1.phpt b/ext/date/tests/date_interval_set_state_error1.phpt index ee68de8db466..4bb71320997f 100644 --- a/ext/date/tests/date_interval_set_state_error1.phpt +++ b/ext/date/tests/date_interval_set_state_error1.phpt @@ -14,7 +14,7 @@ try { ] ); } catch (Error $e) { - echo $e->getMessage() . "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } var_dump($interval); @@ -43,7 +43,7 @@ object(DateInterval)#%d (%d) { ["from_string"]=> bool(false) } -Unknown or bad format (wrong) at position 0 (w) while unserializing: The timezone could not be found in the database +Error: Unknown or bad format (wrong) at position 0 (w) while unserializing: The timezone could not be found in the database object(DateInterval)#%d (%d) { ["y"]=> int(1) diff --git a/ext/date/tests/date_period_exclude_start_and_include_end.phpt b/ext/date/tests/date_period_exclude_start_and_include_end.phpt index 6238f6707351..bcfd89eb5c18 100644 --- a/ext/date/tests/date_period_exclude_start_and_include_end.phpt +++ b/ext/date/tests/date_period_exclude_start_and_include_end.phpt @@ -16,4 +16,3 @@ foreach ($dp as $day) { 2010-06-08 2010-06-09 2010-06-10 - diff --git a/ext/date/tests/date_period_unset_property.phpt b/ext/date/tests/date_period_unset_property.phpt index 7948d61d268d..ced092c768bc 100644 --- a/ext/date/tests/date_period_unset_property.phpt +++ b/ext/date/tests/date_period_unset_property.phpt @@ -14,58 +14,58 @@ unset($period->prop); try { $period->prop; } catch (Error $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { unset($period->start); } catch (Error $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { unset($period->current); } catch (Error $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { unset($period->end); } catch (Error $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { unset($period->interval); } catch (Error $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { unset($period->recurrences); } catch (Error $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { unset($period->include_start_date); } catch (Error $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { unset($period->include_end_date); } catch (Error $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECT-- -Typed property MyDatePeriod::$prop must not be accessed before initialization -Cannot unset MyDatePeriod::$start -Cannot unset MyDatePeriod::$current -Cannot unset MyDatePeriod::$end -Cannot unset MyDatePeriod::$interval -Cannot unset MyDatePeriod::$recurrences -Cannot unset MyDatePeriod::$include_start_date -Cannot unset MyDatePeriod::$include_end_date +Error: Typed property MyDatePeriod::$prop must not be accessed before initialization +Error: Cannot unset MyDatePeriod::$start +Error: Cannot unset MyDatePeriod::$current +Error: Cannot unset MyDatePeriod::$end +Error: Cannot unset MyDatePeriod::$interval +Error: Cannot unset MyDatePeriod::$recurrences +Error: Cannot unset MyDatePeriod::$include_start_date +Error: Cannot unset MyDatePeriod::$include_end_date diff --git a/ext/date/tests/date_sunrise_and_sunset_error.phpt b/ext/date/tests/date_sunrise_and_sunset_error.phpt index 01212992d8fb..0e756f505497 100644 --- a/ext/date/tests/date_sunrise_and_sunset_error.phpt +++ b/ext/date/tests/date_sunrise_and_sunset_error.phpt @@ -6,19 +6,19 @@ Test error condition of date_sunrise() and date_sunset() try { date_sunrise(time(), 3); } catch (ValueError $exception) { - echo $exception->getMessage() . "\n"; + echo $exception::class, ': ', $exception->getMessage(), "\n"; } try { date_sunset(time(), 4); } catch (ValueError $exception) { - echo $exception->getMessage() . "\n"; + echo $exception::class, ': ', $exception->getMessage(), "\n"; } ?> --EXPECTF-- Deprecated: Function date_sunrise() is deprecated since 8.1, use date_sun_info() instead in %s on line %d -date_sunrise(): Argument #2 ($returnFormat) must be one of SUNFUNCS_RET_TIMESTAMP, SUNFUNCS_RET_STRING, or SUNFUNCS_RET_DOUBLE +ValueError: date_sunrise(): Argument #2 ($returnFormat) must be one of SUNFUNCS_RET_TIMESTAMP, SUNFUNCS_RET_STRING, or SUNFUNCS_RET_DOUBLE Deprecated: Function date_sunset() is deprecated since 8.1, use date_sun_info() instead in %s on line %d -date_sunset(): Argument #2 ($returnFormat) must be one of SUNFUNCS_RET_TIMESTAMP, SUNFUNCS_RET_STRING, or SUNFUNCS_RET_DOUBLE +ValueError: date_sunset(): Argument #2 ($returnFormat) must be one of SUNFUNCS_RET_TIMESTAMP, SUNFUNCS_RET_STRING, or SUNFUNCS_RET_DOUBLE diff --git a/ext/date/tests/getSetMicroseconds.phpt b/ext/date/tests/getSetMicroseconds.phpt index debb5459633a..8f4aa864756c 100644 --- a/ext/date/tests/getSetMicroseconds.phpt +++ b/ext/date/tests/getSetMicroseconds.phpt @@ -37,7 +37,7 @@ foreach ($microsecondList as $microsecond) { try { var_dump($dt->setMicrosecond($microsecond)); } catch (Throwable $e) { - echo get_class($e) . ': ' . $e->getMessage() . "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } echo 'DateTime::getMicrosecond(): ' . var_export($dt->getMicrosecond(), true) . "\n"; @@ -45,7 +45,7 @@ foreach ($microsecondList as $microsecond) { try { var_dump($dti->setMicrosecond($microsecond)); } catch (Throwable $e) { - echo get_class($e) . ': ' . $e->getMessage() . "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } echo 'DateTimeImmutable::getMicrosecond(): ' . var_export($dti->getMicrosecond(), true) . "\n"; @@ -53,7 +53,7 @@ foreach ($microsecondList as $microsecond) { try { var_dump($myDt->setMicrosecond($microsecond)); } catch (Throwable $e) { - echo get_class($e) . ': ' . $e->getMessage() . "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } echo 'MyDateTime::getMicrosecond(): ' . var_export($myDt->getMicrosecond(), true) . "\n"; @@ -61,7 +61,7 @@ foreach ($microsecondList as $microsecond) { try { var_dump($myDti->setMicrosecond($microsecond)); } catch (Throwable $e) { - echo get_class($e) . ': ' . $e->getMessage() . "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } echo 'MyDateTimeImmutable::getMicrosecond(): ' . var_export($myDti->getMicrosecond(), true) . "\n"; } diff --git a/ext/date/tests/gh14732.phpt b/ext/date/tests/gh14732.phpt index 19b5f3b481f4..39f3116379e9 100644 --- a/ext/date/tests/gh14732.phpt +++ b/ext/date/tests/gh14732.phpt @@ -5,31 +5,31 @@ GH-14732 (date_sun_info() fails for non-finite values) try { date_sun_info(1, NAN, 1); } catch (ValueError $ex) { - echo $ex->getMessage(), "\n"; + echo $ex::class, ': ', $ex->getMessage(), "\n"; } try { date_sun_info(1, -INF, 1); } catch (ValueError $ex) { - echo $ex->getMessage(), "\n"; + echo $ex::class, ': ', $ex->getMessage(), "\n"; } try { date_sun_info(1, 1, NAN); } catch (ValueError $ex) { - echo $ex->getMessage(), "\n"; + echo $ex::class, ': ', $ex->getMessage(), "\n"; } try { date_sun_info(1, 1, INF); } catch (ValueError $ex) { - echo $ex->getMessage(), "\n"; + echo $ex::class, ': ', $ex->getMessage(), "\n"; } var_dump(date_sunset(1, SUNFUNCS_RET_STRING, NAN, 1)); var_dump(date_sunrise(1, SUNFUNCS_RET_STRING, 1, NAN)); ?> --EXPECTF-- -date_sun_info(): Argument #2 ($latitude) must be finite -date_sun_info(): Argument #2 ($latitude) must be finite -date_sun_info(): Argument #3 ($longitude) must be finite -date_sun_info(): Argument #3 ($longitude) must be finite +ValueError: date_sun_info(): Argument #2 ($latitude) must be finite +ValueError: date_sun_info(): Argument #2 ($latitude) must be finite +ValueError: date_sun_info(): Argument #3 ($longitude) must be finite +ValueError: date_sun_info(): Argument #3 ($longitude) must be finite Deprecated: Constant SUNFUNCS_RET_STRING is deprecated since 8.4, as date_sunrise() and date_sunset() were deprecated in 8.1 in %s on line %d diff --git a/ext/date/tests/gh20936.phpt b/ext/date/tests/gh20936.phpt index e6a525dd4583..10ad79a9d25d 100644 --- a/ext/date/tests/gh20936.phpt +++ b/ext/date/tests/gh20936.phpt @@ -7,7 +7,7 @@ $interval = new DateInterval('P2D'); try { DatePeriod::__set_state(['start' => null, 'end' => $end, 'current' => null, 'interval' => $interval, 'recurrences' => 2, 'include_start_date' => false, 'include_end_date' => true]); } catch (Throwable $e) { - echo $e::class, ": ", $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECT-- diff --git a/ext/date/tests/instantiate_uninstantiable_classes.phpt b/ext/date/tests/instantiate_uninstantiable_classes.phpt index 634ed635b2d2..b14be57ec404 100644 --- a/ext/date/tests/instantiate_uninstantiable_classes.phpt +++ b/ext/date/tests/instantiate_uninstantiable_classes.phpt @@ -18,65 +18,65 @@ abstract class MyDateTimeImmutable extends DateTimeImmutable { try { MyDatePeriod::createFromISO8601String('R5'); } catch (Error $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { MyDateTime::createFromFormat('Y-m-d', '2025-01-01'); } catch (Error $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { MyDateTime::createFromImmutable(new DateTimeImmutable()); } catch (Error $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { MyDateTime::createFromInterface(new DateTimeImmutable()); } catch (Error $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { MyDateTime::createFromTimestamp(0); } catch (Error $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { MyDateTimeImmutable::createFromFormat('Y-m-d', '2025-01-01'); } catch (Error $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { MyDateTimeImmutable::createFromMutable(new DateTime()); } catch (Error $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { MyDateTimeImmutable::createFromInterface(new DateTime()); } catch (Error $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { MyDateTimeImmutable::createFromTimestamp(0); } catch (Error $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECT-- -Cannot instantiate abstract class MyDatePeriod -Cannot instantiate abstract class MyDateTime -Cannot instantiate abstract class MyDateTime -Cannot instantiate abstract class MyDateTime -Cannot instantiate abstract class MyDateTime -Cannot instantiate abstract class MyDateTimeImmutable -Cannot instantiate abstract class MyDateTimeImmutable -Cannot instantiate abstract class MyDateTimeImmutable -Cannot instantiate abstract class MyDateTimeImmutable +Error: Cannot instantiate abstract class MyDatePeriod +Error: Cannot instantiate abstract class MyDateTime +Error: Cannot instantiate abstract class MyDateTime +Error: Cannot instantiate abstract class MyDateTime +Error: Cannot instantiate abstract class MyDateTime +Error: Cannot instantiate abstract class MyDateTimeImmutable +Error: Cannot instantiate abstract class MyDateTimeImmutable +Error: Cannot instantiate abstract class MyDateTimeImmutable +Error: Cannot instantiate abstract class MyDateTimeImmutable diff --git a/ext/date/tests/timezone_offset_get_error.phpt b/ext/date/tests/timezone_offset_get_error.phpt index 4b5cda104ef6..efa5f353ba38 100644 --- a/ext/date/tests/timezone_offset_get_error.phpt +++ b/ext/date/tests/timezone_offset_get_error.phpt @@ -14,22 +14,19 @@ $invalid_obj = new stdClass(); try { var_dump( timezone_offset_get($invalid_obj, $date) ); } catch (Error $ex) { - var_dump($ex->getMessage()); - echo "\n"; + echo $ex::class, ': ', $ex->getMessage(), "\n"; } $invalid_obj = 10; try { var_dump( timezone_offset_get($invalid_obj, $date) ); } catch (Error $ex) { - var_dump($ex->getMessage()); - echo "\n"; + echo $ex::class, ': ', $ex->getMessage(), "\n"; } $invalid_obj = null; try { var_dump( timezone_offset_get($invalid_obj, $date) ); } catch (Error $ex) { - var_dump($ex->getMessage()); - echo "\n"; + echo $ex::class, ': ', $ex->getMessage(), "\n"; } echo "\n-- Testing timezone_offset_get() function with an invalid values for \$datetime argument --\n"; @@ -37,38 +34,30 @@ $invalid_obj = new stdClass(); try { var_dump( timezone_offset_get($tz, $invalid_obj) ); } catch (Error $ex) { - var_dump($ex->getMessage()); - echo "\n"; + echo $ex::class, ': ', $ex->getMessage(), "\n"; } $invalid_obj = 10; try { var_dump( timezone_offset_get($tz, $invalid_obj) ); } catch (Error $ex) { - var_dump($ex->getMessage()); - echo "\n"; + echo $ex::class, ': ', $ex->getMessage(), "\n"; } $invalid_obj = null; try { var_dump( timezone_offset_get($tz, $invalid_obj) ); } catch (Error $ex) { - var_dump($ex->getMessage()); - echo "\n"; + echo $ex::class, ': ', $ex->getMessage(), "\n"; } ?> --EXPECT-- *** Testing timezone_offset_get() : error conditions *** -- Testing timezone_offset_get() function with an invalid values for $object argument -- -string(89) "timezone_offset_get(): Argument #1 ($object) must be of type DateTimeZone, stdClass given" - -string(84) "timezone_offset_get(): Argument #1 ($object) must be of type DateTimeZone, int given" - -string(85) "timezone_offset_get(): Argument #1 ($object) must be of type DateTimeZone, null given" - +TypeError: timezone_offset_get(): Argument #1 ($object) must be of type DateTimeZone, stdClass given +TypeError: timezone_offset_get(): Argument #1 ($object) must be of type DateTimeZone, int given +TypeError: timezone_offset_get(): Argument #1 ($object) must be of type DateTimeZone, null given -- Testing timezone_offset_get() function with an invalid values for $datetime argument -- -string(96) "timezone_offset_get(): Argument #2 ($datetime) must be of type DateTimeInterface, stdClass given" - -string(91) "timezone_offset_get(): Argument #2 ($datetime) must be of type DateTimeInterface, int given" - -string(92) "timezone_offset_get(): Argument #2 ($datetime) must be of type DateTimeInterface, null given" +TypeError: timezone_offset_get(): Argument #2 ($datetime) must be of type DateTimeInterface, stdClass given +TypeError: timezone_offset_get(): Argument #2 ($datetime) must be of type DateTimeInterface, int given +TypeError: timezone_offset_get(): Argument #2 ($datetime) must be of type DateTimeInterface, null given diff --git a/ext/date/tests/unserialize-test.phpt b/ext/date/tests/unserialize-test.phpt index aaff75db6b77..bf3bd117c0cc 100644 --- a/ext/date/tests/unserialize-test.phpt +++ b/ext/date/tests/unserialize-test.phpt @@ -17,7 +17,7 @@ foreach ($files as $file) { try { $x = unserialize(substr($s, strpos($s, "|") + 1)); } catch (Error $e) { - echo get_class($e), ': ', $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } var_dump($x); echo "\n\n"; diff --git a/ext/dom/element.c b/ext/dom/element.c index 2a0aa3a4d0e7..354466623ca4 100644 --- a/ext/dom/element.c +++ b/ext/dom/element.c @@ -1057,6 +1057,10 @@ static void dom_set_attribute_ns_modern(dom_object *intern, xmlNodePtr elemp, ze if (errorcode == 0) { php_dom_libxml_ns_mapper *ns_mapper = php_dom_get_ns_mapper(intern); xmlNsPtr ns = php_dom_libxml_ns_mapper_get_ns_raw_prefix_string(ns_mapper, prefix, xmlStrlen(prefix), uri); + xmlNodePtr existing = (xmlNodePtr) xmlHasNsProp(elemp, localname, ns == NULL ? NULL : ns->href); + if (existing != NULL && existing->type != XML_ATTRIBUTE_DECL) { + node_list_unlink(existing->children); + } xmlAttrPtr attr = xmlSetNsProp(elemp, ns, localname, BAD_CAST value); if (UNEXPECTED(attr == NULL)) { php_dom_throw_error(INVALID_STATE_ERR, /* strict */ true); diff --git a/ext/dom/php_dom.c b/ext/dom/php_dom.c index 158534530c3e..ebbe4a2bf441 100644 --- a/ext/dom/php_dom.c +++ b/ext/dom/php_dom.c @@ -1447,14 +1447,13 @@ void node_list_unlink(xmlNodePtr node) dom_object *wrapper; while (node != NULL) { + xmlNodePtr next = node->next; wrapper = php_dom_object_get_data(node); if (wrapper != NULL ) { xmlUnlinkNode(node); - } else { - if (node->type == XML_ENTITY_REF_NODE) - break; + } else if (node->type != XML_ENTITY_REF_NODE) { node_list_unlink(node->children); switch (node->type) { @@ -1471,7 +1470,7 @@ void node_list_unlink(xmlNodePtr node) } - node = node->next; + node = next; } } /* }}} end node_list_unlink */ diff --git a/ext/dom/tests/gh23331.phpt b/ext/dom/tests/gh23331.phpt new file mode 100644 index 000000000000..8c193b845115 --- /dev/null +++ b/ext/dom/tests/gh23331.phpt @@ -0,0 +1,37 @@ +--TEST-- +GH-23331 (Use-after-free when an attribute child past an entity reference keeps a live wrapper) +--EXTENSIONS-- +dom +--FILE-- +loadXML(']>'); +$attr = $doc->documentElement->getAttributeNode('attr'); +$first = $attr->firstChild; +$entity = $attr->childNodes[1]; +$last = $attr->lastChild; + +$doc->documentElement->setAttribute('attr', 'updated'); + +echo "text before the entity reference: "; +var_dump($first->textContent); +echo "entity reference name: "; +var_dump($entity->nodeName); +echo "entity reference detached: "; +var_dump($entity->parentNode === null); +echo "text after the entity reference: "; +var_dump($last->textContent); +echo "detached from the attribute: "; +var_dump($last->parentNode === null); +echo "new attribute value: "; +var_dump($doc->documentElement->getAttribute('attr')); + +?> +--EXPECT-- +text before the entity reference: string(1) "a" +entity reference name: string(1) "e" +entity reference detached: bool(true) +text after the entity reference: string(1) "b" +detached from the attribute: bool(true) +new attribute value: string(7) "updated" diff --git a/ext/dom/tests/gh23331_2.phpt b/ext/dom/tests/gh23331_2.phpt new file mode 100644 index 000000000000..1e0bb92e8113 --- /dev/null +++ b/ext/dom/tests/gh23331_2.phpt @@ -0,0 +1,34 @@ +--TEST-- +GH-23331 (Use-after-free when an attribute child past an entity reference keeps a live wrapper) - setAttributeNS() and removeAttribute() +--EXTENSIONS-- +dom +--FILE-- +loadXML(']>'); +$attr = $doc->documentElement->getAttributeNodeNS('urn:x', 'attr'); +$last = $attr->lastChild; +$doc->documentElement->setAttributeNS('urn:x', 'p:attr', 'updated'); +echo "setAttributeNS, detached: "; +var_dump($last->parentNode === null); +echo "setAttributeNS, text: "; +var_dump($last->textContent); + +$doc = new DOMDocument(); +$doc->loadXML(']>'); +$attr = $doc->documentElement->getAttributeNode('attr'); +$last = $attr->lastChild; +unset($attr); +$doc->documentElement->removeAttribute('attr'); +echo "removeAttribute, no wrapper on the attribute, detached: "; +var_dump($last->parentNode === null); +echo "removeAttribute, no wrapper on the attribute, text: "; +var_dump($last->textContent); + +?> +--EXPECT-- +setAttributeNS, detached: bool(true) +setAttributeNS, text: string(1) "b" +removeAttribute, no wrapper on the attribute, detached: bool(true) +removeAttribute, no wrapper on the attribute, text: string(1) "b" diff --git a/ext/dom/tests/gh23331_3.phpt b/ext/dom/tests/gh23331_3.phpt new file mode 100644 index 000000000000..42125615ae12 --- /dev/null +++ b/ext/dom/tests/gh23331_3.phpt @@ -0,0 +1,41 @@ +--TEST-- +GH-23331 (Use-after-free when an attribute child past an entity reference keeps a live wrapper) - Dom\XMLDocument +--EXTENSIONS-- +dom +--FILE-- +]>'; + +$doc = Dom\XMLDocument::createFromString($xml); +$el = $doc->documentElement; +$attr = $el->getAttributeNode('attr'); +$first = $attr->firstChild; +$last = $attr->lastChild; +unset($attr); +$el->removeAttribute('attr'); +echo "removeAttribute, first: "; +var_dump($first->textContent); +echo "removeAttribute, detached: "; +var_dump($last->parentNode === null); +echo "removeAttribute, text: "; +var_dump($last->textContent); + +$doc = Dom\XMLDocument::createFromString($xml); +$el = $doc->documentElement; +$attr = $el->getAttributeNodeNS('urn:x', 'nsattr'); +$last = $attr->lastChild; +unset($attr); +$el->removeAttributeNS('urn:x', 'nsattr'); +echo "removeAttributeNS, detached: "; +var_dump($last->parentNode === null); +echo "removeAttributeNS, text: "; +var_dump($last->textContent); + +?> +--EXPECT-- +removeAttribute, first: string(1) "a" +removeAttribute, detached: bool(true) +removeAttribute, text: string(1) "b" +removeAttributeNS, detached: bool(true) +removeAttributeNS, text: string(1) "d" diff --git a/ext/dom/tests/modern/common/Element_setAttributeNS_live_child.phpt b/ext/dom/tests/modern/common/Element_setAttributeNS_live_child.phpt new file mode 100644 index 000000000000..22475c33cf88 --- /dev/null +++ b/ext/dom/tests/modern/common/Element_setAttributeNS_live_child.phpt @@ -0,0 +1,37 @@ +--TEST-- +setAttributeNS() keeps an attribute child that still has a live wrapper +--EXTENSIONS-- +dom +--FILE-- +'); +$el = $doc->documentElement; +$text = $el->getAttributeNodeNS('urn:x', 'attr')->firstChild; +$el->setAttributeNS('urn:x', 'p:attr', 'new'); +echo "prefixed, detached: "; +var_dump($text->parentNode === null); +echo "prefixed, text: "; +var_dump($text->textContent); +echo "prefixed, new value: "; +var_dump($el->getAttributeNS('urn:x', 'attr')); + +$doc = Dom\XMLDocument::createFromString(''); +$el = $doc->documentElement; +$text = $el->getAttributeNode('attr')->firstChild; +$el->setAttributeNS(null, 'attr', 'new'); +echo "no namespace, detached: "; +var_dump($text->parentNode === null); +echo "no namespace, text: "; +var_dump($text->textContent); +echo "no namespace, new value: "; +var_dump($el->getAttribute('attr')); + +?> +--EXPECT-- +prefixed, detached: bool(true) +prefixed, text: string(3) "old" +prefixed, new value: string(3) "new" +no namespace, detached: bool(true) +no namespace, text: string(3) "old" +no namespace, new value: string(3) "new" diff --git a/ext/intl/grapheme/grapheme_string.cpp b/ext/intl/grapheme/grapheme_string.cpp index a1daae84db9c..e2a6280bcaa6 100644 --- a/ext/intl/grapheme/grapheme_string.cpp +++ b/ext/intl/grapheme/grapheme_string.cpp @@ -908,9 +908,9 @@ U_CFUNC PHP_FUNCTION(grapheme_str_split) add_next_index_stringl(return_value, pstr, pos - current); end = pstr + pos - current; i = 0; + pstr += pos - current; + current = pos; } - pstr += pos - current; - current = pos; } else { i += 1; } diff --git a/ext/intl/locale/locale_methods.cpp b/ext/intl/locale/locale_methods.cpp index bb4cd1236497..8cc7e5a800b5 100644 --- a/ext/intl/locale/locale_methods.cpp +++ b/ext/intl/locale/locale_methods.cpp @@ -291,7 +291,7 @@ static zend_off_t getSingletonPos(const char* str) break; } else { /* delimiter found; check for singleton */ - if( isIDSeparator(*(str+i+2)) ){ + if( (size_t)i + 2 < len && isIDSeparator(*(str+i+2)) ){ /* a singleton; so send the position of separator before singleton */ result = i+1; break; diff --git a/ext/intl/tests/locale_parse_trailing_separator.phpt b/ext/intl/tests/locale_parse_trailing_separator.phpt new file mode 100644 index 000000000000..96b2139b72c3 --- /dev/null +++ b/ext/intl/tests/locale_parse_trailing_separator.phpt @@ -0,0 +1,45 @@ +--TEST-- +Locale::parseLocale() does not read past a trailing '-' or '_' +--EXTENSIONS-- +intl +--FILE-- + +--EXPECT-- +en-: array ( + 'language' => 'en', +) +foo-: array ( + 'language' => 'foo', +) +en_US-: array ( + 'language' => 'en', + 'region' => 'US', +) +en_: array ( + 'language' => 'en', +) +de-CH-x-: array ( + 'language' => 'de', + 'region' => 'CH', +) diff --git a/ext/session/session.c b/ext/session/session.c index a6e698d4c0aa..6a9f2b355c12 100644 --- a/ext/session/session.c +++ b/ext/session/session.c @@ -531,7 +531,10 @@ static void php_session_save_current_state(bool write) && zend_string_equals(val, PS(session_vars)) ) { ret = PS(mod)->s_update_timestamp(&PS(mod_data), PS(id), val, PS(gc_maxlifetime)); - handler_function = &PS(mod_user_names).ps_update_timestamp; + /* The user handler falls back to the write handler if no update timestamp handler is set */ + if (!Z_ISUNDEF(PS(mod_user_names).ps_update_timestamp)) { + handler_function = &PS(mod_user_names).ps_update_timestamp; + } } else { ret = PS(mod)->s_write(&PS(mod_data), PS(id), val, PS(gc_maxlifetime)); } @@ -2935,13 +2938,27 @@ static PHP_GINIT_FUNCTION(ps) ps_globals->random_seeded = false; } +/* Interfaces extending the given one are not flattened into ce->interfaces before they are + * themselves processed, so every entry has to be checked with instanceof. */ +static bool session_interfaces_include(const zend_class_entry *ce, const zend_class_entry *iface) +{ + for (uint32_t i = 0; i < ce->num_interfaces; i++) { + if (instanceof_function(ce->interfaces[i], iface)) { + return true; + } + } + return false; +} + static int session_handler_interface_gets_implemented(zend_class_entry *self, zend_class_entry *class) { - if (!zend_hash_str_exists(&class->function_table, ZEND_STRL("create_sid"))) { + if (!zend_hash_str_exists(&class->function_table, ZEND_STRL("create_sid")) + && !session_interfaces_include(class, php_session_id_iface_entry)) { zend_error(E_WARNING, "Class %s implementing SessionHandlerInterface is missing the create_sid() method which will be required in PHP 9.0", ZSTR_VAL(class->name)); } - if (!zend_hash_str_exists(&class->function_table, ZEND_STRL("validateid"))) { + if (!zend_hash_str_exists(&class->function_table, ZEND_STRL("validateid")) + && !session_interfaces_include(class, php_session_update_timestamp_iface_entry)) { zend_error(E_WARNING, "Class %s implementing SessionHandlerInterface is missing the validateId() method which will be required in PHP 9.0", ZSTR_VAL(class->name)); diff --git a/ext/session/tests/user_session_module/gh23043.phpt b/ext/session/tests/user_session_module/gh23043.phpt index dc3676993903..e3528884a79a 100644 --- a/ext/session/tests/user_session_module/gh23043.phpt +++ b/ext/session/tests/user_session_module/gh23043.phpt @@ -27,9 +27,9 @@ string(0) "" Warning: SessionHandler::write(): Session ID is too long or contains illegal characters. Only the A-Z, a-z, 0-9, "-", and "," characters are allowed in %s on line %d -Warning: session_write_close(): Failed to write session data using user defined save handler. (session.save_path: , handler: ) in %s on line %d +Warning: session_write_close(): Failed to write session data using user defined save handler. (session.save_path: , handler: a::write) in %s on line %d string(0) "" Warning: SessionHandler::write(): Session ID is too long or contains illegal characters. Only the A-Z, a-z, 0-9, "-", and "," characters are allowed in Unknown on line 0 -Warning: session_write_close(): Failed to write session data using user defined save handler. (session.save_path: , handler: ) in Unknown on line 0 +Warning: session_write_close(): Failed to write session data using user defined save handler. (session.save_path: , handler: a::write) in Unknown on line 0 diff --git a/ext/session/tests/user_session_module/gh23328.phpt b/ext/session/tests/user_session_module/gh23328.phpt new file mode 100644 index 000000000000..c23ccb1de389 --- /dev/null +++ b/ext/session/tests/user_session_module/gh23328.phpt @@ -0,0 +1,32 @@ +--TEST-- +GH-23328: SessionHandlerInterface create_sid()/validateId() warning depends on interface order +--EXTENSIONS-- +session +--FILE-- + +--EXPECTF-- +Warning: Class MissingBoth implementing SessionHandlerInterface is missing the create_sid() method which will be required in PHP 9.0 in %s on line %d + +Warning: Class MissingBoth implementing SessionHandlerInterface is missing the validateId() method which will be required in PHP 9.0 in %s on line %d + +Warning: Class MissingValidateId implementing SessionHandlerInterface is missing the validateId() method which will be required in PHP 9.0 in %s on line %d + +Warning: Class MissingCreateSid implementing SessionHandlerInterface is missing the create_sid() method which will be required in PHP 9.0 in %s on line %d +Done diff --git a/ext/snmp/tests/bug64124.phpt b/ext/snmp/tests/bug64124.phpt index 5e2c43dc6ada..e2b70f42d24d 100644 --- a/ext/snmp/tests/bug64124.phpt +++ b/ext/snmp/tests/bug64124.phpt @@ -12,9 +12,8 @@ $packed = str_repeat(chr(0), 15) . chr(1); if (@inet_ntop($packed) === false) { die("skip no IPv6 support"); } +if (PHP_OS_FAMILY === 'Windows') die('xfail SNMP tests might possibly fail on Windows'); ?> ---XFAIL-- -SNMP tests might possibly fail on Windows --FILE-- --ENV-- MIBS=noneXistent ---XFAIL-- -SNMP tests might possibly fail on Windows --FILE-- ---XFAIL-- -SNMP tests might possibly fail on Windows --FILE-- ---XFAIL-- -SNMP tests might possibly fail on Windows --FILE-- ---XFAIL-- -SNMP tests might possibly fail on Windows --FILE-- ---XFAIL-- -SNMP tests might possibly fail on Windows --FILE-- ---XFAIL-- -SNMP tests might possibly fail on Windows --FILE-- ---XFAIL-- -SNMP tests might possibly fail on Windows --FILE-- ---XFAIL-- -SNMP tests might possibly fail on Windows --FILE-- --ENV-- MIBS= ---XFAIL-- -SNMP tests might possibly fail on Windows --FILE-- ---XFAIL-- -SNMP tests might possibly fail on Windows --FILE-- ---XFAIL-- -SNMP tests might possibly fail on Windows --FILE-- ---XFAIL-- -SNMP tests might possibly fail on Windows --FILE-- ---XFAIL-- -SNMP tests might possibly fail on Windows --FILE-- ---XFAIL-- -SNMP tests might possibly fail on Windows --FILE-- ---XFAIL-- -SNMP tests might possibly fail on Windows --FILE-- ---XFAIL-- -SNMP tests might possibly fail on Windows --FILE-- ---XFAIL-- -SNMP tests might possibly fail on Windows --FILE-- --ENV-- MIBS= ---XFAIL-- -SNMP tests might possibly fail on Windows --FILE-- ---XFAIL-- -SNMP tests might possibly fail on Windows --FILE-- ---XFAIL-- -SNMP tests might possibly fail on Windows --FILE-- handle first [Uncaught Error in %s on line 16: Call to undefined function foo()] @@ -22,6 +23,8 @@ Stack trace: #0 %s(22): {closure:%s:%d}() #1 {main} [Script ended normally] + +Deprecated: Returning from a finally block is deprecated in %s on line %d prompt> --FILE-- handle first [Uncaught Error in %s on line 16: Call to undefined function foo()] @@ -26,6 +27,8 @@ Stack trace: #0 %s(20): {closure:%s:%d}() #1 {main} [Script ended normally] + +Deprecated: Returning from a finally block is deprecated in %s on line %d prompt> [The stack contains nothing !] prompt> --FILE--