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

Pcre Laravel Package

composer/pcre

Type-safe wrappers around PHP's preg_* functions that fail loudly instead of returning unexpected nulls. Enforces PREG_UNMATCHED_AS_NULL, simplifies return types for PHPStan and Psalm, and includes a PHPStan extension for better regex analysis.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit

  • composer/pcre is a thin, stateless, static-method wrapper over PHP's preg_* functions (Composer\Pcre\Preg, Composer\Pcre\Regex) plus typed result objects (MatchResult, MatchAllResult, ReplaceResult, etc.). It has no service provider, no container bindings, no config, and no framework coupling — a clean fit for a Laravel codebase where regex work is currently scattered across validation rules, form requests, importers, log/route parsers, slug builders and Blade partials.
  • The value proposition is narrow and real: preg_* fails silently (returns null/false), and PHPStan/Psalm see an unmanageable union of return types. This package collapses those unions to string/int/array/bool and throws PcreException on failure. For a TPM the relevant framing is defect class elimination — "unchecked preg_match returned false and the code string-cast it to ''" is a recurring production bug category.
  • The bundled PHPStan extension (vendor/composer/pcre/extension.neon) is the highest-leverage part of the package: it validates literal patterns at analysis time and infers $matches array shapes. In a Laravel shop already running Larastan, this converts regex correctness from runtime to CI.
  • Non-fit: the package is deliberately not a regex DSL. If the need is a rich API (fluent patterns, named-group ergonomics, better error messages), rawr/t-regx is the stated alternative. Choosing composer/pcre is a safety/typing decision, not a capability decision.

Integration feasibility

  • composer require composer/pcre — essentially free. It is already present transitively in most Laravel projects via composer/composer (which requires ^3.0), so the incremental dependency-graph cost is ~zero and there is no new transitive risk surface.
  • PHP floor for 3.x is 7.4; 2.x supports 7.2. Laravel 9 (PHP 8.0+) through Laravel 12 (PHP 8.2+) map cleanly onto ^3.x. Laravel 8 on PHP 7.4 also works on 3.x. There is no realistic Laravel target that forces the older branch.
  • MIT license, Composer-core maintainers, active patch cadence (3.4.0 tracked PHPStan 2.2.2+, 3.3.2 added PHPStan 2 support, 3.1.3/3.1.4 fixed PHP 8.4 deprecations). Low stewardship risk.
  • Adoption is mechanically easy: preg_match(...) → Preg::isMatch(...) (bool), preg_match with offsets → Preg::matchWithOffsets, preg_replace → Preg::replace.
  • Friction points are real but bounded: no array $subject for replace methods, PREG_SET_ORDER rejected in matchAll, preg_filter unsupported, and PREG_OFFSET_CAPTURE/PREG_SPLIT_OFFSET_CAPTURE only available via dedicated methods. Any code relying on those shapes is not a drop-in.

Technical risk

  • Semantic change, not a syntax change. As of 2.0/3.0 the library always sets PREG_UNMATCHED_AS_NULL. Match arrays gain entries and previously-'' groups become null. Any downstream isset($m[4]) or $m[4] !== '' logic silently flips behaviour. This is the single largest migration hazard and it is invisible in a naive find-and-replace.
  • Failure mode changes from silent to fatal. Code that previously coerced null to '' now throws PcreException. Unguarded, that becomes a 500 where the old behaviour was a quietly wrong string. The risk is concentrated in request-handling and Blade paths.
  • *StrictGroups variants throw when a subpattern is optional and unmatched — powerful, but easy to apply to a pattern that legitimately has optional branches, producing intermittent production exceptions driven by input data.
  • Regex quality itself is untouched: catastrophic backtracking, pcre.backtrack_limit, UTF-8/invalid-subject handling, and JIT behaviour are all still PHP's. The package improves error handling, not pattern performance or safety.
  • Overlap risk: Laravel's own Str::match / Str::matchAll cover simple extraction cases. Without a written convention, the codebase drifts into three styles (preg_*, Str::match, Preg::match).

Key questions

  1. What percentage of our preg_* call sites sit in request/response hot paths where a new PcreException would surface as a 500 rather than a validation error?
  2. Do we run PHPStan/Larastan in CI at a level that would let the bundled extension actually pay off? If not, the ROI case weakens substantially and this becomes a style preference.
  3. Which patterns are non-literal (built from config, user input, or concatenation)? The static-analysis validation only covers literal patterns; dynamic ones get typing but no validation.
  4. Do we have call sites depending on PREG_SET_ORDER, array subjects in replace, or preg_filter? Enumerate before committing.
  5. Who owns the regex inventory and the coding standard that decides Str::match vs Preg::* vs Regex::*?
  6. Do we want a single exception-to-response mapping policy (e.g. PcreException → 422 / ValidationException) so failures are handled once, not per call site?

Integration Approach

Stack fit

  • Framework-agnostic static API means no service provider, no facade, no config publish — nothing to register in config/app.php or a bootstrap/providers.php. It drops in at any layer: validation rules, jobs, console commands, importers, middleware.
  • Statelessness makes it safe under Octane and under parallel test execution; no memoization, no globals, no static caches to warm or reset.
  • Complements rather than replaces Laravel's native string layer: keep Str:: for display/formatting helpers, use Preg::* where correctness matters (multi-group extraction, replace with callbacks, grep/split on collections).
  • Larastan + extension.neon is where the package earns its keep; treat "PHPStan extension enabled" as a hard acceptance criterion, not a nice-to-have.

