Skip to content

Further cleanup of DOM mapping APIs #18894

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

Merged
merged 4 commits into from
Jun 22, 2025
Merged
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
5 changes: 3 additions & 2 deletions ext/dom/documenttype.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "php.h"
#if defined(HAVE_LIBXML) && defined(HAVE_DOM)
#include "php_dom.h"
#include "obj_map.h"
#include "dom_properties.h"
#include "internal_helpers.h"

Expand Down Expand Up @@ -53,7 +54,7 @@ zend_result dom_documenttype_entities_read(dom_object *obj, zval *retval)
xmlHashTable *entityht = (xmlHashTable *) dtdptr->entities;

dom_object *intern = Z_DOMOBJ_P(retval);
dom_namednode_iter(obj, intern, entityht, NULL, NULL, &php_dom_obj_map_entities);
php_dom_create_obj_map(obj, intern, entityht, NULL, NULL, &php_dom_obj_map_entities);

return SUCCESS;
}
Expand All @@ -74,7 +75,7 @@ zend_result dom_documenttype_notations_read(dom_object *obj, zval *retval)
xmlHashTable *notationht = (xmlHashTable *) dtdptr->notations;

dom_object *intern = Z_DOMOBJ_P(retval);
dom_namednode_iter(obj, intern, notationht, NULL, NULL, &php_dom_obj_map_notations);
php_dom_create_obj_map(obj, intern, notationht, NULL, NULL, &php_dom_obj_map_notations);

return SUCCESS;
}
Expand Down
2 changes: 1 addition & 1 deletion ext/dom/dom_iterators.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#include "php.h"
#if defined(HAVE_LIBXML) && defined(HAVE_DOM)
#include "php_dom.h"
#include "dom_ce.h"
#include "obj_map.h"

typedef struct nodeIterator {
int cur;
Expand Down
6 changes: 3 additions & 3 deletions ext/dom/element.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
#if defined(HAVE_LIBXML) && defined(HAVE_DOM)
#include "zend_enum.h"
#include "php_dom.h"
#include "obj_map.h"
#include "namespace_compat.h"
#include "private_data.h"
#include "internal_helpers.h"
#include "dom_properties.h"
#include "token_list.h"
Expand Down Expand Up @@ -825,7 +825,7 @@ static void dom_element_get_elements_by_tag_name(INTERNAL_FUNCTION_PARAMETERS, z

object_init_ex(return_value, iter_ce);
namednode = Z_DOMOBJ_P(return_value);
dom_namednode_iter(intern, namednode, NULL, name, NULL, &php_dom_obj_map_by_tag_name);
php_dom_create_obj_map(intern, namednode, NULL, name, NULL, &php_dom_obj_map_by_tag_name);
}

PHP_METHOD(DOMElement, getElementsByTagName)
Expand Down Expand Up @@ -1257,7 +1257,7 @@ static void dom_element_get_elements_by_tag_name_ns(INTERNAL_FUNCTION_PARAMETERS

object_init_ex(return_value, iter_ce);
namednode = Z_DOMOBJ_P(return_value);
dom_namednode_iter(intern, namednode, NULL, name, uri, &php_dom_obj_map_by_tag_name);
php_dom_create_obj_map(intern, namednode, NULL, name, uri, &php_dom_obj_map_by_tag_name);
}

PHP_METHOD(DOMElement, getElementsByTagNameNS)
Expand Down
3 changes: 2 additions & 1 deletion ext/dom/html_collection.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "php.h"
#if defined(HAVE_LIBXML) && defined(HAVE_DOM)
#include "php_dom.h"
#include "obj_map.h"
#include "nodelist.h"
#include "html_collection.h"
#include "namespace_compat.h"
Expand Down Expand Up @@ -115,7 +116,7 @@ zval *dom_html_collection_read_dimension(zend_object *object, zval *offset, int
dom_html_collection_named_item_into_zval(rv, index.str, object);
} else {
ZEND_ASSERT(index.type == DOM_NODELIST_DIM_LONG);
php_dom_nodelist_get_item_into_zval(php_dom_obj_from_obj(object)->ptr, index.lval, rv);
php_dom_obj_map_get_item_into_zval(php_dom_obj_from_obj(object)->ptr, index.lval, rv);
}

return rv;
Expand Down
15 changes: 3 additions & 12 deletions ext/dom/namednodemap.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "php.h"
#if defined(HAVE_LIBXML) && defined(HAVE_DOM)
#include "php_dom.h"
#include "obj_map.h"
#include "zend_interfaces.h"

/*
Expand Down Expand Up @@ -54,16 +55,6 @@ zend_result dom_namednodemap_length_read(dom_object *obj, zval *retval)

/* }}} */

void php_dom_named_node_map_get_named_item_into_zval(dom_nnodemap_object *objmap, const zend_string *named, const char *ns, zval *return_value)
{
xmlNodePtr itemnode = objmap->handler->get_named_item(objmap, named, ns);
if (itemnode) {
DOM_RET_OBJ(itemnode, objmap->baseobj);
} else {
RETURN_NULL();
}
}

/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-1074577549
Since:
*/
Expand All @@ -76,7 +67,7 @@ PHP_METHOD(DOMNamedNodeMap, getNamedItem)
}

dom_nnodemap_object *objmap = Z_DOMOBJ_P(ZEND_THIS)->ptr;
php_dom_named_node_map_get_named_item_into_zval(objmap, named, NULL, return_value);
php_dom_obj_map_get_named_item_into_zval(objmap, named, NULL, return_value);
}
/* }}} end dom_namednodemap_get_named_item */

Expand Down Expand Up @@ -121,7 +112,7 @@ PHP_METHOD(DOMNamedNodeMap, getNamedItemNS)
objmap = (dom_nnodemap_object *)intern->ptr;

if (objmap != NULL) {
php_dom_named_node_map_get_named_item_into_zval(objmap, named, uri, return_value);
php_dom_obj_map_get_named_item_into_zval(objmap, named, uri, return_value);
}
}
/* }}} end dom_namednodemap_get_named_item_ns */
Expand Down
5 changes: 3 additions & 2 deletions ext/dom/node.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "php.h"
#if defined(HAVE_LIBXML) && defined(HAVE_DOM)
#include "php_dom.h"
#include "obj_map.h"
#include "namespace_compat.h"
#include "private_data.h"
#include "internal_helpers.h"
Expand Down Expand Up @@ -288,7 +289,7 @@ zend_result dom_node_child_nodes_read(dom_object *obj, zval *retval)

object_init_ex(retval, dom_get_nodelist_ce(php_dom_follow_spec_intern(obj)));
dom_object *intern = Z_DOMOBJ_P(retval);
dom_namednode_iter(obj, intern, NULL, NULL, NULL, &php_dom_obj_map_child_nodes);
php_dom_create_obj_map(obj, intern, NULL, NULL, NULL, &php_dom_obj_map_child_nodes);

return SUCCESS;
}
Expand Down Expand Up @@ -422,7 +423,7 @@ zend_result dom_node_attributes_read(dom_object *obj, zval *retval)
if (nodep->type == XML_ELEMENT_NODE) {
object_init_ex(retval, dom_get_namednodemap_ce(php_dom_follow_spec_intern(obj)));
dom_object *intern = Z_DOMOBJ_P(retval);
dom_namednode_iter(obj, intern, NULL, NULL, NULL, &php_dom_obj_map_attributes);
php_dom_create_obj_map(obj, intern, NULL, NULL, NULL, &php_dom_obj_map_attributes);
} else {
ZVAL_NULL(retval);
}
Expand Down
14 changes: 3 additions & 11 deletions ext/dom/nodelist.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "php.h"
#if defined(HAVE_LIBXML) && defined(HAVE_DOM)
#include "php_dom.h"
#include "obj_map.h"
#include "nodelist.h"
#include "zend_interfaces.h"

Expand Down Expand Up @@ -63,15 +64,6 @@ PHP_METHOD(DOMNodeList, count)
}
/* }}} end dom_nodelist_count */

void php_dom_nodelist_get_item_into_zval(dom_nnodemap_object *objmap, zend_long index, zval *return_value)
{
if (EXPECTED(objmap)) {
objmap->handler->get_item(objmap, index, return_value);
} else {
RETURN_NULL();
}
}

