Commit ec562d07d29 for php.net
commit ec562d07d29c57889aed178cbe78c0188ed49553
Author: Gina Peter Banyard <girgias@php.net>
Date: Thu Jul 30 11:30:29 2026 +0100
serializer: more unserialize_callback_func INI tests with different types of string callables
diff --git a/ext/standard/tests/serialize/unserialize_callback_func/deprecated_partially_supported_callable.phpt b/ext/standard/tests/serialize/unserialize_callback_func/deprecated_partially_supported_callable.phpt
new file mode 100644
index 00000000000..a7806581abe
--- /dev/null
+++ b/ext/standard/tests/serialize/unserialize_callback_func/deprecated_partially_supported_callable.phpt
@@ -0,0 +1,51 @@
+--TEST--
+unserialize_callback_func with partially deprecated callable string
+--INI--
+unserialize_callback_func=parent::my_unserialize
+--FILE--
+<?php
+
+class TesterParent {
+ public static function my_unserialize($name) {
+ echo 'callback_called in ', __CLASS__ , PHP_EOL;
+ eval('class Foo {}');
+ }
+}
+
+class TesterChild extends TesterParent {
+ public static function my_unserialize($name) {
+ echo 'callback_called in ', __CLASS__ , PHP_EOL;
+ eval('class Foo {}');
+ }
+
+ public function unserialize(string $str) {
+ return unserialize($str);
+ }
+}
+
+$s = 'O:3:"FOO":0:{}';
+try {
+ $o = unserialize($s);
+ var_dump($o);
+} catch (Throwable $e) {
+ echo $e::class, ': ', $e->getMessage(), PHP_EOL;
+}
+
+try {
+ $tester = new TesterChild();
+ $o = $tester->unserialize($s);
+ var_dump($o);
+} catch (Throwable $e) {
+ echo $e::class, ': ', $e->getMessage(), PHP_EOL;
+}
+echo "Done";
+
+?>
+--EXPECTF--
+Error: Invalid callback parent::my_unserialize, cannot access "parent" when no class scope is active
+
+Deprecated: Use of "parent" in callables is deprecated in %s on line %d
+callback_called in TesterParent
+object(Foo)#3 (0) {
+}
+Done
diff --git a/ext/standard/tests/serialize/unserialize_callback_func/fn_with_fqn.phpt b/ext/standard/tests/serialize/unserialize_callback_func/fn_with_fqn.phpt
new file mode 100644
index 00000000000..67ce94c00da
--- /dev/null
+++ b/ext/standard/tests/serialize/unserialize_callback_func/fn_with_fqn.phpt
@@ -0,0 +1,22 @@
+--TEST--
+unserialize_callback_func with fully qualified name function
+--INI--
+unserialize_callback_func=\my_global_fn
+--FILE--
+<?php
+function my_global_fn($name) {
+ echo "callback_called\n";
+ eval('class Foo {}');
+}
+
+$o = unserialize('O:3:"FOO":0:{}');
+
+var_dump($o);
+
+echo "Done";
+?>
+--EXPECT--
+callback_called
+object(Foo)#1 (0) {
+}
+Done
diff --git a/ext/standard/tests/serialize/unserialize_callback_func/fn_with_fqn_namespace.phpt b/ext/standard/tests/serialize/unserialize_callback_func/fn_with_fqn_namespace.phpt
new file mode 100644
index 00000000000..28718bdb241
--- /dev/null
+++ b/ext/standard/tests/serialize/unserialize_callback_func/fn_with_fqn_namespace.phpt
@@ -0,0 +1,26 @@
+--TEST--
+unserialize_callback_func with fully qualified named namespaced function
+--INI--
+unserialize_callback_func=\php\test\my_global_fn
+--FILE--
+<?php
+
+namespace php\test {
+ function my_global_fn($name) {
+ echo "callback_called\n";
+ eval('class Foo {}');
+ }
+}
+namespace {
+ $o = unserialize('O:3:"FOO":0:{}');
+
+ var_dump($o);
+
+ echo "Done";
+}
+?>
+--EXPECT--
+callback_called
+object(Foo)#1 (0) {
+}
+Done
diff --git a/ext/standard/tests/serialize/unserialize_callback_func/fn_with_null_bytes.phpt b/ext/standard/tests/serialize/unserialize_callback_func/fn_with_null_bytes.phpt
new file mode 100644
index 00000000000..5341d4bb6dd
--- /dev/null
+++ b/ext/standard/tests/serialize/unserialize_callback_func/fn_with_null_bytes.phpt
@@ -0,0 +1,25 @@
+--TEST--
+unserialize_callback_func with function name containing null bytes
+--FILE--
+<?php
+
+ini_set('unserialize_callback_func', "foo\0butno");
+
+function foo(string $name) {
+ echo "callback_called\n";
+ eval('class Foo {}');
+}
+
+$s = 'O:3:"FOO":0:{}';
+try {
+ $o = unserialize($s);
+ var_dump($o);
+} catch (Throwable $e) {
+ echo $e::class, ': ', $e->getMessage(), PHP_EOL;
+}
+
+echo "Done";
+?>
+--EXPECT--
+Error: Invalid callback foo, function "foo" not found or invalid function name
+Done
diff --git a/ext/standard/tests/serialize/unserialize_callback_func/non_static_method_private.phpt b/ext/standard/tests/serialize/unserialize_callback_func/non_static_method_private.phpt
new file mode 100644
index 00000000000..2b3fb93f3d4
--- /dev/null
+++ b/ext/standard/tests/serialize/unserialize_callback_func/non_static_method_private.phpt
@@ -0,0 +1,42 @@
+--TEST--
+unserialize_callback_func with private non-static method
+--INI--
+unserialize_callback_func=Tester::my_unserialize
+--FILE--
+<?php
+
+class Tester {
+ private function my_unserialize($name) {
+ echo "callback_called\n";
+ eval('class Foo {}');
+ }
+
+ public function unserialize(string $str) {
+ return unserialize($str);
+ }
+}
+
+$s = 'O:3:"FOO":0:{}';
+try {
+ $o = unserialize($s);
+ var_dump($o);
+} catch (Throwable $e) {
+ echo $e::class, ': ', $e->getMessage(), PHP_EOL;
+}
+
+try {
+ $tester = new Tester();
+ $o = $tester->unserialize($s);
+ var_dump($o);
+} catch (Throwable $e) {
+ echo $e::class, ': ', $e->getMessage(), PHP_EOL;
+}
+echo "Done";
+
+?>
+--EXPECT--
+Error: Invalid callback Tester::my_unserialize, non-static method Tester::my_unserialize() cannot be called statically
+callback_called
+object(Foo)#3 (0) {
+}
+Done
diff --git a/ext/standard/tests/serialize/unserialize_callback_func/non_static_method_public.phpt b/ext/standard/tests/serialize/unserialize_callback_func/non_static_method_public.phpt
new file mode 100644
index 00000000000..ec09c8285a5
--- /dev/null
+++ b/ext/standard/tests/serialize/unserialize_callback_func/non_static_method_public.phpt
@@ -0,0 +1,42 @@
+--TEST--
+unserialize_callback_func with public non-static method
+--INI--
+unserialize_callback_func=Tester::my_unserialize
+--FILE--
+<?php
+
+class Tester {
+ public function my_unserialize($name) {
+ echo "callback_called\n";
+ eval('class Foo {}');
+ }
+
+ public function unserialize(string $str) {
+ return unserialize($str);
+ }
+}
+
+$s = 'O:3:"FOO":0:{}';
+try {
+ $o = unserialize($s);
+ var_dump($o);
+} catch (Throwable $e) {
+ echo $e::class, ': ', $e->getMessage(), PHP_EOL;
+}
+
+try {
+ $tester = new Tester();
+ $o = $tester->unserialize($s);
+ var_dump($o);
+} catch (Throwable $e) {
+ echo $e::class, ': ', $e->getMessage(), PHP_EOL;
+}
+echo "Done";
+
+?>
+--EXPECT--
+Error: Invalid callback Tester::my_unserialize, non-static method Tester::my_unserialize() cannot be called statically
+callback_called
+object(Foo)#3 (0) {
+}
+Done
diff --git a/ext/standard/tests/serialize/unserialize_callback_func/static_method.phpt b/ext/standard/tests/serialize/unserialize_callback_func/static_method.phpt
new file mode 100644
index 00000000000..a96d998cd8c
--- /dev/null
+++ b/ext/standard/tests/serialize/unserialize_callback_func/static_method.phpt
@@ -0,0 +1,26 @@
+--TEST--
+unserialize_callback_func with public static method
+--INI--
+unserialize_callback_func=Tester::my_unserialize
+--FILE--
+<?php
+
+class Tester {
+ public static function my_unserialize($name) {
+ echo "callback_called\n";
+ eval('class Foo {}');
+ }
+}
+
+$o = unserialize('O:3:"FOO":0:{}');
+
+var_dump($o);
+
+echo "Done";
+
+?>
+--EXPECT--
+callback_called
+object(Foo)#1 (0) {
+}
+Done
diff --git a/ext/standard/tests/serialize/unserialize_callback_func/static_method_private.phpt b/ext/standard/tests/serialize/unserialize_callback_func/static_method_private.phpt
new file mode 100644
index 00000000000..4bc4e760bed
--- /dev/null
+++ b/ext/standard/tests/serialize/unserialize_callback_func/static_method_private.phpt
@@ -0,0 +1,41 @@
+--TEST--
+unserialize_callback_func with private static method
+--INI--
+unserialize_callback_func=Tester::my_unserialize
+--FILE--
+<?php
+
+class Tester {
+ private static function my_unserialize($name) {
+ echo "callback_called\n";
+ eval('class Foo {}');
+ }
+
+ public static function unserialize(string $str) {
+ return unserialize($str);
+ }
+}
+
+$s = 'O:3:"FOO":0:{}';
+try {
+ $o = unserialize($s);
+ var_dump($o);
+} catch (Throwable $e) {
+ echo $e::class, ': ', $e->getMessage(), PHP_EOL;
+}
+
+try {
+ $o = Tester::unserialize($s);
+ var_dump($o);
+} catch (Throwable $e) {
+ echo $e::class, ': ', $e->getMessage(), PHP_EOL;
+}
+echo "Done";
+
+?>
+--EXPECT--
+Error: Invalid callback Tester::my_unserialize, cannot access private method Tester::my_unserialize()
+callback_called
+object(Foo)#2 (0) {
+}
+Done