tburry/pquery
pQuery is a jQuery-inspired PHP library for parsing and manipulating HTML. It offers CSS selector queries, chainable DOM traversal and modification, and a familiar API for scraping or transforming markup without fragile regex.
Architecture fit. tburry/pquery is a thin, jQuery-style facade over PHP's native ext-dom (DOMDocument + DOMXPath). It bundles two capabilities that are usually split across packages: a CSS3 selector engine and a mutation API (attr(), append(), html(), remove()). That combination is the reason to consider it — symfony/css-selector gives you selectors but no manipulation, and symfony/dom-crawler is primarily read-oriented. It fits a server-side PHP/Laravel monolith that needs to scrape, sanitize, or rewrite HTML fragments without introducing Node, headless Chrome, or a queue worker. It does not fit template rendering, and it is not a replacement for a sanitizer — it parses, it does not make untrusted HTML safe.
Integration feasibility. Installable via Composer, but the package is effectively unmaintained: last release 2016-01-14, 133 stars, no active issue triage. Expect the composer.json platform constraint to predate PHP 8, which means either --ignore-platform-reqs (unacceptable for CI hygiene) or an internal fork with a widened constraint and a PHP 8 deprecation pass. It requires ext-dom and likely ext-libxml/ext-mbstring; verify against your base image. There is no Laravel service provider or facade, so integration is a small adapter class bound into the container — that is cheap, and intentionally so.
Technical risk. Three concerns, in order:
libxml CVE or PHP runtime break lands on your team. The attack surface is small (no network, no eval), but "no upstream" means you own it forever.DOMDocument parsing of hostile HTML is a known minefield — entity expansion and external entity loading depend on parser flags. Confirm pquery does not enable LIBXML_NOENT/LIBXML_DTDLOAD, and never point it at user-supplied documents without a hardened libxml_disable_entity_loader posture (default in PHP 8, but assert it).Key questions for the assessment owner.
symfony/css-selector + dom-crawler removes the entire risk profile.Stack fit. Best case is a legacy Laravel 5.x/6.x–era codebase on PHP 7.x, where pquery drops in and the jQuery-shaped API is immediately productive for developers coming from frontend. On PHP 8.1+ the honest answer is: fork it into a company/pquery package, widen the constraint, fix deprecations (dynamic properties, curly-brace string offsets), and add a smoke-test suite — roughly 2–4 days of one engineer's time, plus ongoing ownership.
Migration path. If you adopt, wrap it. Define a narrow internal interface (select(string $css, string $html): NodeList, mutate(...)) and keep pquery behind it. That gives you a one-file swap to symfony/dom-crawler + css-selector, DiDOM, or PHP 8.4's native \Dom\HTMLDocument when the maintenance cost stops being worth it. Note that the mutation methods are the part with no clean equivalent elsewhere — if the product depends on them, the exit cost is real and should be priced in now.
Compatibility. Selector coverage is "jQuery-like," not jQuery. Pseudo-selectors (:visible, :contains, :nth-child variants) are the usual gaps; audit the selectors the product actually needs during the spike rather than after. Encoding is the other recurring trap: DOMDocument assumes Latin-1 unless told otherwise, so UTF-8 content needs the standard meta-prefix workaround or you ship mojibake.
Sequencing.
dom-crawler + css-selector, which is already a transitive dependency in many Laravel installs.composer.lock and forbid dev-master.Maintenance. Effectively zero upstream. Budget an internal owner and a quarterly "does this still work on the current PHP" check. Treat the dependency as vendored-by-fork rather than consumed. The low opportunity score (3.02) reinforces this: it is a tactical utility, not a platform bet — do not let it spread across services.
Support. No vendor, no active maintainer, stale Stack Overflow answers. Onboarding documentation must be internal. Developer ramp-up is genuinely fast — anyone who writes jQuery needs an hour — but that fluency is a trap: developers will assume the full jQuery API exists and hit silent no-ops on unsupported selectors.
Scaling. DOMDocument materializes the entire document in memory before querying. Page-scale HTML (tens to low hundreds of KB) is fine; batch processing of thousands of documents in a single request will spike memory and should be chunked through a queue. Each selector call re-queries the XPath engine — cache compiled queries or reduce query count in hot paths. This is not a streaming parser and should not be used in high-throughput request paths.
Failure modes. Ranked by likelihood:
libxml recovers by guessing; malformed input produces subtly wrong trees rather than exceptions. Test against real degraded inputs.libxml flags; otherwise low.Verdict for the TPM. Viable as a short-term, bounded, internally-owned utility on a PHP 7.x codebase with a legal green light and an adapter in front of it. On PHP 8+, or if the application is distributed, or if only selection is needed, the total cost of ownership exceeds the modest benefit — standardize on symfony/dom-crawler + css-selector instead.
How can I help you explore Laravel packages today?