diff --git a/ext/dom/attr.c b/ext/dom/attr.c index e48d124976c..746ab4efa36 100644 --- a/ext/dom/attr.c +++ b/ext/dom/attr.c @@ -199,4 +199,34 @@ PHP_METHOD(DOMAttr, isId) } /* }}} end dom_attr_is_id */ +xmlChar *dom_attr_value(const xmlAttr *attr, bool *free) +{ + /* For attributes we can have an optimized fast-path. + * This fast-path is only possible in the (common) case where the attribute + * has a single text child. Note that if the child or the content is NULL, this + * is equivalent to not having content (i.e. the attribute has the empty string as value). */ + + *free = false; + + if (attr->children == NULL) { + return BAD_CAST ""; + } + + if (attr->children->type == XML_TEXT_NODE && attr->children->next == NULL) { + if (attr->children->content == NULL) { + return BAD_CAST ""; + } else { + return attr->children->content; + } + } + + xmlChar *value = xmlNodeGetContent((const xmlNode *) attr); + if (UNEXPECTED(value == NULL)) { + return BAD_CAST ""; + } + + *free = true; + return value; +} + #endif diff --git a/ext/dom/php_dom.c b/ext/dom/php_dom.c index dce9a0fb490..d7cb423cd78 100644 --- a/ext/dom/php_dom.c +++ b/ext/dom/php_dom.c @@ -2273,24 +2273,13 @@ void php_dom_get_content_into_zval(const xmlNode *nodep, zval *return_value, boo } case XML_ATTRIBUTE_NODE: { - /* For attributes we can also have an optimized fast-path. - * This fast-path is only possible in the (common) case where the attribute - * has a single text child. Note that if the child or the content is NULL, this - * is equivalent to not having content (i.e. the attribute has the empty string as value). */ - - if (nodep->children == NULL) { - RETURN_EMPTY_STRING(); + bool free; + xmlChar *value = dom_attr_value((const xmlAttr *) nodep, &free); + RETURN_STRING_FAST((const char *) value); + if (free) { + xmlFree(value); } - - if (nodep->children->type == XML_TEXT_NODE && nodep->children->next == NULL) { - if (nodep->children->content == NULL) { - RETURN_EMPTY_STRING(); - } else { - RETURN_STRING((const char *) nodep->children->content); - } - } - - ZEND_FALLTHROUGH; + return; } default: { diff --git a/ext/dom/php_dom.h b/ext/dom/php_dom.h index 26035832d95..0cd62a1afce 100644 --- a/ext/dom/php_dom.h +++ b/ext/dom/php_dom.h @@ -174,6 +174,8 @@ void dom_document_convert_to_modern(php_libxml_ref_obj *document, xmlDocPtr lxml dom_object *php_dom_instantiate_object_helper(zval *return_value, zend_class_entry *ce, xmlNodePtr obj, dom_object *parent); xmlDocPtr php_dom_create_html_doc(void); +xmlChar *dom_attr_value(const xmlAttr *attr, bool *free); + typedef enum { DOM_LOAD_STRING = 0, DOM_LOAD_FILE = 1,