Skip to content

detach($selector) ignores its selector and detaches the current match set instead #76

Description

@jakejackson1

Guidelines

Description of the bug

detach($selector) is documented as detaching the elements matching $selector. The argument has no effect: the query runs, its result is thrown away, and whatever was already selected is detached instead.

This is silently destructive — $qp->detach('i') removes the $qp elements themselves rather than their i descendants.

Root cause

src/Helpers/QueryMutators.php:706-709 discards the return value of find():

public function detach($selector = null): Query
{
	if (null !== $selector) {
		$this->find($selector);      // <-- return value discarded
	}

	$found      = new SplObjectStorage();
	$this->last = $this->matches;
	foreach ($this->matches as $item) {

find() returns a new DOMQuery and leaves $this->matches untouched, so the loop below still iterates the original match set. findInPlace($selector) is the variant that was intended here.

Suggested fix

if (null !== $selector) {
	$this->findInPlace($selector);
}

Note that remove() — the sibling method — does honour its selector, so the two currently disagree.

Workaround

$qp->find($selector)->detach().

QueryPath version

4.2.0 (also reproduces on main at bed5d2c)

PHP Version and environment (server type, cli provider etc., enclosing libraries and their respective versions)

PHP 8.3.16 CLI (macOS, Homebrew). Not PHP-8 specific — the cause is present on every supported version.

Minimal reproducible PHP+HTML snippet to replicate bug

<?php
require __DIR__ . '/vendor/autoload.php';

$xml = '<?xml version="1.0"?><root><p><i>a</i></p></root>';

$qp = qp($xml, 'p');
$removed = $qp->detach('i');

var_dump($removed->tag());         // 'p'       - expected 'i'
var_dump($qp->top()->xml(true));   // '<root/>' - the <p> was removed, not the <i>

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions