Weave Code
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 wrapper around PHP’s preg_* functions. Composer\Pcre\Preg prevents silent PCRE failures, standardizes return types (PREG_UNMATCHED_AS_NULL), and improves static analysis with a PHPStan extension for regex-aware typing.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require composer/pcre
    

    Ensure your PHP version meets requirements (7.4+ for v3.x).

  2. First Use Case: Replace preg_match with Preg::match to enforce type safety:

    use Composer\Pcre\Preg;
    
    try {
        if (Preg::match('/\d+/', 'abc123', $matches)) {
            $number = $matches[0]; // Guaranteed to be a string, no null checks needed
        }
    } catch (PcreException $e) {
        // Handle failure explicitly
    }
    
  3. Key Files to Explore:

    • src/Preg.php: Core wrapper class with all preg_* replacements.
    • src/Regex.php: Alternative API with result objects for stricter type safety.
    • extension.neon: PHPStan extension for regex validation (include in phpstan.neon).

Implementation Patterns

Core Workflows

  1. Type-Safe Matching: Use Preg::match or Regex::match for predictable returns (throws PcreException on failure):

    $result = Regex::match('/(foo)(bar)/', 'foobar');
    if ($result->matched) {
        $foo = $result->matches[1]; // Non-nullable
        $bar = $result->matches[2]; // Non-nullable
    }
    
  2. Strict Groups Handling: Enforce non-nullable groups with *StrictGroups methods:

    try {
        Preg::matchStrictGroups('/(foo)(bar)?/', 'foo', $matches);
        // $matches[2] is guaranteed to be null (not missing) if the group didn’t match
    } catch (PcreException $e) {
        // Throws if any group is missing (e.g., due to optional patterns)
    }
    
  3. Replacement Patterns: Use Preg::replaceCallback for dynamic replacements with type safety:

    $replaced = Preg::replaceCallback(
        '/(\d+)/',
        fn($match) => str_pad($match[1], 5, '0', STR_PAD_LEFT),
        '123'
    ); // Returns "00123"
    
  4. PHPStan Integration: Add to phpstan.neon:

    includes:
        - vendor/composer/pcre/extension.neon
    

    Now PHPStan validates regex syntax and infers $matches shapes:

    // PHPStan will flag invalid regex or infer $matches[1] as string
    Preg::match('/invalid[regex/', 'test', $matches);
    

Laravel-Specific Patterns

  1. Validation Rules: Replace custom regex validation with type-safe alternatives:

    use Composer\Pcre\Preg;
    
    $validator->rule(function ($attribute, $value, $fail) {
        try {
            if (!Preg::isMatch('/^[A-Z0-9]+$/', $value)) {
                $fail('Invalid format.');
            }
        } catch (PcreException) {
            $fail('Regex error.');
        }
    });
    
  2. Request Parsing: Extract query params or headers with strict groups:

    $path = request()->path();
    $result = Regex::matchStrictGroups('/^\/api\/v(\d+)\/(.+)$/', $path);
    if ($result->matched) {
        $version = $result->matches[1]; // Non-nullable
        $resource = $result->matches[2]; // Non-nullable
    }
    
  3. Blade Directives: Create custom Blade directives for regex-based templating:

    Blade::directive('regexMatch', function ($expression) {
        return "<?php
            try {
                if (Composer\Pcre\Preg::isMatch({$expression}, \$__env->data['content'])) {
                    echo 'Matched!';
                }
            } catch (Composer\Pcre\PcreException) {
                echo 'No match.';
            }
        ?>";
    });
    

    Usage in Blade:

    @regexMatch('/success/')
    
  4. Artisan Commands: Validate CLI arguments with Regex:

    protected function handle() {
        $input = $this->argument('input');
        $result = Regex::match('/^(start|stop|restart)$/', $input);
        if (!$result->matched) {
            $this->error('Invalid command.');
            return 1;
        }
        // Proceed...
    }
    

Gotchas and Tips

Pitfalls

  1. Optional Groups in *StrictGroups: Methods like matchStrictGroups throw PcreException if optional groups (e.g., (foo)?) are missing. Fix: Use non-optional patterns or handle exceptions:

    try {
        Preg::matchStrictGroups('/(foo)(bar)?/', 'foo', $matches);
    } catch (PcreException) {
        // Handle case where 'bar' is optional and missing
    }
    
  2. PREG_OFFSET_CAPTURE Limitations:

    • Use matchWithOffsets instead of passing flags to match.
    • splitWithOffsets is required for offset splits (no PREG_SPLIT_OFFSET_CAPTURE support).
  3. PHPStan Extension Quirks:

    • Requires PHPStan 1.x or 2.x (check composer.json for compatibility).
    • May produce false positives for complex regex. Exclude problematic files in phpstan.neon:
      excludeFiles:
          - 'path/to/complex-regexes.php'
      
  4. Callback Type Safety: replaceCallback callbacks must return strings. PHPStan will flag violations:

    // PHPStan error: Callback must return string
    Preg::replaceCallback('/\d+/', fn($m) => $m[0] + 1, '123');
    
  5. Deprecations:

    • PHP 8.4+ may trigger deprecation warnings. Upgrade to v3.1.4+ for fixes.

Debugging Tips

  1. Enable Strict Mode: Use Regex class for explicit result objects to debug matches:

    $result = Regex::match('/(foo)(bar)/', 'foobar');
    dump($result->matched, $result->matches); // Inspect raw output
    
  2. Regex Validation: Test regexes in isolation before integrating:

    $testCases = ['foobar', 'foo', 'bar'];
    foreach ($testCases as $case) {
        $result = Regex::match('/(foo)(bar)/', $case);
        dump($case, $result->matches);
    }
    
  3. Exception Handling: Catch PcreException for all preg_* operations to avoid silent failures:

    try {
        $filtered = Preg::grep('/^[A-Z]/', ['apple', 'Banana']);
    } catch (PcreException $e) {
        Log::error('Regex filter failed:', ['error' => $e->getMessage()]);
        $filtered = [];
    }
    

Extension Points

  1. Custom Result Objects: Extend MatchResult or ReplaceResult for project-specific needs:

    class CustomMatchResult extends MatchResult {
        public function getGroupNames(): array {
            return array_keys($this->matches);
        }
    }
    
  2. PHPStan Extensions: Add custom regex rules to extension.neon:

    parameters:
        regexes:
            email: '^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$'
    
  3. Laravel Service Provider: Bind Preg/Regex globally for convenience:

    public function register() {
        $this->app->singleton('regex', function () {
            return new Composer\Pcre\Regex();
        });
    }
    

    Usage:

    $this->regex->match('/pattern/', $subject);
    
  4. Testing: Mock Preg/Regex in tests for isolated regex logic:

    $mock = Mockery::mock('alias:Composer\Pcre\Preg');
    $mock->shouldReceive('match')
         ->with('/pattern/', 'input')
         ->andReturn(true)
         ->once();
    
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.
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
ecotone/kafka
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata