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

Phpcss Laravel Package

carica/phpcss

carica/phpcss is a lightweight PHP library for parsing, manipulating, and rendering CSS. It turns stylesheets into an object model so you can inspect or modify rules and declarations, then output clean or optimized CSS for dynamic styles and build tools.

View on GitHub
Deep Wiki
Context7

Getting Started

PhpCss is a pure tokenizer/parser for CSS selectors. It turns a string like ul.nav > li:first-child a[href^="https"] into a tree of typed PHP objects. It does not query a DOM, match nodes, or generate XPath — that is your job (or a companion package's). Understand that boundary first; it shapes everything below.

Minimal setup:

composer require carica/phpcss
use Carica\Css\Parser\Selector as SelectorParser;

$parser = new SelectorParser();

// Returns a Carica\Css\Selector\Group
$group = $parser->parse('ul.nav > li:first-child a[href^="https"]');

foreach ($group->getSelectors() as $sequence) {
    // $sequence is Carica\Css\Selector\Sequence
    foreach ($sequence->getParts() as $part) {
        // Simple types: \Selector\Simple\Type, \Simple\Id,
        //   \Simple\ClassName, \Simple\Attribute, \Simple\PseudoClass
        // Combinations: \Selector\Combination\Child,
        //   \Selector\Combination\Descendant, \Selector\Combination\Next,
        //   \Selector\Combination\Previous
        echo get_class($part), PHP_EOL;
    }
}

Where to look first:

  1. Carica\Css\Parser\Selector and its parent Carica\Css\Parser — the entry point and lexer glue.
  2. Carica\Css\Selector\Group and Selector\Sequence — the two container types. A Group holds one Sequence per comma-separated selector; a Sequence holds Simple and Combination nodes.
  3. Carica\Css\Selector\Simple\* — one class per atomic selector construct.
  4. Carica\Css\Selector\Combination\* — the four CSS combinators.

First use case: validating a selector before feeding it to a matcher, or compiling it into XPath. If you want the latter, look at carica/phpcss-to-xpath, which walks this AST and emits XPath 1.0 expressions.

Implementation Patterns

Compile to XPath via the companion package

The intended workflow. Parse, then convert, then hand to DOMXPath:

use Carica\Css\Parser\Selector as SelectorParser;
use Carica\Css\ToXpath\Converter;

$parser   = new SelectorParser();
$converter = new Converter();

$group = $parser->parse('.card > h2.title');
$xpath = $converter($group); // e.g. "descendant-or-self::*[contains(concat(' ', @class, ' '), ' card ')]/h2[...]"

$dom = new DOMDocument();
$dom->loadHTML($html);
$nodes = (new DOMXPath($dom))->query($xpath);

Wrap parsing in a cache service

Selectors are parsed constantly and are pure functions of the input string. Parse once, reuse the AST:

final class SelectorCache
{
    private array $cache = [];
    private SelectorParser $parser;

    public function __construct()
    {
        $this->parser = new SelectorParser();
    }

    public function get(string $selector): \Carica\Css\Selector\Group
    {
        return $this->cache[$selector] ??= $this->parser->parse($selector);
    }
}

For long-lived processes, swap the in-memory array for APCu/PSR-16 keyed on the selector string.

Validate selectors by round-trip

If your UI accepts a selector, the parser is the cheapest validator you can get:

try {
    (new SelectorParser())->parse($userInput);
} catch (\Carica\Css\Parser\Exception $e) {
    // "Invalid selector near ..." — surface this cleanly
}

Catch Carica\Css\Parser\Exception specifically; don't let generic \Exception hide a programming error.

Custom visitor for AST-driven work

Rather than instanceof chains, write a visitor over the node classes to build whatever you need — a matcher, a linter, a re-writer, a minifier:

class XPathCompiler implements \Carica\Css\Parser\Visitor
{
    private string $out = '';
    // one method per node type: visitType, visitId, visitClassName,
    // visitAttribute, visitPseudoClass, visitChild, visitDescendant, ...
}

Walk the group and ->accept($visitor), or recurse manually using getParts(). Nodes are value objects — safe to memoize or serialize between requests.

Integration with test helpers

If you're maintaining a browser-emulation layer or a scraping pipeline, use PhpCss to normalize selectors once at bootstrap, then reuse the compiled result for every document. This pairs well with a DOMXPath instance kept alive per document.

Gotchas and Tips

  • It only parses. No DOM access, no matching, no querySelectorAll. Budget for the companion package (carica/phpcss-to-xpath) or your own visitor. This is the single most common surprise.
  • Pseudo-classes are parsed, not evaluated. :first-child, :nth-child(2n+1), :not(...) come back as Simple\PseudoClass nodes with the argument stored as a string. Semantics (especially :nth-* formulas) are your responsibility when compiling.
  • Modern CSS is unevenly supported. The last release is April 2021, so expect gaps around :is(), :where(), :has(), ::part(), and some attribute operators. Test the exact selectors you need in a unit test before committing to the dependency.
  • Namespace is Carica\Css\..., not PhpCss\.... The repo is ThomasWeinert/PhpCss but the package name and namespaces are carica/phpcss — autoload paths in examples from older blog posts may differ.
  • Parse errors are exceptions, not falsy returns. Wrap user-supplied input in try/catch. Errors surface at the lexer level, so messages point at byte offsets — map them back to the original string before showing to end users.
  • PHP version drift. The 2021 release targets PHP 7.x. On PHP 8.2+ expect deprecation noise (implicit nullable params, dynamic properties). Pin with composer require carica/phpcss and, if needed, add #[\AllowDynamicProperties] or use --ignore-platform-reqs deliberately, not by accident.
  • No dependents and no recent activity. Treat it as a stable-but-frozen parser. Vendor-freeze the version, add your own integration tests, and be prepared to fork if a new CSS feature is required.
  • Extension points are the node classes themselves. If you need a construct the parser doesn't recognize, subclass the appropriate Parser section or pre-process the selector string, then produce your own Simple node. Don't monkey-patch the lexer.
  • Serialization is cheap. Group/Sequence/Simple nodes are plain objects with simple properties, so serialize() (or var_export for tests) works for debugging — dump the AST when a selector behaves unexpectedly rather than guessing at the generated XPath.
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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource