Skip to content

Commit 77cd291

Browse files
committed
Merge branch 'PHP-8.5'
* PHP-8.5: NEWS entries for recent SPL bug fixes ext/spl: ignore leading namespace separator in spl_autoload() (#22323) ext/spl: fix class_parents for classes with leading slash in non-autoload mode (#22283)
2 parents 34116ad + d23da75 commit 77cd291

3 files changed

Lines changed: 97 additions & 11 deletions

File tree

ext/spl/php_spl.c

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,7 @@ ZEND_TLS zend_string *spl_autoload_extensions;
4040

4141
static zend_class_entry * spl_find_ce_by_name(zend_string *name, bool autoload)
4242
{
43-
zend_class_entry *ce;
44-
45-
if (!autoload) {
46-
zend_string *lc_name = zend_string_tolower(name);
47-
48-
ce = zend_hash_find_ptr(EG(class_table), lc_name);
49-
zend_string_release(lc_name);
50-
} else {
51-
ce = zend_lookup_class(name);
52-
}
43+
zend_class_entry *ce = zend_lookup_class_ex(name, NULL, autoload ? 0 : ZEND_FETCH_CLASS_NO_AUTOLOAD);
5344
if (ce == NULL) {
5445
php_error_docref(NULL, E_WARNING, "Class %s does not exist%s", ZSTR_VAL(name), autoload ? " and could not be loaded" : "");
5546
return NULL;
@@ -334,7 +325,12 @@ PHP_FUNCTION(spl_autoload)
334325
pos_len = ZSTR_LEN(file_exts);
335326
}
336327

337-
lc_name = zend_string_tolower(class_name);
328+
if (ZSTR_VAL(class_name)[0] == '\\') {
329+
lc_name = zend_string_alloc(ZSTR_LEN(class_name) - 1, 0);
330+
zend_str_tolower_copy(ZSTR_VAL(lc_name), ZSTR_VAL(class_name) + 1, ZSTR_LEN(class_name) - 1);
331+
} else {
332+
lc_name = zend_string_tolower(class_name);
333+
}
338334
while (pos && *pos && !EG(exception)) {
339335
pos1 = strchr(pos, ',');
340336
if (pos1) {
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
--TEST--
2+
class_parents()/class_implements()/class_uses() accept a leading backslash regardless of $autoload
3+
--FILE--
4+
<?php
5+
6+
namespace {
7+
interface Iface {}
8+
trait Tr {}
9+
class ParentC implements Iface {}
10+
class ChildC extends ParentC {
11+
use Tr;
12+
}
13+
}
14+
15+
namespace MyNS {
16+
interface NSIface {}
17+
trait NSTr {}
18+
class NSParentC implements NSIface {}
19+
class NSChildC extends NSParentC {
20+
use NSTr;
21+
}
22+
}
23+
24+
namespace {
25+
26+
// The no-autoload path missed the leading-backslash strip before the fix.
27+
var_dump(class_parents('\ChildC', false));
28+
var_dump(class_parents('\ChildC'));
29+
var_dump(class_implements('\ParentC', false));
30+
var_dump(class_uses('\ChildC', false));
31+
32+
// Same for namespaced classes.
33+
var_dump(class_parents('\MyNS\NSChildC', false));
34+
var_dump(class_parents('\MyNS\NSChildC'));
35+
var_dump(class_implements('\MyNS\NSParentC', false));
36+
var_dump(class_uses('\MyNS\NSChildC', false));
37+
38+
}
39+
?>
40+
--EXPECT--
41+
array(1) {
42+
["ParentC"]=>
43+
string(7) "ParentC"
44+
}
45+
array(1) {
46+
["ParentC"]=>
47+
string(7) "ParentC"
48+
}
49+
array(1) {
50+
["Iface"]=>
51+
string(5) "Iface"
52+
}
53+
array(1) {
54+
["Tr"]=>
55+
string(2) "Tr"
56+
}
57+
array(1) {
58+
["MyNS\NSParentC"]=>
59+
string(14) "MyNS\NSParentC"
60+
}
61+
array(1) {
62+
["MyNS\NSParentC"]=>
63+
string(14) "MyNS\NSParentC"
64+
}
65+
array(1) {
66+
["MyNS\NSIface"]=>
67+
string(12) "MyNS\NSIface"
68+
}
69+
array(1) {
70+
["MyNS\NSTr"]=>
71+
string(9) "MyNS\NSTr"
72+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
spl_autoload(): a leading "\" in the class name is ignored
3+
--FILE--
4+
<?php
5+
6+
set_include_path(__DIR__);
7+
spl_autoload_extensions(".inc");
8+
9+
spl_autoload("DualIterator");
10+
var_dump(class_exists("DualIterator", false));
11+
12+
spl_autoload("\\RecursiveDualIterator");
13+
var_dump(class_exists("RecursiveDualIterator", false));
14+
15+
?>
16+
--EXPECT--
17+
bool(true)
18+
bool(true)

0 commit comments

Comments
 (0)