Skip to content

Commit 4730b06

Browse files
committed
Make SimpleXMLElement a RecursiveIterator
Context: https://externals.io/message/108789 This essentially moves the functionality of SimpleXMLIterator into SimpleXMLElement, and makes SimpleXMLIterator a no-op extension. Ideally SimpleXMLElement would be an IteratorAggregate, whose getIterator() method returns SimpleXMLIterator. However, because SimpleXMLIterator extends SimpleXMLElement (and code depends on this in non-trivial ways), this is not possible. The only way to not keep SimpleXMLElement as a magic Traversable (that implements neither Iterator nor IteratorAggregate) is to move the SimpleXMLIterator functionality into it. Closes GH-5234.
1 parent bcb9658 commit 4730b06

File tree

12 files changed

+218
-295
lines changed

12 files changed

+218
-295
lines changed

UPGRADING

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -793,6 +793,11 @@ PHP 8.0 UPGRADE NOTES
793793
- PGSQL / PDO PGSQL:
794794
. The PGSQL and PDO PGSQL extensions now require at least libpq 9.1.
795795

796+
- SimpleXML:
797+
. SimpleXMLElement now implements RecursiveIterator and absorbed the
798+
functionality of SimpleXMLIterator. SimpleXMLIterator is an empty extension
799+
of SimpleXMLElement.
800+
796801
- Shmop:
797802
. shmop_open() will now return a Shmop object rather than a resource. Return
798803
value checks using is_resource() should be replaced with checks for `false`.

ext/shmop/shmop_arginfo.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* This is a generated file, edit the .stub.php file instead.
2-
* Stub hash: a2e7d50e79d253e7136a54222346341003cc3b04 */
2+
* Stub hash: e451ccfbe66fc2b6fc0dae6e7e5710ededaf7b0c */
33

44
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_shmop_open, 0, 4, Shmop, MAY_BE_FALSE)
55
ZEND_ARG_TYPE_INFO(0, key, IS_LONG, 0)

ext/simplexml/config.m4

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ if test "$PHP_SIMPLEXML" != "no"; then
1212

1313
PHP_SETUP_LIBXML(SIMPLEXML_SHARED_LIBADD, [
1414
AC_DEFINE(HAVE_SIMPLEXML,1,[ ])
15-
PHP_NEW_EXTENSION(simplexml, simplexml.c sxe.c, $ext_shared)
15+
PHP_NEW_EXTENSION(simplexml, simplexml.c, $ext_shared)
1616
PHP_INSTALL_HEADERS([ext/simplexml/php_simplexml.h ext/simplexml/php_simplexml_exports.h])
1717
PHP_SUBST(SIMPLEXML_SHARED_LIBADD)
1818
])

