Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Zend Dom Laravel Package

zendframework/zend-dom

Zend\Dom provides tools for parsing and querying HTML and XML documents, including CSS selector support translated to XPath via Zend\Dom\Query. A legacy Zend Framework component for DOM inspection and extraction.

Deep Wiki
Context7

Technical Evaluation

Architecture fit. zendframework/zend-dom is a single-purpose, framework-agnostic component: Zend\Dom\Query wraps DOMDocument/DOMXPath and adds CSS-selector-to-XPath translation, with execute() returning a NodeList of DOMNode objects. Nothing in it assumes Zend Framework's MVC, service manager, or DI container, so it drops into a Laravel codebase without adapter work. That is also its limitation — Laravel has no DOM abstraction of its own, and the de facto choice in the ecosystem is symfony/dom-crawler (+ symfony/css-selector), which is already present in most Laravel installs via transitive dependencies (BrowserKit, HTTP-client testing, mail/HTML tooling). Choosing zend-dom means adding a second, older DOM API alongside one the team likely already has.

Integration feasibility. Mechanically trivial: composer require zendframework/zend-dom, no service provider, no config, no facade. The API surface is small enough to wrap behind an interface in a day. The real friction is Composer-level, not code-level — see risk below.

Technical risk — this is the dominant factor. The package is archived and its last release was 2019-06-18. Zend Framework was donated to the Linux Foundation and continues as Laminas; zendframework/zend-dom is the abandoned name for what is now laminas/laminas-dom. Concretely:

  • Abandonment signal. Composer 2.2+ flags it as abandoned and prints the suggested replacement on every install/update, which creates recurring noise and audit findings. Security scanners and SBOM tooling will surface it; a TPM should expect a ticket to be filed against it within one audit cycle.
  • No security patching. Any libxml/DOMDocument CVE exposure or encoding bug will be fixed in Laminas, not here. The 838 composite score and 0.8 "opportunity" score read to me as high opportunity to substitute, not high opportunity to adopt.
  • PHP-version drift. The final 2.8.x line targets PHP 7.x. It generally runs on PHP 8.x, but it is untested against 8.1+ deprecations and 8.2+ dynamic-property changes, so "works today" is not "supported tomorrow." This is unquantified risk at every PHP upgrade.
  • 29 stars. Effectively no community. No Stack Overflow corpus, no third-party fixes, no one to ask.

Key questions.

  1. Is there existing Zend\Dom usage in the codebase (legacy ZF2/ZF3 code carried into Laravel), or is this a greenfield evaluation? The answer flips the recommendation from "don't" to "migrate."
  2. What is the actual need — HTML scraping, sitemap/feed parsing, email template assertions in tests, or CSS-selector querying of stored markup? Each has a better-maintained answer (symfony/dom-crawler, laminas/laminas-dom, or plain DOMXPath).
  3. Are we on PHP 8.1+? If so, an unmaintained 2019 DOM wrapper is a poor bet for a multi-year roadmap.
  4. Does a compliance/SBOM gate exist that blocks abandoned packages? If yes, this is disqualified before any technical discussion.
  5. Is there a hard constraint (license, air-gapped vendor allowlist, existing Zend dependency graph) forcing zend-dom specifically? BSD-3-Clause is permissive and non-blocking, so license is rarely the reason.

Integration Approach

Stack fit. Poor-but-workable. It installs cleanly and needs only ext-dom + ext-libxml, both standard. But it duplicates capability Laravel projects usually already have and introduces a namespace (Zend\) that signals "pre-2019 Zend" to every reviewer.

Migration path. Because the API is identical, the correct move is to adopt the successor rather than the archived artifact:

  1. laminas/laminas-dom — the maintained continuation. Namespace changes from Zend\Dom to Laminas\Dom; classes, method signatures, and behavior are otherwise the same. This is a sed-level rename. Note that laminas/laminas-zendframework-bridge exists to alias old namespaces, but it is a transitional crutch for third-party transitive dependencies, not something to build new code on.
  2. symfony/dom-crawler + symfony/css-selector — the stronger recommendation if the need is HTML scraping/querying. Maintained by Symfony, released on a predictable cadence, already adjacent to Laravel's dependency tree, and it handles encoding, relative-URL resolution, and form interaction (which zend-dom does not). Its filter()/each() API is CSS-first, so most zend-dom call sites translate directly.
  3. Raw DOMDocument + DOMXPath — acceptable if the need is a single narrow query. Do not add a dependency to avoid twenty lines of code.

Compatibility. Watch ext-dom/ext-libxml in CI images (some minimal php:alpine builds omit them), and pin PHP constraints explicitly if zend-dom is retained, because its composer.json predates current PHP. The CSS-selector parser is a subset — pseudo-classes like :nth-child and attribute operators are only partially supported — so verify every selector actually used in the codebase, not just the ones in the docs.

Sequencing.

  1. Inventory call sites (grep -r "Zend\\\\Dom") and classify by use case.
  2. Decide target per use case (Crawler for HTML, Laminas for direct port).
  3. Write an adapter/interface so application code depends on your abstraction, not the vendor class.
  4. Port call sites, run the existing test suite as the correctness gate, and keep a characterization test that pins current parse output for a handful of real documents.
  5. Remove zendframework/zend-dom from composer.json and confirm no transitive dependency still pulls it (check composer why).

If a hard constraint forces retention, wrap it behind your own interface immediately and isolate it to one module so a future swap is a single-file change.

Operational Impact

Maintenance. Effectively zero upstream maintenance — that is the headline. There will be no bug fixes, no PHP-version compatibility releases, and no responses to issues. The BSD-3-Clause license means we can fork and patch, but that converts a commodity dependency into an owned one, which is almost never justified for a component with a maintained equivalent. Budget for a permanent "keep or replace" line item at every architecture review.

Support. Community-only, and the community has moved to Laminas. Internal engineers searching for a fix will find Laminas answers, which mostly apply — but "mostly" is a poor support model for production parsing code.

Scaling. The component is CPU- and memory-bound like all DOMDocument work: the entire document is materialized in memory as a node tree, typically 5–10× the source size. Fine for sitemaps and email templates; a liability for large or untrusted HTML. Throughput scales horizontally with workers, not within a process — if parsing appears in a hot request path, push it to a queue. NodeList is lazy over the XPath result, so iteration cost is modest, but retaining DOMNode references keeps the whole document alive and defeats PHP's cycle collector more often than teams expect.

Failure modes.

  • Silent empty results. Malformed HTML triggers libxml warnings (usually suppressed) and returns an empty NodeList rather than an exception. Callers that don't distinguish "no match" from "parse failure" will silently process zero records — the classic version of this bug is a scraper that reports success while ingesting nothing.
  • Encoding corruption. DOMDocument::loadHTML assumes ISO-8859-1 absent a meta charset declaration; non-ASCII text becomes mojibake unless you force UTF-8 (BOM prefix or mb_convert_encoding). This is the single most common production defect with this class of library and there is no upstream fix coming.
  • XPath injection. Query::execute() accepts a selector string; if any part is user-supplied, you are interpolating into XPath. Treat selectors as code, not data.
  • XXE / entity expansion. Only relevant if XML is loaded with LIBXML_NOENT/external entity loading enabled. The component inherits whatever flags the caller passes — enforce LIBXML_NONET centrally.
  • Memory exhaustion on adversarial or oversized documents; cap input size before parsing.

Ramp-up. Very low. The API is essentially setDocumentHtml(), execute($selector), iterate the NodeList — a competent PHP engineer is productive in under an hour. The real ramp-up cost is organizational: explaining to reviewers, auditors, and future maintainers why an archived 2019 package was chosen over a maintained alternative. That conversation costs more than the integration.

TPM recommendation. Do not adopt zendframework/zend-dom for new work. Route existing usage to laminas/laminas-dom (rename-only) or, preferably, symfony/dom-crawler + symfony/css-selector (better fit for a Laravel stack, maintained, already adjacent to the dependency tree). The 0.8 opportunity score is best read as an opportunity to consolidate away from this package, not to standardize on it.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package