Skip to content

Make SimpleXMLElement a RecursiveIterator #5234

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ext/simplexml/config.m4
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ if test "$PHP_SIMPLEXML" != "no"; then

PHP_SETUP_LIBXML(SIMPLEXML_SHARED_LIBADD, [
AC_DEFINE(HAVE_SIMPLEXML,1,[ ])
PHP_NEW_EXTENSION(simplexml, simplexml.c sxe.c, $ext_shared)
PHP_NEW_EXTENSION(simplexml, simplexml.c, $ext_shared)
PHP_INSTALL_HEADERS([ext/simplexml/php_simplexml.h ext/simplexml/php_simplexml_exports.h])
PHP_SUBST(SIMPLEXML_SHARED_LIBADD)
])
Expand Down
2 changes: 1 addition & 1 deletion ext/simplexml/config.w32
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ if (PHP_SIMPLEXML == "yes") {
ADD_EXTENSION_DEP('simplexml', 'libxml') &&
CHECK_HEADER_ADD_INCLUDE("libxml/tree.h", "CFLAGS_SIMPLEXML", PHP_PHP_BUILD + "\\include\\libxml2")
) {
EXTENSION("simplexml", "simplexml.c sxe.c");
EXTENSION("simplexml", "simplexml.c");
AC_DEFINE("HAVE_SIMPLEXML", 1, "Simple XML support");
if (!PHP_SIMPLEXML_SHARED) {
ADD_FLAG("CFLAGS_SIMPLEXML", "/D LIBXML_STATIC");
Expand Down
3 changes: 3 additions & 0 deletions ext/simplexml/php_simplexml.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ typedef struct {
# define PHP_SXE_API ZEND_API
#endif

extern PHP_SXE_API zend_class_entry *ce_SimpleXMLIterator;
extern PHP_SXE_API zend_class_entry *ce_SimpleXMLElement;

PHP_SXE_API zend_class_entry *sxe_get_element_class_entry();

#endif
155 changes: 147 additions & 8 deletions ext/simplexml/simplexml.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@
#include "simplexml_arginfo.h"
#include "zend_exceptions.h"
#include "zend_interfaces.h"
#include "sxe.h"
#include "ext/spl/spl_iterators.h"

zend_class_entry *sxe_class_entry = NULL;
PHP_SXE_API zend_class_entry *ce_SimpleXMLIterator;
PHP_SXE_API zend_class_entry *ce_SimpleXMLElement;

PHP_SXE_API zend_class_entry *sxe_get_element_class_entry() /* {{{ */
{
Expand Down Expand Up @@ -2024,6 +2026,138 @@ SXE_METHOD(count)
}
/* }}} */


/* {{{ proto void SimpleXMLElement::rewind()
Rewind to first element */
SXE_METHOD(rewind)
{
if (zend_parse_parameters_none() == FAILURE) {
RETURN_THROWS();
}

php_sxe_rewind_iterator(Z_SXEOBJ_P(ZEND_THIS));
}
/* }}} */

/* {{{ proto bool SimpleXMLElement::valid()
Check whether iteration is valid */
SXE_METHOD(valid)
{
php_sxe_object *sxe = Z_SXEOBJ_P(ZEND_THIS);

if (zend_parse_parameters_none() == FAILURE) {
RETURN_THROWS();
}

RETURN_BOOL(!Z_ISUNDEF(sxe->iter.data));
}
/* }}} */

/* {{{ proto SimpleXMLElement SimpleXMLElement::current()
Get current element */
SXE_METHOD(current)
{
php_sxe_object *sxe = Z_SXEOBJ_P(ZEND_THIS);
zval *data;

if (zend_parse_parameters_none() == FAILURE) {
RETURN_THROWS();
}

if (Z_ISUNDEF(sxe->iter.data)) {
return; /* return NULL */
}

data = &sxe->iter.data;
ZVAL_COPY_DEREF(return_value, data);
}
/* }}} */

/* {{{ proto string SimpleXMLElement::key()
Get name of current child element */
SXE_METHOD(key)
{
xmlNodePtr curnode;
php_sxe_object *intern;
php_sxe_object *sxe = Z_SXEOBJ_P(ZEND_THIS);

if (zend_parse_parameters_none() == FAILURE) {
RETURN_THROWS();
}

if (Z_ISUNDEF(sxe->iter.data)) {
RETURN_FALSE;
}

intern = Z_SXEOBJ_P(&sxe->iter.data);
if (intern != NULL && intern->node != NULL) {
curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->node)->node;
RETURN_STRINGL((char*)curnode->name, xmlStrlen(curnode->name));
}

RETURN_FALSE;
}
/* }}} */

/* {{{ proto void SimpleXMLElement::next()
Move to next element */
SXE_METHOD(next)
{
if (zend_parse_parameters_none() == FAILURE) {
RETURN_THROWS();
}

php_sxe_move_forward_iterator(Z_SXEOBJ_P(ZEND_THIS));
}
/* }}} */

/* {{{ proto bool SimpleXMLElement::hasChildren()
Check whether element has children (elements) */
SXE_METHOD(hasChildren)
{
php_sxe_object *sxe = Z_SXEOBJ_P(ZEND_THIS);
php_sxe_object *child;
xmlNodePtr node;

if (zend_parse_parameters_none() == FAILURE) {
RETURN_THROWS();
}

if (Z_ISUNDEF(sxe->iter.data) || sxe->iter.type == SXE_ITER_ATTRLIST) {
RETURN_FALSE;
}
child = Z_SXEOBJ_P(&sxe->iter.data);

GET_NODE(child, node);
if (node) {
node = node->children;
}
while (node && node->type != XML_ELEMENT_NODE) {
node = node->next;
}
RETURN_BOOL(node ? 1 : 0);
}
/* }}} */

/* {{{ proto SimpleXMLElement SimpleXMLElement::getChildren()
Get child element iterator */
SXE_METHOD(getChildren)
{
php_sxe_object *sxe = Z_SXEOBJ_P(ZEND_THIS);
zval *data;

if (zend_parse_parameters_none() == FAILURE) {
RETURN_THROWS();
}

if (Z_ISUNDEF(sxe->iter.data) || sxe->iter.type == SXE_ITER_ATTRLIST) {
return; /* return NULL */
}

data = &sxe->iter.data;
ZVAL_COPY_DEREF(return_value, data);
}

static zend_object_handlers sxe_object_handlers;

/* {{{ sxe_object_clone()
Expand Down Expand Up @@ -2606,13 +2740,14 @@ ZEND_GET_MODULE(simplexml)
*/
PHP_MINIT_FUNCTION(simplexml)
{
zend_class_entry sxe;
zend_class_entry ce;

INIT_CLASS_ENTRY(sxe, "SimpleXMLElement", class_SimpleXMLElement_methods);
sxe.create_object = sxe_object_new;
sxe_class_entry = zend_register_internal_class(&sxe);
INIT_CLASS_ENTRY(ce, "SimpleXMLElement", class_SimpleXMLElement_methods);
sxe_class_entry = zend_register_internal_class(&ce);
sxe_class_entry->create_object = sxe_object_new;
sxe_class_entry->get_iterator = php_sxe_get_iterator;
zend_class_implements(sxe_class_entry, 3, zend_ce_traversable, zend_ce_countable, zend_ce_stringable);
zend_class_implements(sxe_class_entry, 3,
zend_ce_countable, zend_ce_stringable, spl_ce_RecursiveIterator);

memcpy(&sxe_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
sxe_object_handlers.offset = XtOffsetOf(php_sxe_object, zo);
Expand All @@ -2639,9 +2774,13 @@ PHP_MINIT_FUNCTION(simplexml)
sxe_class_entry->serialize = zend_class_serialize_deny;
sxe_class_entry->unserialize = zend_class_unserialize_deny;

php_libxml_register_export(sxe_class_entry, simplexml_export_node);
/* TODO: Why do we have two variables for this? */
ce_SimpleXMLElement = sxe_class_entry;

PHP_MINIT(sxe)(INIT_FUNC_ARGS_PASSTHRU);
INIT_CLASS_ENTRY(ce, "SimpleXMLIterator", NULL);
ce_SimpleXMLIterator = zend_register_internal_class_ex(&ce, ce_SimpleXMLElement);

php_libxml_register_export(sxe_class_entry, simplexml_export_node);

return SUCCESS;
}
Expand Down
27 changes: 26 additions & 1 deletion ext/simplexml/simplexml.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ function simplexml_load_string(string $data, ?string $class_name = SimpleXMLElem

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

class SimpleXMLElement implements Stringable
class SimpleXMLElement implements Stringable, Countable, RecursiveIterator
{
/** @return array|false */
public function xpath(string $path) {}
Expand Down Expand Up @@ -52,4 +52,29 @@ public function __toString(): string {}

/** @return int */
public function count() {}

/** @return void */
public function rewind() {}

/** @return bool */
public function valid() {}

/** @return ?SimpleXMLElement */
public function current() {}

/** @return string|false */
public function key() {}

/** @return void */
public function next() {}

/** @return bool */
public function hasChildren() {}

/** @return ?SimpleXMLElement */
public function getChildren() {}
}

class SimpleXMLIterator extends SimpleXMLElement
{
}
33 changes: 33 additions & 0 deletions ext/simplexml/simplexml_arginfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,20 @@ ZEND_END_ARG_INFO()

#define arginfo_class_SimpleXMLElement_count arginfo_class_SimpleXMLElement_getName

#define arginfo_class_SimpleXMLElement_rewind arginfo_class_SimpleXMLElement_getName

#define arginfo_class_SimpleXMLElement_valid arginfo_class_SimpleXMLElement_getName

#define arginfo_class_SimpleXMLElement_current arginfo_class_SimpleXMLElement_getName

#define arginfo_class_SimpleXMLElement_key arginfo_class_SimpleXMLElement_getName

#define arginfo_class_SimpleXMLElement_next arginfo_class_SimpleXMLElement_getName

#define arginfo_class_SimpleXMLElement_hasChildren arginfo_class_SimpleXMLElement_getName

#define arginfo_class_SimpleXMLElement_getChildren arginfo_class_SimpleXMLElement_getName


ZEND_FUNCTION(simplexml_load_file);
ZEND_FUNCTION(simplexml_load_string);
Expand All @@ -93,6 +107,13 @@ ZEND_METHOD(SimpleXMLElement, addAttribute);
ZEND_METHOD(SimpleXMLElement, getName);
ZEND_METHOD(SimpleXMLElement, __toString);
ZEND_METHOD(SimpleXMLElement, count);
ZEND_METHOD(SimpleXMLElement, rewind);
ZEND_METHOD(SimpleXMLElement, valid);
ZEND_METHOD(SimpleXMLElement, current);
ZEND_METHOD(SimpleXMLElement, key);
ZEND_METHOD(SimpleXMLElement, next);
ZEND_METHOD(SimpleXMLElement, hasChildren);
ZEND_METHOD(SimpleXMLElement, getChildren);


static const zend_function_entry ext_functions[] = {
Expand All @@ -118,5 +139,17 @@ static const zend_function_entry class_SimpleXMLElement_methods[] = {
ZEND_ME(SimpleXMLElement, getName, arginfo_class_SimpleXMLElement_getName, ZEND_ACC_PUBLIC)
ZEND_ME(SimpleXMLElement, __toString, arginfo_class_SimpleXMLElement___toString, ZEND_ACC_PUBLIC)
ZEND_ME(SimpleXMLElement, count, arginfo_class_SimpleXMLElement_count, ZEND_ACC_PUBLIC)
ZEND_ME(SimpleXMLElement, rewind, arginfo_class_SimpleXMLElement_rewind, ZEND_ACC_PUBLIC)
ZEND_ME(SimpleXMLElement, valid, arginfo_class_SimpleXMLElement_valid, ZEND_ACC_PUBLIC)
ZEND_ME(SimpleXMLElement, current, arginfo_class_SimpleXMLElement_current, ZEND_ACC_PUBLIC)
ZEND_ME(SimpleXMLElement, key, arginfo_class_SimpleXMLElement_key, ZEND_ACC_PUBLIC)
ZEND_ME(SimpleXMLElement, next, arginfo_class_SimpleXMLElement_next, ZEND_ACC_PUBLIC)
ZEND_ME(SimpleXMLElement, hasChildren, arginfo_class_SimpleXMLElement_hasChildren, ZEND_ACC_PUBLIC)
ZEND_ME(SimpleXMLElement, getChildren, arginfo_class_SimpleXMLElement_getChildren, ZEND_ACC_PUBLIC)
ZEND_FE_END
};


static const zend_function_entry class_SimpleXMLIterator_methods[] = {
ZEND_FE_END
};
Loading