_wrapperNode->get(); } protected function __get_xpath(): \DOMXPath { if ($this->_xpath === null) { $this->_xpath = new \DOMXPath($this); } return $this->_xpath; } private static ?string $parentNamespace = null; public function __construct(WrapperDocument $wrapperNode) { parent::__construct(); parent::registerNodeClass('DOMDocument', self::class); $this->nodeCache = new NodeCache(); // Use a weak reference here to prevent a circular reference $this->_wrapperNode = \WeakReference::create($wrapperNode); if (self::$parentNamespace === null) { self::$parentNamespace = substr(__NAMESPACE__, 0, strrpos(__NAMESPACE__, '\\')); } } public function getWrapperNode(\DOMNode $node): ?WrapperNode { // If the node is a Document then the wrapperNode is this's wrapperNode // property. if ($node instanceof Document) { return $this->wrapperNode; } // If the wrapper node already exists then return that. if ($wrapperNode = $this->nodeCache->get($node)) { return $wrapperNode; } // If the node didn't exist we must construct the wrapper node's class name // based upon the node's class name if ($node instanceof \DOMAttr) { $className = 'Attr'; } elseif ($node instanceof \DOMCdataSection) { $className = 'CDATASection'; } elseif ($node instanceof \DOMComment) { $className = 'Comment'; } elseif ($node instanceof \DOMDocumentFragment) { $className = 'DocumentFragment'; } elseif ($node instanceof \DOMDocumentType) { $className = 'DocumentType'; } elseif ($node instanceof \DOMElement) { $namespace = $node->namespaceURI; if ($namespace === null) { if ($node->nodeName === 'template') { $className = 'HTMLTemplateElement'; } else { $className = 'HTMLElement'; } } elseif ($namespace === WrapperNode::SVG_NAMESPACE) { $className = 'SVGElement'; } elseif ($namespace === WrapperNode::MATHML_NAMESPACE) { $className = 'MathMLElement'; } else { $className = 'Element'; } } elseif ($node instanceof \DOMProcessingInstruction) { $className = 'ProcessingInstruction'; } elseif ($node instanceof \DOMText) { $className = 'Text'; } $wrapperNode = Reflection::createFromProtectedConstructor(self::$parentNamespace . "\\$className", $node); // We need to work around a PHP DOM bug where doctype nodes aren't associated // with a document until they're appended. if ($className === 'DocumentType') { Reflection::setProtectedProperties($wrapperNode, [ '_ownerDocument' => $this->_wrapperNode ]); } $this->nodeCache->set($wrapperNode, $node); return $wrapperNode; } }