/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#ID-844377136
Since:
*/
Expand All @@ -85,7 +77,7 @@ PHP_METHOD(DOMNodeList, item)
zval *id = ZEND_THIS;
dom_object *intern = Z_DOMOBJ_P(id);
dom_nnodemap_object *objmap = intern->ptr;
php_dom_nodelist_get_item_into_zval(objmap, index, return_value);
php_dom_obj_map_get_item_into_zval(objmap, index, return_value);
}
/* }}} end dom_nodelist_item */

Expand Down Expand Up @@ -136,7 +128,7 @@ zval *dom_modern_nodelist_read_dimension(zend_object *object, zval *offset, int
return NULL;
}

php_dom_nodelist_get_item_into_zval(php_dom_obj_from_obj(object)->ptr, index.lval, rv);
php_dom_obj_map_get_item_into_zval(php_dom_obj_from_obj(object)->ptr, index.lval, rv);
return rv;
}

Expand Down
2 changes: 0 additions & 2 deletions ext/dom/nodelist.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ typedef struct dom_nodelist_dimension_index {
enum dom_nodelist_dimension_index_type type;
} dom_nodelist_dimension_index;

void php_dom_nodelist_get_item_into_zval(dom_nnodemap_object *objmap, zend_long index, zval *return_value);
zend_long php_dom_get_nodelist_length(dom_object *obj);
dom_nodelist_dimension_index dom_modern_nodelist_get_index(const zval *offset);
zval *dom_modern_nodelist_read_dimension(zend_object *object, zval *offset, int type, zval *rv);
int dom_modern_nodelist_has_dimension(zend_object *object, zval *member, int check_empty);
Expand Down
67 changes: 63 additions & 4 deletions ext/dom/obj_map.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,7 @@ static zend_long dom_map_get_xmlht_length(dom_nnodemap_object *map)

static zend_long dom_map_get_nodeset_length(dom_nnodemap_object *map)
{
HashTable *nodeht = Z_ARRVAL(map->baseobj_zv);
return zend_hash_num_elements(nodeht);
return zend_hash_num_elements(map->array);
}