Migration path

  1. Inventory first. Static grep for preg_match, preg_match_all, preg_replace, preg_replace_callback, preg_replace_callback_array, preg_grep, preg_split, preg_filter. Classify each as compatible / needs dedicated method / incompatible.
  2. Quarantine incompatibles. Flag PREG_SET_ORDER, array subjects, and preg_filter sites for manual rework or explicit exclusion rather than forcing them through.
  3. Pilot one bounded module — custom validation rules or a single importer — to observe real PREG_UNMATCHED_AS_NULL fallout and establish the exception-handling pattern.
  4. Codify the pattern, then bulk-convert the remainder file-by-file, with the offset/flag variants handled manually. Run the full test suite per file; treat any test that asserted on '' groups as a signal of intentional behaviour to preserve.
  5. Enable the PHPStan extension and ratchet the baseline down over the following sprints.
  6. Add a guardrail (PHPStan custom rule or code-review checklist) to block new raw preg_* usage in application code.

Compatibility

  • Pin ^3.x in composer.json for consistency across first-party code so that transitive resolution and direct dependency never diverge.
  • Verify the resolved PHPStan version: 3.4.0 dropped PHPStan 1.x support. Teams still on PHPStan 1.x should pin 3.3.2, or upgrade PHPStan as part of the same workstream.
  • PHP floor of 7.4 is satisfied by every supported Laravel version in scope; no constraint conflicts expected.
  • Watch for conflicts with packages that pin composer/pcre narrowly — though since composer/composer already requires ^3.0, that pressure mostly resolves in favour of 3.x.

Sequencing

  • Phase 1 (1 sprint): inventory + pilot + exception policy + PHPStan config.
  • Phase 2 (1–2 sprints): bulk conversion of application code, module by module behind normal PR review.
  • Phase 3 (ongoing): guardrail rule, baseline reduction, *StrictGroups adoption only where patterns are provably non-optional.
  • Do not lead with *StrictGroups; adopt it after conversion stabilizes, and only for patterns reviewed for optional branches.

Operational Impact

Maintenance

  • Very low ongoing cost. Static API, MIT license, no configuration surface, no runtime dependencies beyond PHP itself. Upgrades are patch-level and have historically been deprecation fixes (PHP 8.4) and type-annotation corrections.
  • The real maintenance artefact is the coding standard and the regex inventory, not the library. Budget review time for that, not for dependency maintenance.
  • Upstream is maintained by Composer's core team; cadence is steady and semver-disciplined, so a ^3.0 constraint is a low-supervision hold.

Support

  • Single exception type (PcreException) makes support tractable: one catch-and-map policy, one log channel assertion, one test helper.
  • Onboarding material is the README — thorough on semantics and limitations, but there is no separate docs site. Plan an internal one-pager covering: when to use Preg vs Regex vs Str::match, and how to handle PcreException.
  • Debuggability improves over raw preg_*: an exception with a pattern and a preg_last_error reason beats a silent null.

Scaling

  • Runtime overhead is one extra function frame per call — effectively unmeasurable against the regex engine itself. Under Octane there is no per-request warmup or state to reset.
  • Scaling risk is not throughput; it is regex cost. Untouched by this library: a pathological pattern still consumes the same CPU and still hits pcre.backtrack_limit / pcre.jit limits. If regex-heavy paths are a known latency source, pair this adoption with pattern-level profiling and input length caps.
  • Large subject strings and array-heavy grep/split workloads retain their existing memory profile; nothing here changes allocation behaviour meaningfully.

Failure modes

  • Uncaught PcreException → 500. The headline risk. Previously silent null becomes an exception. Mitigation: map PcreException centrally (exception handler / middleware) to a 422 or a domain error, and never leave conversion call sites unguarded in request paths.
  • Null-vs-empty-string regressions. PREG_UNMATCHED_AS_NULL changes array shape; downstream isset/!== '' checks silently invert. Highest-probability defect class in migration; caught only by tests that assert actual match arrays.
  • *StrictGroups input-dependent exceptions. Throws only when a group doesn't participate, so it passes in CI and fails on the one customer record with an unusual payload. Treat as production risk, not a lint.
  • Flag rejection. Passing PREG_SET_ORDER or PREG_OFFSET_CAPTURE to the wrong method throws — good, but produces a mid-migration failure rather than a compile-time one. The inventory phase front-loads these.
  • Blind spot on dynamic patterns. Non-literal patterns get typing but no static validation, so they retain full runtime risk while looking covered.

Ramp-up

  • Individual engineer: roughly half a day to be productive — README plus a handful of examples covers 90% of usage. The PREG_UNMATCHED_AS_NULL semantics table is the one thing everyone must actually read.
  • Team-level: one sprint of guided practice, anchored by the pilot module, the internal one-pager, and the guardrail rule. The static-analysis extension adds a further half-day for whoever owns the PHPStan config, since type-shape changes can surface as a wave of new baseline noise.
  • Net ramp-up cost is small and front-loaded; the corresponding reduction in silent-failure debugging across the application is the durable return.
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.
steadrun/laravel-monitor
labyrinthe/connect-laravel
elmogy/layan
drewdan/sentinel-client
dskripchenko/laravel-llm
fatryst/nuonuo
stevenay/myanfont
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc
animalyoung/laravel-influxdb
onix-solutions/sms-telera
lonely-lights/prosetta
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin