Commit 075b6b85f6b for php.net

commit 075b6b85f6b964108c76cea7c64c944bf1585954
Author: Arnaud Le Blanc <365207+arnaud-lb@users.noreply.github.com>
Date:   Tue Jan 13 12:32:52 2026 +0100

    Set default_object_handlers when registering internal enums

    Internal enums can be cloned and compared, unlike user enums, because we didn't set default_object_handlers when registering internal enums.

    Fix by setting default_object_handlers when registering internal enums.

    Fixes GH-20914
    Closes GH-20915

diff --git a/Zend/tests/enum/comparison-internal.phpt b/Zend/tests/enum/comparison-internal.phpt
new file mode 100644
index 00000000000..3d0a2f1e172
--- /dev/null
+++ b/Zend/tests/enum/comparison-internal.phpt
@@ -0,0 +1,54 @@
+--TEST--
+Enum comparison (internal enum)
+--EXTENSIONS--
+zend_test
+--FILE--
+<?php
+
+$foo = ZendTestUnitEnum::Foo;
+$bar = ZendTestUnitEnum::Bar;
+
+var_dump($foo === $foo);
+var_dump($foo == $foo);
+
+var_dump($foo === $bar);
+var_dump($foo == $bar);
+
+var_dump($bar === $foo);
+var_dump($bar == $foo);
+
+var_dump($foo > $foo);
+var_dump($foo < $foo);
+var_dump($foo >= $foo);
+var_dump($foo <= $foo);
+
+var_dump($foo > $bar);
+var_dump($foo < $bar);
+var_dump($foo >= $bar);
+var_dump($foo <= $bar);
+
+var_dump($foo > true);
+var_dump($foo < true);
+var_dump($foo >= true);
+var_dump($foo <= true);
+
+?>
+--EXPECT--
+bool(true)
+bool(true)
+bool(false)
+bool(false)
+bool(false)
+bool(false)
+bool(false)
+bool(false)
+bool(true)
+bool(true)
+bool(false)
+bool(false)
+bool(false)
+bool(false)
+bool(false)
+bool(false)
+bool(false)
+bool(false)
diff --git a/Zend/tests/enum/implements-internal.phpt b/Zend/tests/enum/implements-internal.phpt
new file mode 100644
index 00000000000..518602af97e
--- /dev/null
+++ b/Zend/tests/enum/implements-internal.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Enum implements (internal enum)
+--EXTENSIONS--
+zend_test
+--FILE--
+<?php
+
+var_dump(ZendTestUnitEnum::Foo instanceof _ZendTestInterface);
+var_dump(ZendTestEnumWithInterface::Foo instanceof _ZendTestInterface);
+
+?>
+--EXPECT--
+bool(false)
+bool(true)
diff --git a/Zend/tests/enum/instanceof-backed-enum.phpt b/Zend/tests/enum/instanceof-backed-enum.phpt
index 4716835d116..7087cfec74b 100644
--- a/Zend/tests/enum/instanceof-backed-enum.phpt
+++ b/Zend/tests/enum/instanceof-backed-enum.phpt
@@ -1,5 +1,7 @@
 --TEST--
 Auto implement BackedEnum interface
+--EXTENSIONS--
+zend_test
 --FILE--
 <?php