ext/simplexml/config.w32

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ if (PHP_SIMPLEXML == "yes") {
77
ADD_EXTENSION_DEP('simplexml', 'libxml') &&
88
CHECK_HEADER_ADD_INCLUDE("libxml/tree.h", "CFLAGS_SIMPLEXML", PHP_PHP_BUILD + "\\include\\libxml2")
99
) {
10-
EXTENSION("simplexml", "simplexml.c sxe.c");
10+
EXTENSION("simplexml", "simplexml.c");
1111
AC_DEFINE("HAVE_SIMPLEXML", 1, "Simple XML support");
1212
if (!PHP_SIMPLEXML_SHARED) {
1313
ADD_FLAG("CFLAGS_SIMPLEXML", "/D LIBXML_STATIC");

ext/simplexml/php_simplexml.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ typedef struct {
7777
# define PHP_SXE_API ZEND_API
7878
#endif
7979

80+
extern PHP_SXE_API zend_class_entry *ce_SimpleXMLIterator;
81+
extern PHP_SXE_API zend_class_entry *ce_SimpleXMLElement;
82+
8083
PHP_SXE_API zend_class_entry *sxe_get_element_class_entry(void);
8184

8285
#endif

ext/simplexml/simplexml.c

Lines changed: 147 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,11 @@
3131
#include "simplexml_arginfo.h"
3232
#include "zend_exceptions.h"
3333
#include "zend_interfaces.h"
34-
#include "sxe.h"
34+
#include "ext/spl/spl_iterators.h"
3535

3636
zend_class_entry *sxe_class_entry = NULL;
37+
PHP_SXE_API zend_class_entry *ce_SimpleXMLIterator;
38+
PHP_SXE_API zend_class_entry *ce_SimpleXMLElement;
3739

3840
PHP_SXE_API zend_class_entry *sxe_get_element_class_entry(void) /* {{{ */
3941
{
@@ -2024,6 +2026,138 @@ SXE_METHOD(count)
20242026
}
20252027
/* }}} */
20262028

2029+
2030+
/* {{{ proto void SimpleXMLElement::rewind()
2031+
Rewind to first element */
2032+
SXE_METHOD(rewind)
2033+
{
2034+
if (zend_parse_parameters_none() == FAILURE) {
2035+
RETURN_THROWS();
2036+
}
2037+
2038+
php_sxe_rewind_iterator(Z_SXEOBJ_P(ZEND_THIS));
2039+
}
2040+
/* }}} */
2041+
2042+
/* {{{ proto bool SimpleXMLElement::valid()
2043+
Check whether iteration is valid */
2044+
SXE_METHOD(valid)
2045+
{
2046+
php_sxe_object *sxe = Z_SXEOBJ_P(ZEND_THIS);
2047+
2048+
if (zend_parse_parameters_none() == FAILURE) {
2049+
RETURN_THROWS();
2050+
}
2051+
2052+
RETURN_BOOL(!Z_ISUNDEF(sxe->iter.data));
2053+
}
2054+
/* }}} */
2055+
2056+
/* {{{ proto SimpleXMLElement SimpleXMLElement::current()
2057+
Get current element */
2058+
SXE_METHOD(current)
2059+
{
2060+
php_sxe_object *sxe = Z_SXEOBJ_P(ZEND_THIS);
2061+
zval *data;
2062+
2063+
if (zend_parse_parameters_none() == FAILURE) {
2064+
RETURN_THROWS();
2065+
}
2066+
2067+
if (Z_ISUNDEF(sxe->iter.data)) {
2068+
return; /* return NULL */
2069+
}
2070+
2071+
data = &sxe->iter.data;
2072+
ZVAL_COPY_DEREF(return_value, data);
2073+
}
2074+
/* }}} */
2075+
2076+
/* {{{ proto string SimpleXMLElement::key()
2077+
Get name of current child element */
2078+
SXE_METHOD(key)
2079+
{
2080+
xmlNodePtr curnode;
2081+
php_sxe_object *intern;
2082+
php_sxe_object *sxe = Z_SXEOBJ_P(ZEND_THIS);
2083+
2084+
if (zend_parse_parameters_none() == FAILURE) {
2085+
RETURN_THROWS();
2086+
}
2087+
2088+
if (Z_ISUNDEF(sxe->iter.data)) {
2089+
RETURN_FALSE;
2090+
}
2091+
2092+
intern = Z_SXEOBJ_P(&sxe->iter.data);
2093+
if (intern != NULL && intern->node != NULL) {
2094+
curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->node)->node;
2095+
RETURN_STRINGL((char*)curnode->name, xmlStrlen(curnode->name));
2096+
}
2097+
2098+
RETURN_FALSE;
2099+
}
2100+
/* }}} */
2101+
2102+
/* {{{ proto void SimpleXMLElement::next()
2103+
Move to next element */
2104+
SXE_METHOD(next)
2105+
{
2106+
if (zend_parse_parameters_none() == FAILURE) {
2107+
RETURN_THROWS();
2108+
}
2109+
2110+
php_sxe_move_forward_iterator(Z_SXEOBJ_P(ZEND_THIS));
2111+
}
2112+
/* }}} */
2113+
2114+
/* {{{ proto bool SimpleXMLElement::hasChildren()
2115+
Check whether element has children (elements) */
2116+
SXE_METHOD(hasChildren)
2117+
{
2118+
php_sxe_object *sxe = Z_SXEOBJ_P(ZEND_THIS);
2119+
php_sxe_object *child;
2120+
xmlNodePtr node;
2121+
2122+
if (zend_parse_parameters_none() == FAILURE) {
2123+
RETURN_THROWS();
2124+
}
2125+
2126+
if (Z_ISUNDEF(sxe->iter.data) || sxe->iter.type == SXE_ITER_ATTRLIST) {
2127+
RETURN_FALSE;
2128+
}
2129+
child = Z_SXEOBJ_P(&sxe->iter.data);
2130+
2131+
GET_NODE(child, node);
2132+
if (node) {
2133+
node = node->children;
2134+
}
2135+
while (node && node->type != XML_ELEMENT_NODE) {
2136+
node = node->next;
2137+
}
2138+
RETURN_BOOL(node ? 1 : 0);
2139+
}
2140+
/* }}} */
2141+
2142+
/* {{{ proto SimpleXMLElement SimpleXMLElement::getChildren()
2143+
Get child element iterator */
2144+
SXE_METHOD(getChildren)
2145+
{
2146+
php_sxe_object *sxe = Z_SXEOBJ_P(ZEND_THIS);
2147+
zval *data;
2148+
2149+
if (zend_parse_parameters_none() == FAILURE) {
2150+
RETURN_THROWS();
2151+
}
2152+
2153+
if (Z_ISUNDEF(sxe->iter.data) || sxe->iter.type == SXE_ITER_ATTRLIST) {
2154+
return; /* return NULL */
2155+
}
2156+
2157+
data = &sxe->iter.data;
2158+
ZVAL_COPY_DEREF(return_value, data);
2159+
}
2160+
20272161
static zend_object_handlers sxe_object_handlers;
20282162

20292163
/* {{{ sxe_object_clone()
@@ -2617,13 +2751,14 @@ ZEND_GET_MODULE(simplexml)
26172751
*/
26182752
PHP_MINIT_FUNCTION(simplexml)
26192753
{
2620-
zend_class_entry sxe;
2754+
zend_class_entry ce;
26212755

2622-
INIT_CLASS_ENTRY(sxe, "SimpleXMLElement", class_SimpleXMLElement_methods);
2623-
sxe.create_object = sxe_object_new;
2624-
sxe_class_entry = zend_register_internal_class(&sxe);
2756+
INIT_CLASS_ENTRY(ce, "SimpleXMLElement", class_SimpleXMLElement_methods);
2757+
sxe_class_entry = zend_register_internal_class(&ce);
2758+
sxe_class_entry->create_object = sxe_object_new;
26252759
sxe_class_entry->get_iterator = php_sxe_get_iterator;
2626-
zend_class_implements(sxe_class_entry, 3, zend_ce_traversable, zend_ce_countable, zend_ce_stringable);
2760+
zend_class_implements(sxe_class_entry, 3,
2761+
zend_ce_countable, zend_ce_stringable, spl_ce_RecursiveIterator);
26272762

26282763
memcpy(&sxe_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
26292764
sxe_object_handlers.offset = XtOffsetOf(php_sxe_object, zo);
@@ -2650,9 +2785,13 @@ PHP_MINIT_FUNCTION(simplexml)
26502785
sxe_class_entry->serialize = zend_class_serialize_deny;
26512786
sxe_class_entry->unserialize = zend_class_unserialize_deny;
26522787

2653-
php_libxml_register_export(sxe_class_entry, simplexml_export_node);
2788+
/* TODO: Why do we have two variables for this? */
2789+
ce_SimpleXMLElement = sxe_class_entry;
26542790

2655-
PHP_MINIT(sxe)(INIT_FUNC_ARGS_PASSTHRU);
2791+
INIT_CLASS_ENTRY(ce, "SimpleXMLIterator", NULL);
2792+
ce_SimpleXMLIterator = zend_register_internal_class_ex(&ce, ce_SimpleXMLElement);
2793+
2794+
php_libxml_register_export(sxe_class_entry, simplexml_export_node);
26562795

26572796
return SUCCESS;
26582797
}

ext/simplexml/simplexml.stub.php

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ function simplexml_load_string(string $data, ?string $class_name = SimpleXMLElem
88

99
function simplexml_import_dom(DOMNode $node, ?string $class_name = SimpleXMLElement::class): ?SimpleXMLElement {}
1010

11-
class SimpleXMLElement implements Stringable
11+
class SimpleXMLElement implements Stringable, Countable, RecursiveIterator
1212
{
1313
/** @return array|false */
1414
public function xpath(string $path) {}
@@ -52,4 +52,29 @@ public function __toString(): string {}
5252

5353
/** @return int */
5454
public function count() {}
55+
56+
/** @return void */
57+
public function rewind() {}
58+
59+
/** @return bool */
60+
public function valid() {}
61+
62+
/** @return ?SimpleXMLElement */
63+
public function current() {}
64+
65+
/** @return string|false */
66+
public function key() {}
67+
68+
/** @return void */
69+
public function next() {}
70+
71+
/** @return bool */
72+
public function hasChildren() {}
73+
74+
/** @return ?SimpleXMLElement */
75+
public function getChildren() {}
76+
}
77+
78+
class SimpleXMLIterator extends SimpleXMLElement
79+
{
5580
}

ext/simplexml/simplexml_arginfo.h

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* This is a generated file, edit the .stub.php file instead.
2-
* Stub hash: f74d2fc54ca25216f1b54b0776c480d5e8d297fb */
2+
* Stub hash: 7b3ff8b991fc7e424aaf1e86cfbebe662a30c48f */
33

44
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_simplexml_load_file, 0, 1, SimpleXMLElement, MAY_BE_FALSE)
55
ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0)
@@ -77,6 +77,20 @@ ZEND_END_ARG_INFO()
7777

7878
#define arginfo_class_SimpleXMLElement_count arginfo_class_SimpleXMLElement_getName
7979

80+
#define arginfo_class_SimpleXMLElement_rewind arginfo_class_SimpleXMLElement_getName
81+
82+
#define arginfo_class_SimpleXMLElement_valid arginfo_class_SimpleXMLElement_getName
83+
84+
#define arginfo_class_SimpleXMLElement_current arginfo_class_SimpleXMLElement_getName
85+
86+
#define arginfo_class_SimpleXMLElement_key arginfo_class_SimpleXMLElement_getName
87+
88+
#define arginfo_class_SimpleXMLElement_next arginfo_class_SimpleXMLElement_getName
89+
90+
#define arginfo_class_SimpleXMLElement_hasChildren arginfo_class_SimpleXMLElement_getName
91+
92+
#define arginfo_class_SimpleXMLElement_getChildren arginfo_class_SimpleXMLElement_getName
93+
8094

8195
ZEND_FUNCTION(simplexml_load_file);
8296
ZEND_FUNCTION(simplexml_load_string);
@@ -94,6 +108,13 @@ ZEND_METHOD(SimpleXMLElement, addAttribute);
94108
ZEND_METHOD(SimpleXMLElement, getName);
95109
ZEND_METHOD(SimpleXMLElement, __toString);
96110
ZEND_METHOD(SimpleXMLElement, count);
111+
ZEND_METHOD(SimpleXMLElement, rewind);
112+
ZEND_METHOD(SimpleXMLElement, valid);
113+
ZEND_METHOD(SimpleXMLElement, current);
114+
ZEND_METHOD(SimpleXMLElement, key);
115+
ZEND_METHOD(SimpleXMLElement, next);
116+
ZEND_METHOD(SimpleXMLElement, hasChildren);
117+
ZEND_METHOD(SimpleXMLElement, getChildren);
97118

98119

99120
static const zend_function_entry ext_functions[] = {
@@ -119,5 +140,17 @@ static const zend_function_entry class_SimpleXMLElement_methods[] = {
119140
ZEND_ME(SimpleXMLElement, getName, arginfo_class_SimpleXMLElement_getName, ZEND_ACC_PUBLIC)
120141
ZEND_ME(SimpleXMLElement, __toString, arginfo_class_SimpleXMLElement___toString, ZEND_ACC_PUBLIC)
121142
ZEND_ME(SimpleXMLElement, count, arginfo_class_SimpleXMLElement_count, ZEND_ACC_PUBLIC)
143+
ZEND_ME(SimpleXMLElement, rewind, arginfo_class_SimpleXMLElement_rewind, ZEND_ACC_PUBLIC)
144+
ZEND_ME(SimpleXMLElement, valid, arginfo_class_SimpleXMLElement_valid, ZEND_ACC_PUBLIC)
145+
ZEND_ME(SimpleXMLElement, current, arginfo_class_SimpleXMLElement_current, ZEND_ACC_PUBLIC)
146+
ZEND_ME(SimpleXMLElement, key, arginfo_class_SimpleXMLElement_key, ZEND_ACC_PUBLIC)
147+
ZEND_ME(SimpleXMLElement, next, arginfo_class_SimpleXMLElement_next, ZEND_ACC_PUBLIC)
148+
ZEND_ME(SimpleXMLElement, hasChildren, arginfo_class_SimpleXMLElement_hasChildren, ZEND_ACC_PUBLIC)
149+
ZEND_ME(SimpleXMLElement, getChildren, arginfo_class_SimpleXMLElement_getChildren, ZEND_ACC_PUBLIC)
150+
ZEND_FE_END
151+
};
152+
153+
154+
static const zend_function_entry class_SimpleXMLIterator_methods[] = {
122155
ZEND_FE_END
123156
};

0 commit comments

Comments
 (0)