diff --git a/NEWS b/NEWS index 0d9e42792078..5bbabbf66dc8 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,8 @@ PHP NEWS - Core: . Fixed bug GH-15375 (Nested "yield from" skips items after a valid() or next() call on the inner generator). (iliaal) + . Fixed bug GH-23232 (is_callable('\::method') asks the autoloader for an + empty class name). (spawnia) 27 Aug 2026, PHP 8.4.25 diff --git a/Zend/tests/gh23232.phpt b/Zend/tests/gh23232.phpt new file mode 100644 index 000000000000..d32baa8b071a --- /dev/null +++ b/Zend/tests/gh23232.phpt @@ -0,0 +1,27 @@ +--TEST-- +GH-23232 (is_callable('\::method') asks the autoloader for an empty class name) +--FILE-- + +--EXPECT-- +is_callable("::a") +bool(false) +is_callable("\::a") +bool(false) +is_callable("\Foo::a") +autoload: 'Foo' +bool(false) +is_callable("Foo::a") +autoload: 'Foo' +bool(false) +bool(false) diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index c81a8cfe5ff7..6e42be5f888c 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -1180,6 +1180,10 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string * } if (ZSTR_VAL(name)[0] == '\\') { + if (ZSTR_LEN(name) == 1) { + /* A lone namespace separator names no class, e.g. is_callable('\::method'). */ + return NULL; + } lc_name = zend_string_alloc(ZSTR_LEN(name) - 1, 0); zend_str_tolower_copy(ZSTR_VAL(lc_name), ZSTR_VAL(name) + 1, ZSTR_LEN(name) - 1); } else {