@@ -13,8 +15,12 @@ enum Baz: int {

 var_dump(Foo::Bar instanceof BackedEnum);
 var_dump(Baz::Qux instanceof BackedEnum);
+var_dump(ZendTestUnitEnum::Foo instanceof BackedEnum);
+var_dump(ZendTestIntEnum::Foo instanceof BackedEnum);

 ?>
 --EXPECT--
 bool(false)
 bool(true)
+bool(false)
+bool(true)
diff --git a/Zend/tests/enum/instanceof-unitenum.phpt b/Zend/tests/enum/instanceof-unitenum.phpt
index 55237963253..89b04b50466 100644
--- a/Zend/tests/enum/instanceof-unitenum.phpt
+++ b/Zend/tests/enum/instanceof-unitenum.phpt
@@ -1,5 +1,7 @@
 --TEST--
 Auto implement UnitEnum interface
+--EXTENSIONS--
+zend_test
 --FILE--
 <?php

@@ -11,8 +13,10 @@ class Baz {}

 var_dump(Foo::Bar instanceof UnitEnum);
 var_dump((new Baz()) instanceof UnitEnum);
+var_dump(ZendTestUnitEnum::Foo instanceof UnitEnum);

 ?>
 --EXPECT--
 bool(true)
 bool(false)
+bool(true)
diff --git a/Zend/tests/enum/no-clone-internal.phpt b/Zend/tests/enum/no-clone-internal.phpt
new file mode 100644
index 00000000000..84b7ee2634d
--- /dev/null
+++ b/Zend/tests/enum/no-clone-internal.phpt
@@ -0,0 +1,16 @@
+--TEST--
+Enum disallows cloning (internal enum)
+--EXTENSIONS--
+zend_test
+--FILE--
+<?php
+
+try {
+    var_dump(clone ZendTestIntEnum::Foo);
+} catch (Error $e) {
+    echo $e->getMessage() . "\n";
+}
+
+?>
+--EXPECT--
+Trying to clone an uncloneable object of class ZendTestIntEnum
diff --git a/Zend/tests/enum/no-dynamic-properties-internal.phpt b/Zend/tests/enum/no-dynamic-properties-internal.phpt
new file mode 100644
index 00000000000..8d821a5f629
--- /dev/null
+++ b/Zend/tests/enum/no-dynamic-properties-internal.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Enum case disallows dynamic properties (internal enum)
+--EXTENSIONS--
+zend_test
+--FILE--
+<?php
+
+$bar = ZendTestUnitEnum::Bar;
+
+try {
+    $bar->baz = 'Baz';
+} catch (\Error $e) {
+    echo $e->getMessage();
+}
+
+?>
+--EXPECT--
+Cannot create dynamic property ZendTestUnitEnum::$baz
diff --git a/Zend/zend_enum.c b/Zend/zend_enum.c
index ccafca48fe9..464e7d801a8 100644
--- a/Zend/zend_enum.c
+++ b/Zend/zend_enum.c
@@ -528,6 +528,8 @@ ZEND_API zend_class_entry *zend_register_internal_enum(
 		zend_class_implements(ce, 1, zend_ce_backed_enum);
 	}

+	ce->default_object_handlers = &zend_enum_object_handlers;
+
 	return ce;
 }

diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c
index 59b2c79edf6..576bacd5e4a 100644
--- a/ext/zend_test/test.c
+++ b/ext/zend_test/test.c
@@ -74,6 +74,7 @@ static zend_class_entry *zend_test_ns2_ns_foo_class;
 static zend_class_entry *zend_test_unit_enum;
 static zend_class_entry *zend_test_string_enum;
 static zend_class_entry *zend_test_int_enum;
+static zend_class_entry *zend_test_enum_with_interface;
 static zend_class_entry *zend_test_magic_call;
 static zend_object_handlers zend_test_class_handlers;

@@ -1318,6 +1319,7 @@ PHP_MINIT_FUNCTION(zend_test)
 	zend_test_unit_enum = register_class_ZendTestUnitEnum();
 	zend_test_string_enum = register_class_ZendTestStringEnum();
 	zend_test_int_enum = register_class_ZendTestIntEnum();
+	zend_test_enum_with_interface = register_class_ZendTestEnumWithInterface(zend_test_interface);

 	zend_test_magic_call = register_class__ZendTestMagicCall();

diff --git a/ext/zend_test/test.stub.php b/ext/zend_test/test.stub.php
index 1be61b7a170..9116245c30f 100644
--- a/ext/zend_test/test.stub.php
+++ b/ext/zend_test/test.stub.php
@@ -201,6 +201,11 @@ enum ZendTestIntEnum: int {
         case Baz = -1;
     }

+    enum ZendTestEnumWithInterface implements _ZendTestInterface {
+        case Foo;
+        case Bar;
+    }
+
     function zend_test_array_return(): array {}

     /** @genstubs-expose-comment-block
diff --git a/ext/zend_test/test_arginfo.h b/ext/zend_test/test_arginfo.h
index b38a3546518..039757207e6 100644
Binary files a/ext/zend_test/test_arginfo.h and b/ext/zend_test/test_arginfo.h differ