Skip to content

Commit d480c04

Browse files
authored
Implement cache slot optimization for XMLReader (php#17232)
1 parent 26244c7 commit d480c04

File tree

3 files changed

+80
-4
lines changed

3 files changed

+80
-4
lines changed

UPGRADING

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,5 +236,8 @@ PHP 8.5 UPGRADE NOTES
236236
14. Performance Improvements
237237
========================================
238238

239+
- XMLReader:
240+
. Improved property access performance.
241+
239242
- XMLWriter:
240243
. Improved performance and reduce memory consumption.

ext/xmlreader/php_xmlreader.c

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,25 @@ static zval *xmlreader_get_property_ptr_ptr(zend_object *object, zend_string *na
123123
}
124124
/* }}} */
125125

126+
static xmlreader_prop_handler *xmlreader_get_prop_handler(zend_string *name, void **cache_slot)
127+
{
128+
/* We don't store the `ce` as that may match with how the std cache slot code works in the fallback,
129+
* instead use the prop handlers table as `ce`. */
130+
if (cache_slot && cache_slot[0] == &xmlreader_prop_handlers) {
131+
return cache_slot[1];
132+
} else {
133+
xmlreader_prop_handler *hnd = zend_hash_find_ptr(&xmlreader_prop_handlers, name);
134+
if (hnd != NULL && cache_slot) {
135+
CACHE_POLYMORPHIC_PTR_EX(cache_slot, &xmlreader_prop_handlers, hnd);
136+
}
137+
return hnd;
138+
}
139+
}
140+
126141
static int xmlreader_has_property(zend_object *object, zend_string *name, int type, void **cache_slot)
127142
{
128143
xmlreader_object *obj = php_xmlreader_fetch_object(object);
129-
xmlreader_prop_handler *hnd = zend_hash_find_ptr(&xmlreader_prop_handlers, name);
144+
xmlreader_prop_handler *hnd = xmlreader_get_prop_handler(name, cache_slot);
130145

131146
if (hnd != NULL) {
132147
if (type == ZEND_PROPERTY_EXISTS) {
@@ -162,7 +177,7 @@ static zval *xmlreader_read_property(zend_object *object, zend_string *name, int
162177
{
163178
zval *retval = NULL;
164179
xmlreader_object *obj = php_xmlreader_fetch_object(object);
165-
xmlreader_prop_handler *hnd = zend_hash_find_ptr(&xmlreader_prop_handlers, name);
180+
xmlreader_prop_handler *hnd = xmlreader_get_prop_handler(name, cache_slot);
166181

167182
if (hnd != NULL) {
168183
if (xmlreader_property_reader(obj, hnd, rv) == FAILURE) {
@@ -181,7 +196,7 @@ static zval *xmlreader_read_property(zend_object *object, zend_string *name, int
181196
/* {{{ xmlreader_write_property */
182197
static zval *xmlreader_write_property(zend_object *object, zend_string *name, zval *value, void **cache_slot)
183198
{
184-
xmlreader_prop_handler *hnd = zend_hash_find_ptr(&xmlreader_prop_handlers, name);
199+
xmlreader_prop_handler *hnd = xmlreader_get_prop_handler(name, cache_slot);
185200

186201
if (hnd != NULL) {
187202
zend_readonly_property_modification_error_ex(ZSTR_VAL(object->ce->name), ZSTR_VAL(name));
@@ -195,7 +210,7 @@ static zval *xmlreader_write_property(zend_object *object, zend_string *name, zv
195210

196211
void xmlreader_unset_property(zend_object *object, zend_string *name, void **cache_slot)
197212
{
198-
xmlreader_prop_handler *hnd = zend_hash_find_ptr(&xmlreader_prop_handlers, name);
213+
xmlreader_prop_handler *hnd = xmlreader_get_prop_handler(name, cache_slot);
199214

200215
if (hnd != NULL) {
201216
zend_throw_error(NULL, "Cannot unset %s::$%s", ZSTR_VAL(object->ce->name), ZSTR_VAL(name));

ext/xmlreader/tests/cache_slot.phpt

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
--TEST--
2+
Cache slot test
3+
--EXTENSIONS--
4+
xmlreader
5+
--FILE--
6+
<?php
7+
8+
class Test1 {
9+
function __construct(public string $localName) {}
10+
}
11+
12+
#[AllowDynamicProperties]
13+
class Test2 extends XMLReader {
14+
}
15+
16+
function readLocalName($obj) {
17+
for ($i = 0; $i < 2; $i++)
18+
var_dump($obj->localName);
19+
}
20+
21+
function readTestProp($obj) {
22+
for ($i = 0; $i < 2; $i++)
23+
var_dump($obj->testProp);
24+
}
25+
26+
$reader = XMLReader::fromString("<root/>");
27+
$reader->read();
28+
$test1 = new Test1("hello");
29+
30+
readLocalName($reader);
31+
readLocalName($test1);
32+
readLocalName($reader);
33+
34+
$test2 = new Test2;
35+
$test2->testProp = 1;
36+
37+
readTestProp($test2);
38+
readTestProp($reader);
39+
readTestProp($test2);
40+
41+
?>
42+
--EXPECTF--
43+
string(4) "root"
44+
string(4) "root"
45+
string(5) "hello"
46+
string(5) "hello"
47+
string(4) "root"
48+
string(4) "root"
49+
int(1)
50+
int(1)
51+
52+
Warning: Undefined property: XMLReader::$testProp in %s on line %d
53+
NULL
54+
55+
Warning: Undefined property: XMLReader::$testProp in %s on line %d
56+
NULL
57+
int(1)
58+
int(1)

0 commit comments

Comments
 (0)