Skip to content

[part of RFC] Add Dom\TokenList #13664

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 1 commit into from
Jul 2, 2024
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
1 change: 1 addition & 0 deletions ext/dom/config.m4
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ if test "$PHP_DOM" != "no"; then
documenttype.c entity.c \
nodelist.c html_collection.c text.c comment.c \
entityreference.c \
token_list.c \
notation.c xpath.c dom_iterators.c \
namednodemap.c xpath_callbacks.c \
$LEXBOR_SOURCES],
Expand Down
1 change: 1 addition & 0 deletions ext/dom/config.w32
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ if (PHP_DOM == "yes") {
node.c characterdata.c documenttype.c \
entity.c nodelist.c html_collection.c text.c comment.c \
entityreference.c \
token_list.c \
notation.c xpath.c dom_iterators.c \
namednodemap.c xpath_callbacks.c", null, "-Iext/dom/lexbor");

Expand Down
1 change: 1 addition & 0 deletions ext/dom/dom_ce.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ extern PHP_DOM_EXPORT zend_class_entry *dom_modern_entityreference_class_entry;
extern PHP_DOM_EXPORT zend_class_entry *dom_processinginstruction_class_entry;
extern PHP_DOM_EXPORT zend_class_entry *dom_modern_processinginstruction_class_entry;
extern PHP_DOM_EXPORT zend_class_entry *dom_abstract_base_document_class_entry;
extern PHP_DOM_EXPORT zend_class_entry *dom_token_list_class_entry;
#ifdef LIBXML_XPATH_ENABLED
extern PHP_DOM_EXPORT zend_class_entry *dom_xpath_class_entry;
extern PHP_DOM_EXPORT zend_class_entry *dom_modern_xpath_class_entry;
Expand Down
6 changes: 6 additions & 0 deletions ext/dom/dom_properties.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ zend_result dom_element_id_write(dom_object *obj, zval *newval);
zend_result dom_element_schema_type_info_read(dom_object *obj, zval *retval);
zend_result dom_element_inner_html_read(dom_object *obj, zval *retval);
zend_result dom_element_inner_html_write(dom_object *obj, zval *newval);
zend_result dom_element_class_list_read(dom_object *obj, zval *retval);

/* entity properties */
zend_result dom_entity_public_id_read(dom_object *obj, zval *retval);
Expand Down Expand Up @@ -148,6 +149,11 @@ zend_result dom_processinginstruction_data_write(dom_object *obj, zval *newval);
/* text properties */
zend_result dom_text_whole_text_read(dom_object *obj, zval *retval);

/* token_list properties */
zend_result dom_token_list_length_read(dom_object *obj, zval *retval);
zend_result dom_token_list_value_read(dom_object *obj, zval *retval);
zend_result dom_token_list_value_write(dom_object *obj, zval *newval);

#ifdef LIBXML_XPATH_ENABLED
/* xpath properties */
zend_result dom_xpath_document_read(dom_object *obj, zval *retval);
Expand Down
28 changes: 28 additions & 0 deletions ext/dom/element.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "namespace_compat.h"
#include "internal_helpers.h"
#include "dom_properties.h"
#include "token_list.h"

/*
* class DOMElement extends DOMNode
Expand Down Expand Up @@ -175,6 +176,33 @@ zend_result dom_element_class_name_write(dom_object *obj, zval *newval)
}
/* }}} */

/* {{{ classList TokenList
URL: https://dom.spec.whatwg.org/#dom-element-classlist
*/
zend_result dom_element_class_list_read(dom_object *obj, zval *retval)
{
const uint32_t PROP_INDEX = 20;

#if ZEND_DEBUG
zend_string *class_list_str = ZSTR_INIT_LITERAL("classList", false);
const zend_property_info *prop_info = zend_get_property_info(dom_modern_element_class_entry, class_list_str, 0);
zend_string_release_ex(class_list_str, false);
ZEND_ASSERT(OBJ_PROP_TO_NUM(prop_info->offset) == PROP_INDEX);
#endif

zval *cached_token_list = OBJ_PROP_NUM(&obj->std, PROP_INDEX);
if (Z_ISUNDEF_P(cached_token_list)) {
object_init_ex(cached_token_list, dom_token_list_class_entry);
dom_token_list_object *intern = php_dom_token_list_from_obj(Z_OBJ_P(cached_token_list));
dom_token_list_ctor(intern, obj);
}

ZVAL_OBJ_COPY(retval, Z_OBJ_P(cached_token_list));

return SUCCESS;
}
/* }}} */

/* {{{ id string
URL: https://dom.spec.whatwg.org/#dom-element-id
Since:
Expand Down
39 changes: 38 additions & 1 deletion ext/dom/php_dom.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "internal_helpers.h"
#include "php_dom_arginfo.h"
#include "dom_properties.h"
#include "token_list.h"
#include "zend_interfaces.h"
#include "lexbor/lexbor/core/types.h"
#include "lexbor/lexbor/core/lexbor.h"
Expand Down Expand Up @@ -81,6 +82,7 @@ PHP_DOM_EXPORT zend_class_entry *dom_modern_entityreference_class_entry;
PHP_DOM_EXPORT zend_class_entry *dom_processinginstruction_class_entry;
PHP_DOM_EXPORT zend_class_entry *dom_modern_processinginstruction_class_entry;
PHP_DOM_EXPORT zend_class_entry *dom_abstract_base_document_class_entry;
PHP_DOM_EXPORT zend_class_entry *dom_token_list_class_entry;
#ifdef LIBXML_XPATH_ENABLED
PHP_DOM_EXPORT zend_class_entry *dom_xpath_class_entry;
PHP_DOM_EXPORT zend_class_entry *dom_modern_xpath_class_entry;
Expand All @@ -97,6 +99,7 @@ static zend_object_handlers dom_modern_nodelist_object_handlers;
static zend_object_handlers dom_html_collection_object_handlers;
static zend_object_handlers dom_object_namespace_node_handlers;
static zend_object_handlers dom_modern_domimplementation_object_handlers;
static zend_object_handlers dom_token_list_object_handlers;
#ifdef LIBXML_XPATH_ENABLED
zend_object_handlers dom_xpath_object_handlers;
#endif
Expand Down Expand Up @@ -132,6 +135,7 @@ static HashTable dom_modern_entity_prop_handlers;
static HashTable dom_processinginstruction_prop_handlers;
static HashTable dom_modern_processinginstruction_prop_handlers;
static HashTable dom_namespace_node_prop_handlers;
static HashTable dom_token_list_prop_handlers;
#ifdef LIBXML_XPATH_ENABLED
static HashTable dom_xpath_prop_handlers;
#endif
Expand Down Expand Up @@ -633,6 +637,18 @@ static zend_object *dom_object_namespace_node_clone_obj(zend_object *zobject)
return clone;
}

static zend_object *dom_token_list_new(zend_class_entry *class_type)
{
dom_token_list_object *intern = zend_object_alloc(sizeof(*intern), class_type);

intern->dom.prop_handler = &dom_token_list_prop_handlers;

zend_object_std_init(&intern->dom.std, class_type);
object_properties_init(&intern->dom.std, class_type);

return &intern->dom.std;
}

static const zend_module_dep dom_deps[] = {
ZEND_MOD_REQUIRED("libxml")
ZEND_MOD_CONFLICTS("domxml")
Expand All @@ -658,7 +674,6 @@ zend_module_entry dom_module_entry = { /* {{{ */
ZEND_GET_MODULE(dom)
#endif

void dom_objects_free_storage(zend_object *object);
void dom_nnodemap_objects_free_storage(zend_object *object);
static zval *dom_nodelist_read_dimension(zend_object *object, zval *offset, int type, zval *rv);
static int dom_nodelist_has_dimension(zend_object *object, zval *member, int check_empty);
Expand Down Expand Up @@ -732,6 +747,16 @@ PHP_MINIT_FUNCTION(dom)
dom_object_namespace_node_handlers.free_obj = dom_object_namespace_node_free_storage;
dom_object_namespace_node_handlers.clone_obj = dom_object_namespace_node_clone_obj;

memcpy(&dom_token_list_object_handlers, &dom_object_handlers, sizeof(zend_object_handlers));
dom_token_list_object_handlers.offset = XtOffsetOf(dom_token_list_object, dom.std);
dom_token_list_object_handlers.free_obj = dom_token_list_free_obj;
/* The Web IDL (Web Interface Description Language - https://webidl.spec.whatwg.org) has the [SameObject] constraint
* for this object, which is incompatible with cloning because it imposes that there is only one instance
* per parent object. */
dom_token_list_object_handlers.clone_obj = NULL;
dom_token_list_object_handlers.read_dimension = dom_token_list_read_dimension;
dom_token_list_object_handlers.has_dimension = dom_token_list_has_dimension;

zend_hash_init(&classes, 0, NULL, NULL, true);

dom_adjacent_position_class_entry = register_class_Dom_AdjacentPosition();
Expand Down Expand Up @@ -1033,6 +1058,7 @@ PHP_MINIT_FUNCTION(dom)
DOM_REGISTER_PROP_HANDLER(&dom_modern_element_prop_handlers, "tagName", dom_element_tag_name_read, NULL);
DOM_REGISTER_PROP_HANDLER(&dom_modern_element_prop_handlers, "id", dom_element_id_read, dom_element_id_write);
DOM_REGISTER_PROP_HANDLER(&dom_modern_element_prop_handlers, "className", dom_element_class_name_read, dom_element_class_name_write);
DOM_REGISTER_PROP_HANDLER(&dom_modern_element_prop_handlers, "classList", dom_element_class_list_read, NULL);
DOM_REGISTER_PROP_HANDLER(&dom_modern_element_prop_handlers, "attributes", dom_node_attributes_read, NULL);
DOM_REGISTER_PROP_HANDLER(&dom_modern_element_prop_handlers, "firstElementChild", dom_parent_node_first_element_child_read, NULL);
DOM_REGISTER_PROP_HANDLER(&dom_modern_element_prop_handlers, "lastElementChild", dom_parent_node_last_element_child_read, NULL);
Expand Down Expand Up @@ -1227,6 +1253,16 @@ PHP_MINIT_FUNCTION(dom)
zend_hash_add_new_ptr(&classes, dom_modern_xpath_class_entry->name, &dom_xpath_prop_handlers);
#endif

dom_token_list_class_entry = register_class_Dom_TokenList(zend_ce_aggregate, zend_ce_countable);
dom_token_list_class_entry->create_object = dom_token_list_new;
dom_token_list_class_entry->default_object_handlers = &dom_token_list_object_handlers;
dom_token_list_class_entry->get_iterator = dom_token_list_get_iterator;

zend_hash_init(&dom_token_list_prop_handlers, 0, NULL, NULL, true);
DOM_REGISTER_PROP_HANDLER(&dom_token_list_prop_handlers, "length", dom_token_list_length_read, NULL);
DOM_REGISTER_PROP_HANDLER(&dom_token_list_prop_handlers, "value", dom_token_list_value_read, dom_token_list_value_write);
zend_hash_add_new_ptr(&classes, dom_token_list_class_entry->name, &dom_token_list_prop_handlers);

register_php_dom_symbols(module_number);

php_libxml_register_export(dom_node_class_entry, php_dom_export_node);
Expand Down Expand Up @@ -1292,6 +1328,7 @@ PHP_MSHUTDOWN_FUNCTION(dom) /* {{{ */
zend_hash_destroy(&dom_modern_entity_prop_handlers);
zend_hash_destroy(&dom_processinginstruction_prop_handlers);
zend_hash_destroy(&dom_modern_processinginstruction_prop_handlers);
zend_hash_destroy(&dom_token_list_prop_handlers);
#ifdef LIBXML_XPATH_ENABLED
zend_hash_destroy(&dom_xpath_prop_handlers);
#endif
Expand Down
9 changes: 2 additions & 7 deletions ext/dom/php_dom.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ static inline dom_object_namespace_node *php_dom_namespace_node_obj_from_obj(zen

#define DOM_HTML_NO_DEFAULT_NS (1U << 31)

void dom_objects_free_storage(zend_object *object);
dom_doc_propsptr dom_get_doc_props(php_libxml_ref_obj *document);
libxml_doc_props const* dom_get_doc_props_read_only(const php_libxml_ref_obj *document);
zend_object *dom_objects_new(zend_class_entry *class_type);
Expand Down Expand Up @@ -230,14 +231,8 @@ xmlNodePtr dom_clone_node(php_dom_libxml_ns_mapper *ns_mapper, xmlNodePtr node,

static zend_always_inline bool php_dom_is_cache_tag_stale_from_doc_ptr(const php_libxml_cache_tag *cache_tag, const php_libxml_ref_obj *doc_ptr)
{
ZEND_ASSERT(cache_tag != NULL);
ZEND_ASSERT(doc_ptr != NULL);
/* See overflow comment in php_libxml_invalidate_node_list_cache(). */
#if SIZEOF_SIZE_T == 8
return cache_tag->modification_nr != doc_ptr->cache_tag.modification_nr;
#else
return cache_tag->modification_nr != doc_ptr->cache_tag.modification_nr || UNEXPECTED(doc_ptr->cache_tag.modification_nr == SIZE_MAX);
#endif
return php_libxml_is_cache_tag_stale(cache_tag, &doc_ptr->cache_tag);
}

static zend_always_inline bool php_dom_is_cache_tag_stale_from_node(const php_libxml_cache_tag *cache_tag, const xmlNodePtr node)
Expand Down
27 changes: 27 additions & 0 deletions ext/dom/php_dom.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -1304,6 +1304,8 @@ class Element extends Node implements ParentNode, ChildNode

public string $id;
public string $className;
/** @readonly */
public TokenList $classList;

/** @implementation-alias DOMNode::hasAttributes */
public function hasAttributes(): bool {}
Expand Down Expand Up @@ -1661,6 +1663,31 @@ public function saveXml(?Node $node = null, int $options = 0): string|false {}
public function saveXmlFile(string $filename, int $options = 0): int|false {}
}

/**
* @not-serializable
* @strict-properties
*/
final class TokenList implements IteratorAggregate, Countable
{
/** @implementation-alias Dom\Node::__construct */
private function __construct() {}

/** @readonly */
public int $length;
public function item(int $index): ?string {}
public function contains(string $token): bool {}
public function add(string ...$tokens): void {}
public function remove(string ...$tokens): void {}
public function toggle(string $token, ?bool $force = null): bool {}
public function replace(string $token, string $newToken): bool {}
public function supports(string $token): bool {}
public string $value;

public function count(): int {}

public function getIterator(): \Iterator {}
}

#ifdef LIBXML_XPATH_ENABLED
/** @not-serializable */
final class XPath
Expand Down
88 changes: 87 additions & 1 deletion ext/dom/php_dom_arginfo.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading