diff --git a/docs/bootstrap-inventory.md b/docs/bootstrap-inventory.md index 2205090fce5..6c898e03d9e 100644 --- a/docs/bootstrap-inventory.md +++ b/docs/bootstrap-inventory.md @@ -8,11 +8,11 @@ Regenerate: `php script/bootstrap-inventory.php` | Metric | Count | |--------|------:| -| PHP files on vm.php path | 5818 | -| Phase A inventory files (M2 ratio SSOT) | 5818 | +| PHP files on vm.php path | 5819 | +| Phase A inventory files (M2 ratio SSOT) | 5819 | | Phase A ratio-deferred paths | 0 | | Source constructs flagged (blockers) | 0 | -| Source constructs flagged (warnings) | 17261 | +| Source constructs flagged (warnings) | 17271 | ## Compiler CFG gaps (`lib/Compiler.php`) @@ -234,7 +234,7 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag | `ext/dom/DomImportNodeJitHelper.php` | 0 | 3 | | `ext/dom/DomIsConnectedJitHelper.php` | 0 | 1 | | `ext/dom/DomIsEqualNodeJitHelper.php` | 0 | 1 | -| `ext/dom/DomLivingBuiltinClasses.php` | 0 | 48 | +| `ext/dom/DomLivingBuiltinClasses.php` | 0 | 53 | | `ext/dom/DomLoadHTMLFileJitHelper.php` | 0 | 1 | | `ext/dom/DomLoadHTMLJitHelper.php` | 0 | 1 | | `ext/dom/DomLoadJitHelper.php` | 0 | 1 | @@ -349,6 +349,7 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag | `ext/dom/JitDomXPathEvaluateUserScript.php` | 0 | 1 | | `ext/dom/JitDomXPathQuery.php` | 0 | 1 | | `ext/dom/JitDomXPathQueryUserScript.php` | 0 | 2 | +| `ext/dom/LivingXPathConstruct.php` | 0 | 2 | | `ext/dom/Module.php` | 0 | 3 | | `ext/dom/NamedNodeMapCount.php` | 0 | 1 | | `ext/dom/NamedNodeMapCurrent.php` | 0 | 1 | @@ -405,7 +406,7 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag | `ext/dom/TokenListReplace.php` | 0 | 1 | | `ext/dom/TokenListSupports.php` | 0 | 1 | | `ext/dom/TokenListToggle.php` | 0 | 1 | -| `ext/dom/VmDom.php` | 0 | 396 | +| `ext/dom/VmDom.php` | 0 | 399 | | `ext/dom/VmDomCollectionDimension.php` | 0 | 1 | | `ext/dom/VmDomInstanceInvoke.php` | 0 | 2 | | `ext/dom/VmDomJitDispatch.php` | 0 | 42 | @@ -7109,24 +7110,29 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag - new ClassProperty (line 135) - new Variable (line 135) - new HtmlCollectionNamedItem (line 137) -- new ClassEntry (line 142) -- new ClassProperty (line 145) -- new DocumentGetElementsByClassName (line 153) -- new ClassEntry (line 158) -- new ClassProperty (line 161) -- new ClassProperty (line 162) -- new ClassProperty (line 163) -- new HtmlDocumentCreateFromString (line 164) -- new HtmlDocumentCreateEmpty (line 167) -- new HtmlDocumentCreateFromFile (line 170) -- new HtmlDocumentGetElementById (line 173) -- new HtmlDocumentQuerySelector (line 176) -- new HtmlDocumentQuerySelectorAll (line 179) -- new HtmlDocumentSaveHtml (line 182) -- new ClassEntry (line 199) -- new ClassProperty (line 202) -- new XmlDocumentCreateFromString (line 203) -- new XmlDocumentCreateEmpty (line 206) +- new ClassEntry (line 143) +- new ClassProperty (line 152) +- new Variable (line 152) +- new ClassEntry (line 157) +- new LivingXPathConstruct (line 159) +- new ClassEntry (line 166) +- new ClassProperty (line 169) +- new DocumentGetElementsByClassName (line 177) +- new ClassEntry (line 182) +- new ClassProperty (line 185) +- new ClassProperty (line 186) +- new ClassProperty (line 187) +- new HtmlDocumentCreateFromString (line 188) +- new HtmlDocumentCreateEmpty (line 191) +- new HtmlDocumentCreateFromFile (line 194) +- new HtmlDocumentGetElementById (line 197) +- new HtmlDocumentQuerySelector (line 200) +- new HtmlDocumentQuerySelectorAll (line 203) +- new HtmlDocumentSaveHtml (line 206) +- new ClassEntry (line 223) +- new ClassProperty (line 226) +- new XmlDocumentCreateFromString (line 227) +- new XmlDocumentCreateEmpty (line 230) - 3 class method(s) ### `ext/dom/DomLoadHTMLFileJitHelper.php` @@ -7775,6 +7781,12 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag - new JITVariable (line 101) - 4 class method(s) +### `ext/dom/LivingXPathConstruct.php` + +**Warnings** (review for bootstrap subset): +- new DomNodeState (line 53) +- 1 class method(s) + ### `ext/dom/Module.php` **Warnings** (review for bootstrap subset): @@ -8423,40 +8435,43 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag - new ObjectEntry (line 7134) - new DomNodeState (line 7138) - new Variable (line 7145) -- new DOMException (line 7222) -- new ObjectEntry (line 7497) -- new DomNodeState (line 7501) -- new Variable (line 7508) +- new ObjectEntry (line 7163) +- new DomNodeState (line 7167) +- new Variable (line 7174) +- new DOMException (line 7257) - new ObjectEntry (line 7535) -- new DomNodeState (line 7538) +- new DomNodeState (line 7539) - new Variable (line 7546) -- new Variable (line 7737) -- new DOMException (line 7874) -- new DOMException (line 7881) -- new DOMException (line 7888) -- new DOMException (line 7892) -- new DOMException (line 7895) -- new DOMException (line 7904) +- new ObjectEntry (line 7573) +- new DomNodeState (line 7576) +- new Variable (line 7584) +- new Variable (line 7779) - new DOMException (line 7916) -- new DOMException (line 8977) -- new Variable (line 9036) -- new Variable (line 9049) -- new Variable (line 9087) -- new DOMException (line 9098) -- new Variable (line 9100) -- new DOMException (line 9261) -- new DOMException (line 9288) -- new DOMException (line 9324) -- new DOMException (line 9388) -- new DOMException (line 9396) -- new DOMException (line 9409) -- new DOMException (line 9414) -- new DOMException (line 9417) -- new DOMException (line 9420) -- new DOMException (line 9449) -- new Error (line 10348) -- new Error (line 10352) -- 424 class method(s) +- new DOMException (line 7923) +- new DOMException (line 7930) +- new DOMException (line 7934) +- new DOMException (line 7937) +- new DOMException (line 7946) +- new DOMException (line 7958) +- new DOMException (line 9019) +- new Variable (line 9078) +- new Variable (line 9091) +- new Variable (line 9129) +- new DOMException (line 9140) +- new Variable (line 9142) +- new DOMException (line 9303) +- new DOMException (line 9330) +- new DOMException (line 9366) +- new DOMException (line 9430) +- new DOMException (line 9438) +- new DOMException (line 9451) +- new DOMException (line 9456) +- new DOMException (line 9459) +- new DOMException (line 9462) +- new DOMException (line 9491) +- new Error (line 10402) +- new Error (line 10406) +- 426 class method(s) - 2 closure(s) ### `ext/dom/VmDomCollectionDimension.php` @@ -8524,19 +8539,19 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag ### `ext/dom/VmDomLiving.php` **Warnings** (review for bootstrap subset): -- new ObjectEntry (line 86) -- new ObjectEntry (line 104) -- new DOMException (line 133) -- new Variable (line 136) -- new DOMException (line 176) -- new DOMException (line 259) -- new DOMException (line 264) -- new DOMException (line 271) -- new DOMException (line 302) -- new DOMException (line 314) -- new DOMException (line 427) -- new Variable (line 433) -- new Variable (line 467) +- new ObjectEntry (line 92) +- new ObjectEntry (line 110) +- new DOMException (line 139) +- new Variable (line 142) +- new DOMException (line 182) +- new DOMException (line 265) +- new DOMException (line 270) +- new DOMException (line 277) +- new DOMException (line 308) +- new DOMException (line 320) +- new DOMException (line 433) +- new Variable (line 439) +- new Variable (line 473) - 36 class method(s) - 1 closure(s) @@ -8567,39 +8582,39 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag **Warnings** (review for bootstrap subset): - new ObjectEntry (line 48) - new DomNodeState (line 51) -- new Variable (line 199) -- new Variable (line 205) -- new Variable (line 211) -- new DOMException (line 233) -- new DOMException (line 239) -- new DOMException (line 331) -- new DOMException (line 382) -- new DOMException (line 784) -- new DOMException (line 1108) -- new DOMException (line 1212) -- new DOMException (line 1253) -- new DOMException (line 1321) -- new DOMException (line 1333) -- new DOMException (line 1360) -- new DOMException (line 1400) -- new Variable (line 1844) -- new DOMException (line 1850) -- new Error (line 1863) -- new Variable (line 1867) -- new Variable (line 1877) -- new Variable (line 2003) -- new DOMException (line 2010) -- new Error (line 2064) -- new Variable (line 2099) -- new Variable (line 2105) -- new Variable (line 2111) -- new Variable (line 2117) -- new Variable (line 2126) -- new HashTable (line 2137) -- new Variable (line 2143) +- new Variable (line 203) +- new Variable (line 209) +- new Variable (line 215) +- new DOMException (line 237) +- new DOMException (line 243) +- new DOMException (line 335) +- new DOMException (line 386) +- new DOMException (line 788) +- new DOMException (line 1112) +- new DOMException (line 1216) +- new DOMException (line 1257) +- new DOMException (line 1325) +- new DOMException (line 1337) +- new DOMException (line 1364) +- new DOMException (line 1404) +- new Variable (line 1848) +- new DOMException (line 1854) +- new Error (line 1867) +- new Variable (line 1871) +- new Variable (line 1881) +- new Variable (line 2007) +- new DOMException (line 2014) +- new Error (line 2068) +- new Variable (line 2103) +- new Variable (line 2109) +- new Variable (line 2115) +- new Variable (line 2121) +- new Variable (line 2130) +- new HashTable (line 2141) - new Variable (line 2147) -- new Variable (line 2164) -- new Variable (line 2173) +- new Variable (line 2151) +- new Variable (line 2168) +- new Variable (line 2177) - 73 class method(s) - 1 closure(s) diff --git a/ext/dom/DomLivingBuiltinClasses.php b/ext/dom/DomLivingBuiltinClasses.php index 759b2bc368b..a788a3513ab 100644 --- a/ext/dom/DomLivingBuiltinClasses.php +++ b/ext/dom/DomLivingBuiltinClasses.php @@ -139,6 +139,30 @@ public static function register(Context $ctx): void $htmlCollection->methodNames['nameditem'] = 'namedItem'; $ctx->classes[VmDomLiving::CLASS_HTML_COLLECTION] = $htmlCollection; + // Dom\NodeList — XPath node-set results (php-src php_dom.stub.php; #20757). + $nodeList = new ClassEntry('Dom\\NodeList'); + $nodeList->isInternal = true; + $nodeList->interfaces[] = 'countable'; + if (isset($ctx->classes['iterator'])) { + $nodeList->interfaces[] = 'iterator'; + } + if (isset($ctx->classes['traversable'])) { + $nodeList->interfaces[] = 'traversable'; + } + $nodeList->properties[] = new ClassProperty(VmDom::PROP_LENGTH, null, new Variable(Variable::TYPE_INTEGER)); + self::copyMethods($ctx->classes[VmDom::CLASS_NODE_LIST] ?? null, $nodeList); + $ctx->classes[VmDomLiving::CLASS_NODE_LIST] = $nodeList; + + // Dom\XPath — living Document XPath (php-src php_dom.stub.php / xpath.c; #20757). + $xpath = new ClassEntry('Dom\\XPath'); + $xpath->isInternal = true; + $xpathConstruct = new LivingXPathConstruct(); + $xpath->constructor = $xpathConstruct; + $xpath->methods['__construct'] = $xpathConstruct; + $xpath->methodVisibility['__construct'] = $pub; + self::copyMethods($ctx->classes[VmDom::CLASS_XPATH] ?? null, $xpath); + $ctx->classes[VmDomLiving::CLASS_XPATH] = $xpath; + $document = new ClassEntry('Dom\\Document'); $document->isInternal = true; $document->parentLc = VmDomLiving::CLASS_NODE; diff --git a/ext/dom/LivingXPathConstruct.php b/ext/dom/LivingXPathConstruct.php new file mode 100644 index 00000000000..a59c0e8bd2d --- /dev/null +++ b/ext/dom/LivingXPathConstruct.php @@ -0,0 +1,59 @@ +receiver($frame, VmDomLiving::CLASS_XPATH, 'Dom\\XPath::__construct()'); + if (\count($frame->calledArgs) < 2) { + throw new \LogicException('Dom\\XPath::__construct() expects at least 1 argument'); + } + $documentVar = $frame->calledArgs[1]->resolveIndirect(); + if (Variable::TYPE_OBJECT !== $documentVar->type) { + throw new \TypeError(sprintf( + 'Dom\\XPath::__construct(): Argument #1 ($document) must be of type Dom\\Document, %s given', + VmDom::typeLabel($documentVar) + )); + } + $document = $documentVar->toObject(); + if (!VmDomLiving::isLivingDocument($document) && VmDomLiving::CLASS_DOCUMENT !== strtolower($document->class->name)) { + throw new \TypeError(sprintf( + 'Dom\\XPath::__construct(): Argument #1 ($document) must be of type Dom\\Document, %s given', + $document->class->name + )); + } + if (!VmDom::isDocument($document)) { + throw new \TypeError(sprintf( + 'Dom\\XPath::__construct(): Argument #1 ($document) must be of type Dom\\Document, %s given', + $document->class->name + )); + } + VmDom::ensureDocument($document); + if (DomRegistry::has($receiver)) { + $state = DomRegistry::state($receiver); + $state->xpathDocumentId = $document->id; + + return; + } + $state = new DomNodeState(); + $state->nodeType = DomConstants::XML_XPATH; + $state->nodeName = 'Dom\\XPath'; + $state->xpathDocumentId = $document->id; + DomRegistry::attach($receiver, $state); + } +} diff --git a/ext/dom/VmDom.php b/ext/dom/VmDom.php index ab7478558b0..16bf13249eb 100644 --- a/ext/dom/VmDom.php +++ b/ext/dom/VmDom.php @@ -7148,6 +7148,41 @@ public static function createHtmlCollection(Context $ctx, array $nodeIds): Varia return $var; } + /** + * Dom\NodeList handle — XPath node-sets (php-src php_dom.stub.php; #20757). + * + * @param list $nodeIds + */ + public static function createDomNodeList(Context $ctx, array $nodeIds): Variable + { + $class = $ctx->classes[VmDomLiving::CLASS_NODE_LIST] ?? null; + if (null === $class) { + return self::createNodeList($ctx, $nodeIds); + } + + $entry = new ObjectEntry($class); + $entry->constructed = true; + $entry->getProperty(self::PROP_LENGTH)->int(\count($nodeIds)); + + $state = new DomNodeState(); + $state->nodeType = DomConstants::XML_NODELIST; + $state->nodeName = '#nodelist'; + $state->listNodeIds = $nodeIds; + $state->listIterIndex = 0; + DomRegistry::attach($entry, $state); + + $var = new Variable(Variable::TYPE_OBJECT); + $var->object($entry); + + return $var; + } + + /** Living Dom\XPath query/evaluate node-sets use Dom\NodeList (#20757). */ + public static function prefersDomNodeList(ObjectEntry $xpath): bool + { + return VmDomLiving::CLASS_XPATH === strtolower($xpath->class->name); + } + /** Living Dom\* receivers use HTMLCollection; legacy DOM* keep DOMNodeList (#20709). */ public static function prefersHtmlCollection(ObjectEntry $root): bool { @@ -7293,7 +7328,10 @@ public static function refreshNodeListIfLive(ObjectEntry $nodeList): void public static function isNodeList(ObjectEntry $entry): bool { $lc = strtolower($entry->class->name); - if (self::CLASS_NODE_LIST !== $lc && VmDomLiving::CLASS_HTML_COLLECTION !== $lc) { + if (self::CLASS_NODE_LIST !== $lc + && VmDomLiving::CLASS_HTML_COLLECTION !== $lc + && VmDomLiving::CLASS_NODE_LIST !== $lc + ) { return false; } @@ -7562,8 +7600,12 @@ public static function isTokenList(ObjectEntry $entry): bool public static function isXPath(ObjectEntry $entry): bool { - return self::CLASS_XPATH === strtolower($entry->class->name) - && DomRegistry::has($entry) + $lc = strtolower($entry->class->name); + if (self::CLASS_XPATH !== $lc && VmDomLiving::CLASS_XPATH !== $lc) { + return false; + } + + return DomRegistry::has($entry) && DomConstants::XML_XPATH === DomRegistry::state($entry)->nodeType; } @@ -9609,13 +9651,25 @@ public static function requireReceiver( if (self::CLASS_TOKEN_LIST === $classLc && self::isTokenList($object)) { return $object; } - // Dom\HTMLCollection shares DOMNodeList item/count/iterator handlers (#20709). + // Dom\HTMLCollection / Dom\NodeList share DOMNodeList item/count/iterator handlers (#20709, #20757). if (self::CLASS_NODE_LIST === $classLc && self::isNodeList($object)) { return $object; } if (VmDomLiving::CLASS_HTML_COLLECTION === $classLc && self::isHtmlCollection($object)) { return $object; } + if (VmDomLiving::CLASS_NODE_LIST === $classLc && self::isNodeList($object) + && VmDomLiving::CLASS_NODE_LIST === strtolower($object->class->name) + ) { + return $object; + } + // Dom\XPath shares DOMXPath query/evaluate handlers (#20757). + if (self::CLASS_XPATH === $classLc && self::isXPath($object)) { + return $object; + } + if (VmDomLiving::CLASS_XPATH === $classLc && self::isXPath($object)) { + return $object; + } throw new \TypeError(sprintf('%s must be called on a %s instance', $label, self::classNameFromLc($classLc))); } diff --git a/ext/dom/VmDomLiving.php b/ext/dom/VmDomLiving.php index 409ec2d52db..8345586ee40 100644 --- a/ext/dom/VmDomLiving.php +++ b/ext/dom/VmDomLiving.php @@ -30,6 +30,12 @@ final class VmDomLiving /** php-src Dom\HTMLCollection (ext/dom/html_collection.c / php_dom.stub.php; #20709). */ public const CLASS_HTML_COLLECTION = 'dom\\htmlcollection'; + /** php-src Dom\NodeList (php_dom.stub.php; XPath query/evaluate node-sets; #20757). */ + public const CLASS_NODE_LIST = 'dom\\nodelist'; + + /** php-src Dom\XPath (php_dom.stub.php / xpath.c; #20757). */ + public const CLASS_XPATH = 'dom\\xpath'; + /** HTML namespace URI (https://html.spec.whatwg.org/#html-namespace). */ public const HTML_NS = 'http://www.w3.org/1999/xhtml'; diff --git a/ext/dom/VmDomXPath.php b/ext/dom/VmDomXPath.php index cfd34a4923c..5979692c7f0 100644 --- a/ext/dom/VmDomXPath.php +++ b/ext/dom/VmDomXPath.php @@ -176,6 +176,10 @@ public static function query( ): Variable { $nodeIds = self::evaluateNodeSet($ctx, $xpath, $expression, $contextNode, $registerNodeNS); + if (VmDom::prefersDomNodeList($xpath)) { + return VmDom::createDomNodeList($ctx, $nodeIds); + } + return VmDom::createNodeList($ctx, $nodeIds); } diff --git a/test/compliance/JITTest.php b/test/compliance/JITTest.php index b302eb3d09c..d17660801b9 100755 --- a/test/compliance/JITTest.php +++ b/test/compliance/JITTest.php @@ -1385,6 +1385,11 @@ public static function providePHPTests(): \Generator && !str_contains($name, 'curl_share_init_persistent_type')) { continue; } + // Dom\XPath::query()/evaluate node-sets: VM green (#20757); jit.php WeakRefNativeOpsJit::nullSlot + // getValue() abort during helper bootstrap when compiling Dom\XPath::query(). + if (str_contains($name, 'dom_xpath_living')) { + continue; + } // Phar instance API: VM green (#20628); jit.php hits MathBaseConvertRuntime::constFloat // (hexdec/WeakRef bootstrap) same as curl_share_init_persistent. if (str_contains($name, 'phar_instance_api')) { diff --git a/test/compliance/cases/dom/dom_xpath_living.phpt b/test/compliance/cases/dom/dom_xpath_living.phpt new file mode 100644 index 00000000000..ee32130e9d4 --- /dev/null +++ b/test/compliance/cases/dom/dom_xpath_living.phpt @@ -0,0 +1,54 @@ +--TEST-- +Dom\XPath + Dom\NodeList on HTMLDocument/XMLDocument (#20757) +--SKIPIF-- + +--ENV-- +PHP_COMPILER_PROFILE=8.4 +--FILE-- +

hi

yo

' +); +$xp = new Dom\XPath($doc); +echo get_class($xp), "\n"; +$list = $xp->query('//p'); +echo get_class($list), "\n"; +echo ($list instanceof Dom\NodeList) ? "isa\n" : "not\n"; +echo 'len=', $list->length, "\n"; +echo 'item=', $list->item(0)->tagName, "\n"; +echo 'count=', $xp->evaluate('count(//p)'), "\n"; + +$xml = Dom\XMLDocument::createFromString('1'); +$xp2 = new Dom\XPath($xml); +$xp2->registerNamespace('q', 'urn:x'); +echo 'ns=', $xp2->query('//q:a')->length, "\n"; + +try { + new Dom\XPath(new DOMDocument()); + echo "legacy_ok\n"; +} catch (TypeError $e) { + echo str_contains($e->getMessage(), 'Document') ? "legacy_type\n" : "legacy_other\n"; +} + +$legacy = new DOMDocument(); +$legacy->loadXML(''); +echo 'legacy_list=', get_class((new DOMXPath($legacy))->query('//a')), "\n"; +--EXPECT-- +xpath +nodelist +Dom\XPath +Dom\NodeList +isa +len=2 +item=p +count=2 +ns=1 +legacy_type +legacy_list=DOMNodeList diff --git a/test/repro/maintainer_gap_dom_xpath_living.php b/test/repro/maintainer_gap_dom_xpath_living.php new file mode 100644 index 00000000000..dda6e50b0bd --- /dev/null +++ b/test/repro/maintainer_gap_dom_xpath_living.php @@ -0,0 +1,73 @@ +

hi

yo

' +); +$xp = new Dom\XPath($doc); +if (!$xp instanceof Dom\XPath) { + fwrite(STDERR, "fail: construct class\n"); + exit(1); +} + +$list = $xp->query('//p'); +if (!$list instanceof Dom\NodeList) { + fwrite(STDERR, 'fail: query returned '.get_class($list).", expected Dom\\NodeList\n"); + exit(1); +} +if (2 !== $list->length) { + fwrite(STDERR, "fail: query length={$list->length}\n"); + exit(1); +} +$first = $list->item(0); +if (!$first instanceof Dom\Element && !$first instanceof Dom\HTMLElement) { + fwrite(STDERR, 'fail: item class='.(null === $first ? 'null' : get_class($first))."\n"); + exit(1); +} + +$n = $xp->evaluate('count(//p)'); +if (2.0 !== (float) $n) { + fwrite(STDERR, 'fail: evaluate count='.var_export($n, true)."\n"); + exit(1); +} + +$xml = Dom\XMLDocument::createFromString('1'); +$xp2 = new Dom\XPath($xml); +$xp2->registerNamespace('q', 'urn:x'); +$nsList = $xp2->query('//q:a'); +if (1 !== $nsList->length) { + fwrite(STDERR, "fail: ns query length={$nsList->length}\n"); + exit(1); +} + +if (method_exists(Dom\XPath::class, 'quote')) { + $q = Dom\XPath::quote("a'b"); + if (!is_string($q) || '' === $q) { + fwrite(STDERR, "fail: quote empty\n"); + exit(1); + } +} + +try { + new Dom\XPath(new DOMDocument()); + fwrite(STDERR, "fail: legacy DOMDocument should TypeError\n"); + exit(1); +} catch (TypeError $e) { + if (!str_contains($e->getMessage(), 'Dom\\Document') && !str_contains($e->getMessage(), 'Document')) { + fwrite(STDERR, 'fail: TypeError message='.$e->getMessage()."\n"); + exit(1); + } +} + +echo "ok\n"; diff --git a/test/selfhost/compiler_lib_spine_smoke/main.php b/test/selfhost/compiler_lib_spine_smoke/main.php index 40bace1a48d..e470654f7c5 100644 --- a/test/selfhost/compiler_lib_spine_smoke/main.php +++ b/test/selfhost/compiler_lib_spine_smoke/main.php @@ -467,6 +467,7 @@ require_once __DIR__.'/../../../ext/dom/VmDomValidationNative.php'; require_once __DIR__.'/../../../ext/dom/VmDomXPath.php'; require_once __DIR__.'/../../../ext/dom/XPathConstruct.php'; +require_once __DIR__.'/../../../ext/dom/LivingXPathConstruct.php'; require_once __DIR__.'/../../../ext/dom/XPathEvaluate.php'; require_once __DIR__.'/../../../ext/dom/XPathQuery.php'; require_once __DIR__.'/../../../ext/dom/XPathQuote.php';