Commit 540fd6e96bb for php.net
commit 540fd6e96bb12a466cb0e4ea4696fd1ad618ef7f
Author: Niels Dossche <7771979+ndossche@users.noreply.github.com>
Date: Mon Nov 3 18:46:56 2025 +0100
dom: Optimize splitText() (#20371)
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
<?php
$dom = new DOMDocument;
$dom->loadXML('<root>testabcdef</root>');
$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
```
diff --git a/UPGRADING b/UPGRADING
index f4a455caefa..7a3aff95da8 100644
--- a/UPGRADING
+++ b/UPGRADING
@@ -117,5 +117,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 b08619252b8..4c503201c8b 100644
--- a/ext/dom/text.c
+++ b/ext/dom/text.c
@@ -127,17 +127,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);