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