static zend_long dom_map_get_prop_length(dom_nnodemap_object *map)
Expand Down Expand Up @@ -132,8 +131,7 @@ static void dom_map_get_notation_item(dom_nnodemap_object *map, zend_long index,

static void dom_map_get_nodeset_item(dom_nnodemap_object *map, zend_long index, zval *return_value)
{
HashTable *nodeht = Z_ARRVAL(map->baseobj_zv);
zval *entry = zend_hash_index_find(nodeht, index);
zval *entry = zend_hash_index_find(map->array, index);
if (entry) {
RETURN_COPY(entry);
} else {
Expand Down Expand Up @@ -288,6 +286,67 @@ zend_long php_dom_get_nodelist_length(dom_object *obj)
return count;
}

void php_dom_create_obj_map(dom_object *basenode, dom_object *intern, xmlHashTablePtr ht, zend_string *local, zend_string *ns, const php_dom_obj_map_handler *handler)
{
dom_nnodemap_object *mapptr = intern->ptr;

ZEND_ASSERT(basenode != NULL);

GC_ADDREF(&basenode->std);

xmlDocPtr doc = basenode->document ? basenode->document->ptr : NULL;

mapptr->handler = handler;
mapptr->baseobj = basenode;
mapptr->ht = ht;
if (EXPECTED(doc != NULL)) {
mapptr->dict = doc->dict;
xmlDictReference(doc->dict);
}

const xmlChar* tmp;

if (local) {
int len = (int) ZSTR_LEN(local);
if (doc != NULL && (tmp = xmlDictExists(doc->dict, (const xmlChar *)ZSTR_VAL(local), len)) != NULL) {
mapptr->local = BAD_CAST tmp;
} else {
mapptr->local = BAD_CAST ZSTR_VAL(zend_string_copy(local));
mapptr->release_local = true;
}
mapptr->local_lower = zend_string_tolower(local);
}

if (ns) {
int len = (int) ZSTR_LEN(ns);
if (doc != NULL && (tmp = xmlDictExists(doc->dict, (const xmlChar *)ZSTR_VAL(ns), len)) != NULL) {
mapptr->ns = BAD_CAST tmp;
} else {
mapptr->ns = BAD_CAST ZSTR_VAL(zend_string_copy(ns));
mapptr->release_ns = true;
}
}
}

void php_dom_obj_map_get_item_into_zval(dom_nnodemap_object *objmap, zend_long index, zval *return_value)
{
if (EXPECTED(objmap)) {
objmap->handler->get_item(objmap, index, return_value);
} else {
RETURN_NULL();
}
}

void php_dom_obj_map_get_named_item_into_zval(dom_nnodemap_object *objmap, const zend_string *named, const char *ns, zval *return_value)
{
xmlNodePtr itemnode = objmap->handler->get_named_item(objmap, named, ns);
if (itemnode) {
DOM_RET_OBJ(itemnode, objmap->baseobj);
} else {
RETURN_NULL();
}
}

/**********************
* === Named item === *
**********************/
Expand Down
39 changes: 33 additions & 6 deletions ext/dom/obj_map.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,41 @@
typedef struct dom_nnodemap_object dom_nnodemap_object;

typedef struct php_dom_obj_map_handler {
zend_long (*length)(dom_nnodemap_object *);
void (*get_item)(dom_nnodemap_object *, zend_long, zval *);
xmlNodePtr (*get_named_item)(dom_nnodemap_object *, const zend_string *, const char *);
bool (*has_named_item)(dom_nnodemap_object *, const zend_string *, const char *);
bool use_cache;
bool nameless;
zend_long (*length)(dom_nnodemap_object *);
void (*get_item)(dom_nnodemap_object *, zend_long, zval *);
xmlNodePtr (*get_named_item)(dom_nnodemap_object *, const zend_string *, const char *);
bool (*has_named_item)(dom_nnodemap_object *, const zend_string *, const char *);
bool use_cache;
bool nameless;
} php_dom_obj_map_handler;

typedef struct dom_nnodemap_object {
dom_object *baseobj;
zend_long cached_length;
union {
xmlHashTable *ht;
HashTable *array;
struct {
xmlChar *local;
zend_string *local_lower;
xmlChar *ns;
};
};
php_libxml_cache_tag cache_tag;
dom_object *cached_obj;
zend_long cached_obj_index;
xmlDictPtr dict;
const php_dom_obj_map_handler *handler;
bool release_local;
bool release_ns;
bool release_array;
} dom_nnodemap_object;

void php_dom_create_obj_map(dom_object *basenode, dom_object *intern, xmlHashTablePtr ht, zend_string *local, zend_string *ns, const php_dom_obj_map_handler *handler);
void php_dom_obj_map_get_named_item_into_zval(dom_nnodemap_object *objmap, const zend_string *named, const char *ns, zval *return_value);
void php_dom_obj_map_get_item_into_zval(dom_nnodemap_object *objmap, zend_long index, zval *return_value);
zend_long php_dom_get_nodelist_length(dom_object *obj);

extern const php_dom_obj_map_handler php_dom_obj_map_attributes;
extern const php_dom_obj_map_handler php_dom_obj_map_by_tag_name;
extern const php_dom_obj_map_handler php_dom_obj_map_child_nodes;
Expand Down
4 changes: 3 additions & 1 deletion ext/dom/parentnode/css_selectors.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "php.h"
#if defined(HAVE_LIBXML) && defined(HAVE_DOM)
#include "../php_dom.h"
#include "../obj_map.h"

#include "ext/lexbor/lexbor/css/parser.h"
#include "../lexbor/selectors-adapted/selectors.h"
Expand Down Expand Up @@ -248,7 +249,8 @@ void dom_parent_node_query_selector_all(xmlNodePtr thisp, dom_object *intern, zv
object_init_ex(return_value, dom_modern_nodelist_class_entry);
dom_object *ret_obj = Z_DOMOBJ_P(return_value);
dom_nnodemap_object *mapptr = (dom_nnodemap_object *) ret_obj->ptr;
ZVAL_ARR(&mapptr->baseobj_zv, list);
mapptr->array = list;
mapptr->release_array = true;
mapptr->handler = &php_dom_obj_map_nodeset;
}
}
Expand Down
Loading