Skip to content

Every inst() deep-copies the match set, so each find() from the root copies the whole document #137

Open

Description

@gravitypdf-bot

Problem

Every method that returns a new object goes through DOMQuery::inst(), which does clone $this. __clone() calls cloneAll(), which deep-copies (cloneNode(true)) every node in the match set. inst() then immediately replaces the match set, so the copies are thrown away.

For the usual qp($doc)->find(...) the match set is the document element, so each find() copies the whole document first. On a document of <p><i>x</i><b>y</b></p> × n, PHP 8.5:

n qp($x)->find('#nope') cloneNode(true) of the root DOMTraverser alone
1,000 1.15 ms 0.25 ms 0.59 ms
10,000 8.97 ms 2.46 ms 6.06 ms
50,000 52.5 ms 12.7 ms 38.7 ms

The same copy happens on every chained call (children(), filter(), next(), eq(), …), sized by whatever is in the match set, and it allocates a second copy of the tree each time.

#127 had remove($selector) call DOMTraverser directly to avoid this. detach($selector) still pays it.

Proposal

Have inst() build the new object without going through __clone()'s deep copy (for example a shallow-copy helper, or a flag __clone() checks), and keep clone $qp deep-copying as documented. Check branch() and end() still behave the same.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions