Commit 8c37bb95303 for php.net

commit 8c37bb953031955369e4dd26bcfd2b793a109160
Author: Gina Peter Banyard <girgias@php.net>
Date:   Wed Mar 25 13:31:36 2026 +0000

    ext/spl: refactor reflection-like functions

    Make the helpers private and remove a lot of unnecessary computation and code that was effectively dead.

diff --git a/ext/spl/php_spl.c b/ext/spl/php_spl.c
index 0c64d815dc8..a4f3284025f 100644
--- a/ext/spl/php_spl.c
+++ b/ext/spl/php_spl.c
@@ -60,6 +60,43 @@ static zend_class_entry * spl_find_ce_by_name(zend_string *name, bool autoload)
 	return ce;
 }

+static void spl_add_class_name(HashTable *list, zend_string *name)
+{
+	zval t;
+	ZVAL_STR_COPY(&t, name);
+	zend_hash_add(list, name, &t);
+}
+
+static void spl_add_interfaces(HashTable *list, const zend_class_entry *pce)
+{
+	if (pce->num_interfaces) {
+		ZEND_ASSERT(pce->ce_flags & ZEND_ACC_LINKED);
+		for (uint32_t num_interfaces = 0; num_interfaces < pce->num_interfaces; num_interfaces++) {
+			spl_add_class_name(list, pce->interfaces[num_interfaces]->name);
+		}
+	}
+}
+
+static void spl_add_traits(HashTable *list, const zend_class_entry *pce)
+{
+	for (uint32_t num_traits = 0; num_traits < pce->num_traits; num_traits++) {
+		spl_add_class_name(list, pce->trait_names[num_traits].name);
+	}
+}
+
+static void spl_add_classes(HashTable *list, const zend_class_entry *pce, bool only_classes, bool only_interfaces)
+{
+	ZEND_ASSERT(pce);
+	ZEND_ASSERT(!(only_classes && only_interfaces) && "Cannot have both only classes and only interfaces be enabled");
+	if (
+		(only_classes && (pce->ce_flags & ZEND_ACC_INTERFACE) == ZEND_ACC_INTERFACE)
+		|| (only_interfaces && (pce->ce_flags & ZEND_ACC_INTERFACE) == 0)
+	) {
+		return;
+	}
+	spl_add_class_name(list, pce->name);
+}
+
 /* {{{ Return an array containing the names of all parent classes */
 PHP_FUNCTION(class_parents)
 {
@@ -88,7 +125,7 @@ PHP_FUNCTION(class_parents)
 	array_init(return_value);
 	const zend_class_entry *parent_class = ce->parent;
 	while (parent_class) {
-		spl_add_class_name(return_value, parent_class, 0, 0);
+		spl_add_class_name(Z_ARR_P(return_value), parent_class->name);
 		parent_class = parent_class->parent;
 	}
 }
@@ -119,7 +156,7 @@ PHP_FUNCTION(class_implements)
 	}

 	array_init(return_value);
-	spl_add_interfaces(return_value, ce, 1, ZEND_ACC_INTERFACE);
+	spl_add_interfaces(Z_ARR_P(return_value), ce);
 }
 /* }}} */

@@ -148,69 +185,69 @@ PHP_FUNCTION(class_uses)
 	}

 	array_init(return_value);
-	spl_add_traits(return_value, ce, 1, ZEND_ACC_TRAIT);
+	spl_add_traits(Z_ARR_P(return_value), ce);
 }
 /* }}} */

-#define SPL_ADD_CLASS(class_name, z_list, sub, allow, ce_flags) \
-	spl_add_classes(spl_ce_ ## class_name, z_list, sub, allow, ce_flags)
-
-#define SPL_LIST_CLASSES(z_list, sub, allow, ce_flags) \
-	SPL_ADD_CLASS(AppendIterator, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(ArrayIterator, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(ArrayObject, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(BadFunctionCallException, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(BadMethodCallException, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(CachingIterator, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(CallbackFilterIterator, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(DirectoryIterator, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(DomainException, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(EmptyIterator, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(FilesystemIterator, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(FilterIterator, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(GlobIterator, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(InfiniteIterator, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(InvalidArgumentException, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(IteratorIterator, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(LengthException, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(LimitIterator, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(LogicException, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(MultipleIterator, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(NoRewindIterator, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(OuterIterator, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(OutOfBoundsException, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(OutOfRangeException, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(OverflowException, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(ParentIterator, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(RangeException, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(RecursiveArrayIterator, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(RecursiveCachingIterator, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(RecursiveCallbackFilterIterator, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(RecursiveDirectoryIterator, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(RecursiveFilterIterator, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(RecursiveIterator, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(RecursiveIteratorIterator, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(RecursiveRegexIterator, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(RecursiveTreeIterator, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(RegexIterator, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(RuntimeException, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(SeekableIterator, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(SplDoublyLinkedList, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(SplFileInfo, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(SplFileObject, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(SplFixedArray, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(SplHeap, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(SplMinHeap, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(SplMaxHeap, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(SplObjectStorage, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(SplObserver, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(SplPriorityQueue, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(SplQueue, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(SplStack, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(SplSubject, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(SplTempFileObject, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(UnderflowException, z_list, sub, allow, ce_flags); \
-	SPL_ADD_CLASS(UnexpectedValueException, z_list, sub, allow, ce_flags); \
+#define SPL_ADD_CLASS(class_name, z_list, only_classes, only_interfaces) \
+	spl_add_classes(Z_ARR_P(z_list), spl_ce_ ## class_name, only_classes, only_interfaces)
+
+#define SPL_LIST_CLASSES(z_list, only_classes, only_interfaces) \
+	SPL_ADD_CLASS(AppendIterator, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(ArrayIterator, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(ArrayObject, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(BadFunctionCallException, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(BadMethodCallException, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(CachingIterator, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(CallbackFilterIterator, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(DirectoryIterator, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(DomainException, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(EmptyIterator, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(FilesystemIterator, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(FilterIterator, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(GlobIterator, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(InfiniteIterator, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(InvalidArgumentException, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(IteratorIterator, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(LengthException, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(LimitIterator, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(LogicException, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(MultipleIterator, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(NoRewindIterator, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(OuterIterator, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(OutOfBoundsException, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(OutOfRangeException, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(OverflowException, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(ParentIterator, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(RangeException, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(RecursiveArrayIterator, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(RecursiveCachingIterator, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(RecursiveCallbackFilterIterator, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(RecursiveDirectoryIterator, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(RecursiveFilterIterator, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(RecursiveIterator, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(RecursiveIteratorIterator, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(RecursiveRegexIterator, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(RecursiveTreeIterator, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(RegexIterator, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(RuntimeException, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(SeekableIterator, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(SplDoublyLinkedList, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(SplFileInfo, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(SplFileObject, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(SplFixedArray, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(SplHeap, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(SplMinHeap, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(SplMaxHeap, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(SplObjectStorage, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(SplObserver, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(SplPriorityQueue, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(SplQueue, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(SplStack, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(SplSubject, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(SplTempFileObject, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(UnderflowException, z_list, only_classes, only_interfaces); \
+	SPL_ADD_CLASS(UnexpectedValueException, z_list, only_classes, only_interfaces); \

 /* {{{ Return an array containing the names of all classes and interfaces defined in SPL */
 PHP_FUNCTION(spl_classes)
@@ -219,7 +256,7 @@ PHP_FUNCTION(spl_classes)

 	array_init(return_value);

-	SPL_LIST_CLASSES(return_value, 0, 0, 0)
+	SPL_LIST_CLASSES(return_value, false, false)
 }
 /* }}} */

@@ -486,7 +523,7 @@ PHP_MINFO_FUNCTION(spl)
 	php_info_print_table_row(2, "SPL support", "enabled");

 	array_init(&list);
-	SPL_LIST_CLASSES(&list, 0, 1, ZEND_ACC_INTERFACE)
+	SPL_LIST_CLASSES(&list, false, true)
 	strg = estrdup("");
 	ZEND_HASH_MAP_FOREACH_VAL(Z_ARRVAL_P(&list), zv) {
 		spl_build_class_list_string(zv, &strg);
@@ -496,7 +533,7 @@ PHP_MINFO_FUNCTION(spl)
 	efree(strg);

 	array_init(&list);
-	SPL_LIST_CLASSES(&list, 0, -1, ZEND_ACC_INTERFACE)
+	SPL_LIST_CLASSES(&list, true, false)
 	strg = estrdup("");
 	ZEND_HASH_MAP_FOREACH_VAL(Z_ARRVAL_P(&list), zv) {
 		spl_build_class_list_string(zv, &strg);
diff --git a/ext/spl/spl_functions.c b/ext/spl/spl_functions.c
index 7b7991a1217..e3963aced7e 100644
--- a/ext/spl/spl_functions.c
+++ b/ext/spl/spl_functions.c
@@ -20,61 +20,6 @@

 #include "php.h"

-/* {{{ spl_add_class_name */
-void spl_add_class_name(zval *list, const zend_class_entry *pce, int allow, int ce_flags)
-{
-	if (!allow || (allow > 0 && (pce->ce_flags & ce_flags)) || (allow < 0 && !(pce->ce_flags & ce_flags))) {
-		const zval *tmp = zend_hash_find(Z_ARRVAL_P(list), pce->name);
-
-		if (tmp == NULL) {
-			zval t;
-			ZVAL_STR_COPY(&t, pce->name);
-			zend_hash_add(Z_ARRVAL_P(list), pce->name, &t);
-		}
-	}
-}
-/* }}} */
-
-/* {{{ spl_add_interfaces */
-void spl_add_interfaces(zval *list, const zend_class_entry *pce, int allow, int ce_flags)
-{
-	if (pce->num_interfaces) {
-		ZEND_ASSERT(pce->ce_flags & ZEND_ACC_LINKED);
-		for (uint32_t num_interfaces = 0; num_interfaces < pce->num_interfaces; num_interfaces++) {
-			spl_add_class_name(list, pce->interfaces[num_interfaces], allow, ce_flags);
-		}
-	}
-}
-/* }}} */
-
-/* {{{ spl_add_traits */
-void spl_add_traits(zval *list, const zend_class_entry *pce, int allow, int ce_flags)
-{
-	for (uint32_t num_traits = 0; num_traits < pce->num_traits; num_traits++) {
-		const zend_class_entry *trait = zend_fetch_class_by_name(pce->trait_names[num_traits].name,
-			pce->trait_names[num_traits].lc_name, ZEND_FETCH_CLASS_TRAIT);
-		ZEND_ASSERT(trait);
-		spl_add_class_name(list, trait, allow, ce_flags);
-	}
-}
-/* }}} */
-
-
-/* {{{ spl_add_classes */
-void spl_add_classes(const zend_class_entry *pce, zval *list, bool sub, int allow, int ce_flags)
-{
-	ZEND_ASSERT(pce);
-	spl_add_class_name(list, pce, allow, ce_flags);
-	if (sub) {
-		spl_add_interfaces(list, pce, allow, ce_flags);
-		while (pce->parent) {
-			pce = pce->parent;
-			spl_add_classes(pce, list, sub, allow, ce_flags);
-		}
-	}
-}
-/* }}} */
-
 void spl_set_private_debug_info_property(
 	const zend_class_entry *ce,
 	const char *property,
diff --git a/ext/spl/spl_functions.h b/ext/spl/spl_functions.h
index ca92a237169..409ce9fcada 100644
--- a/ext/spl/spl_functions.h
+++ b/ext/spl/spl_functions.h
@@ -19,16 +19,6 @@

 #include "php.h"

-/* sub: whether to allow subclasses/interfaces
-   allow = 0: allow all classes and interfaces
-   allow > 0: allow all that match and mask ce_flags
-   allow < 0: disallow all that match and mask ce_flags
- */
-void spl_add_class_name(zval * list, const zend_class_entry *pce, int allow, int ce_flags);
-void spl_add_interfaces(zval * list, const zend_class_entry *pce, int allow, int ce_flags);
-void spl_add_traits(zval * list, const zend_class_entry *pce, int allow, int ce_flags);
-void spl_add_classes(const zend_class_entry *pce, zval *list, bool sub, int allow, int ce_flags);
-
 void spl_set_private_debug_info_property(const zend_class_entry *ce, const char *property, size_t property_len, HashTable *debug_info, zval *value);

 #endif /* PHP_FUNCTIONS_H */