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--