Category
Regression: · php-src-strict · ext/dom · XPath 1.0 or / and
Problem
DOMXPath does not implement XPath 1.0 boolean operators or / and (php-src → libxml xmlXPathEval). Predicates such as [@id or @class] and not(@id) match 0 nodes; evaluate('true() or false()') falls through to invalid-expression false. Zend returns the node-set / boolean.
Probed 2026-08-18 — host Zend PHP 8.2 vs php bin/vm.php.
| Repro |
Zend 8.2+ |
VM (2026-08-18) |
query('//a[@id or @class]') on <r><a id="1" class="c"/><a id="2"/><b class="x"/></r> |
length 2 |
length 0 |
query('//*[@id and @class]') |
length 1 |
length 0 |
query('//*[not(@id)]') |
length 2 (r,b) |
length 0 |
evaluate('true() or false()') |
true |
false |
evaluate('1 or 0') |
true |
false |
evaluate('count(//a[@id or @class])') |
2.0 |
0.0 |
query('//a or //b') is not a union (|); Zend returns an empty NodeList (boolean expr). evaluate('//a or //b') is boolean true when //a is non-empty.
php-src reference
PHP implementation target
ext/dom/VmDomXPath.php — top-level or/and in evaluateBoolean / isBooleanExpression; general [pred] on location steps via evaluateToMixed with the candidate as context
- JIT/AOT: existing
JitDomXPath* host/runtime paths should follow the VM engine; no new runtime/*.c
Repro
./script/docker-exec.sh -- bash -lc 'php test/repro/maintainer_gap_dom_xpath_or_and.php'
./script/docker-exec.sh -- bash -lc 'php bin/vm.php test/repro/maintainer_gap_dom_xpath_or_and.php'
Done when
Category
Regression:· php-src-strict · ext/dom · XPath 1.0or/andProblem
DOMXPathdoes not implement XPath 1.0 boolean operatorsor/and(php-src → libxmlxmlXPathEval). Predicates such as[@id or @class]andnot(@id)match 0 nodes;evaluate('true() or false()')falls through to invalid-expression false. Zend returns the node-set / boolean.Probed 2026-08-18 — host Zend PHP 8.2 vs
php bin/vm.php.query('//a[@id or @class]')on<r><a id="1" class="c"/><a id="2"/><b class="x"/></r>query('//*[@id and @class]')query('//*[not(@id)]')r,b)evaluate('true() or false()')truefalseevaluate('1 or 0')truefalseevaluate('count(//a[@id or @class])')2.00.0query('//a or //b')is not a union (|); Zend returns an empty NodeList (boolean expr).evaluate('//a or //b')is booleantruewhen//ais non-empty.php-src reference
ext/dom/xpath.c—xmlXPathEval/ libxml XPath 1.0or/and/ predicate booleanizationorlower precedence thanand; node-set truth = non-emptyPHP implementation target
ext/dom/VmDomXPath.php— top-levelor/andinevaluateBoolean/isBooleanExpression; general[pred]on location steps viaevaluateToMixedwith the candidate as contextJitDomXPath*host/runtime paths should follow the VM engine; no newruntime/*.cRepro
Done when
query('//a[@id or @class]')///*[@id and @class]///*[not(@id)]match Zend lengthsevaluate('true() or false()')/'1 or 0'/'true() and false()'match Zend booleans