From ec9a20d502e191c8c84f32acaf08316ed172c6c3 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+ndossche@users.noreply.github.com> Date: Sun, 2 Nov 2025 23:37:23 +0100 Subject: [PATCH] dom: Optimize splitText() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This avoids duplicating the intermediate strings, by transferring ownership. It's hard to measure the improvement in a reliable way, as we have to operate on the same node. The following benchmark shows a nice improvement (although not perfect as a benchmark): ```php loadXML('testabcdef'); $text = $dom->documentElement->firstChild; for ($i = 0; $i < 1000000; $i++) { $text2 = clone $text; $text2->splitText(5); } ``` Only tested on my desktop i7-4790: ``` Benchmark 1: ./sapi/cli/php x.php Time (mean ± σ): 284.1 ms ± 2.8 ms [User: 280.0 ms, System: 3.0 ms] Range (min … max): 281.4 ms … 291.3 ms 10 runs Benchmark 2: ./sapi/cli/php_old x.php Time (mean ± σ): 314.0 ms ± 7.8 ms [User: 309.2 ms, System: 2.9 ms] Range (min … max): 306.5 ms … 328.0 ms 10 runs Summary ./sapi/cli/php x.php ran 1.11 ± 0.03 times faster than ./sapi/cli/php_old x.php ``` --- UPGRADING | 3 +++ ext/dom/text.c | 11 ++++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/UPGRADING b/UPGRADING index eb158460cefb7..a3c0bdd353f5c 100644 --- a/UPGRADING +++ b/UPGRADING @@ -111,5 +111,8 @@ PHP 8.6 UPGRADE NOTES . Arguments are now passed more efficiently to known constructors (e.g. when using new self()). +- DOM: + . Made splitText() faster and consume less memory. + - JSON: . Improve performance of encoding arrays and objects. diff --git a/ext/dom/text.c b/ext/dom/text.c index ca8fcf63d3aca..1138294c8a3ea 100644 --- a/ext/dom/text.c +++ b/ext/dom/text.c @@ -129,17 +129,18 @@ PHP_METHOD(DOMText, splitText) first = xmlUTF8Strndup(cur, (int)offset); second = xmlUTF8Strsub(cur, (int)offset, (int)(length - offset)); - xmlNodeSetContent(node, first); - nnode = xmlNewDocText(node->doc, second); - - xmlFree(first); - xmlFree(second); + xmlNodeSetContent(node, NULL); + node->content = first; + nnode = xmlNewDocText(node->doc, NULL); if (nnode == NULL) { + xmlFree(second); php_dom_throw_error(INVALID_STATE_ERR, /* strict */ true); RETURN_THROWS(); } + nnode->content = second; + if (node->parent != NULL) { nnode->type = XML_ELEMENT_NODE; xmlAddNextSibling(node, nnode);