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

Polyfill Php84 Laravel Package

symfony/polyfill-php84

Symfony polyfill that backports PHP 8.4 features to earlier PHP versions, including array_find, mb_trim, mb_ucfirst, fpow, bcdivmod, grapheme_str_split, the Deprecated attribute, PDO driver subclasses, and ReflectionConstant.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require symfony/polyfill-php84
    

    Laravel’s autoloader picks it up via Composer’s files/bootstrap chain—no manual require needed. Current release to pin or track is v1.43.0 (previous assessment covered v1.38.0).

  2. First Use Case: Replace a Collection round-trip with the native array API your code will use after the PHP 8.4 upgrade:

    // Before (Laravel 9.x/10.x on PHP ≤8.3)
    $admin = collect($users)->first(fn ($user) => $user['role'] === 'admin');
    
    // After (works on 8.3 today, drops the polyfill on 8.4 automatically)
    $admin = array_find($users, fn ($user) => $user['role'] === 'admin');
    

    Verify: php -r "echo PHP_VERSION;" — you should still be on ≤8.3, yet array_find() resolves.

  3. Where to Look First:

    • Array Functions: array_find, array_find_key, array_all, array_any (replace collect()->first() / ->contains() loops).
    • Multibyte Strings: mb_trim, mb_lcfirst, mb_ucfirst — the v1.43.0 release re-aligns mb_trim() with native semantics, so behaviour now matches the 8.4 core function exactly.
    • Grapheme/Intl: grapheme_str_split, grapheme_levenshtein, Normalizer — argument validation and ill-formed UTF-8 handling were fixed in v1.43.0 to mirror the intl extension.
    • BCMath: bcdivmod and friends now validate numeric strings the same way ext-bcmath does.
    • Deprecation: #[Deprecated] for aligning custom classes with Laravel’s deprecation practices.
    • Misc: fpow, request_parse_body, http_get_last_response_headers, odbc_connection_string_should_quote(), and the UUID constants (all aligned with native in v1.43.0).

Implementation Patterns

Usage Patterns

  1. Array Operations:

    • Replace a Collection pipeline on already-materialized arrays:
      $user = array_find($rows, fn ($u) => $u['role'] === 'admin');
      $index = array_find_key($rows, fn ($u) => $u['role'] === 'admin');
      
    • Predicates:
      $allActive = array_all($users, fn ($u) => $u['active']);
      $anyAdmin  = array_any($users, fn ($u) => $u['role'] === 'admin');
      
  2. Multibyte String Handling (now native-identical as of v1.43.0):

    $cleanInput = mb_trim($request->input('name', '')); // Unicode whitespace, emoji-safe
    $title      = mb_ucfirst($request->input('title', '')); // correct for non-ASCII
    $slugish    = mb_lcfirst($request->input('title', ''));
    
  3. Grapheme-Safe User Input (validated like intl since v1.43.0):

    $chars = grapheme_str_split($request->input('nickname', '')); // clusters, not bytes
    $distance = grapheme_levenshtein($a, $b); // typo-tolerance for CJK/emoji
    
    $normalized = Normalizer::normalize($request->input('name', ''), Normalizer::FORM_C);
    if ($normalized === false) {
        // ill-formed UTF-8 — same contract as ext-intl
    }
    
  4. Deprecation Management:

    #[Deprecated('Use App\Services\V2\LegacyService instead')]
    class LegacyService { /* ... */ }
    

    Combine with Laravel’s own deprecation surface for a single warning channel.

  5. Math/Precision:

    [$quotient, $remainder] = bcdivmod('10.5', '3', 4); // ['3.5000', '0.0000']
    $power = fpow(2, -3); // 0.125 (negative exponents supported)
    

    BCMath arguments are now validated like the native extension—non-numeric strings produce the same ValueError you’ll get after upgrading.

  6. PDO and cURL:

    $pdo->setAttribute(PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT, true);
    curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_3);
    

Workflows

  1. Gradual Migration: write new code against the 8.4 API (polyfilled on ≤8.3) and leave legacy code untouched until you bump the platform requirement. The polyfill is a no-op on 8.4, so nothing to rip out later.
  2. Localization Pipelines: swap Str::of()->trim() for mb_trim() in multilingual validation:
    'name' => ['required', fn ($attr, $value) => mb_strlen(mb_trim($value)) > 2],
    
    Unicode normalization is now a realistic option for search indexes given the v1.43.0 Normalizer alignment.
  3. Testing Strategy:
    • Unit-test the edge cases the polyfill just changed: malformed UTF-8 to Normalizer::normalize(), non-string args to grapheme_str_split() / grapheme_levenshtein(), junk numeric strings to bcadd()/bcdivmod().
    • Integration-test mb_trim in FormRequests with emoji and CJK input.
    • Benchmark array_find vs collect()->first() on hot paths.
    • Keep a CI matrix leg on PHP 8.4 so you catch any remaining polyfill/native divergence before release.
  4. CI/CD: pin a minimum polyfill version so the alignment fixes actually land:
    - name: Install dependencies
      run: composer require "symfony/polyfill-php84:^1.43" --no-interaction
    

Integration Tips

  • Laravel Collections: the polyfills complement collections. Use array_find for flat arrays; keep Model::query()->first() for anything hitting the database.
  • Service Providers: wrap polyfilled calls behind a small abstraction so you can swap implementations and centralise the null-vs-false contract:
    $this->app->bind('array_finder', fn () => new class {
        public function find(array $items, callable $callback): mixed
        {
            return array_find($items, $callback);
        }
    });
    
  • Blade Templates: keep polyfill logic in @php blocks (or better, view models) rather than inline conditionals.
  • Database Seeds / Data Imports: array_all($rows, fn ($r) => filled($r['email'])) reads better than a foreach with an early return.
  • PostgreSQL UUID columns: the polyfilled UUID constants now match native, so you can reference them in migrations without a defined() guard.

Gotchas and Tips

Pitfalls

  1. null and mb_trim:

    • Behaviour: v1.43.0 aligns mb_trim() with the core function. On PHP ≤8.3 the polyfill's contract (rather than an error) governs what you get—historically TypeError before v1.38.0, deprecation-style handling after.
    • Fix: Regardless of version, sanitise at the boundary: mb_trim($value ?? ''). Don't rely on polyfill-specific error behaviour that can shift between patch releases.
  2. Ill-formed UTF-8 with Normalizer / grapheme functions:

    • Issue: before v1.43.0 the polyfill diverged from ext-intl on malformed UTF-8; that's now fixed, meaning code that "worked" may start returning false where you expected a string.
    • Fix: always null-check and validate upstream:
      $value = $request->input('name');
      if (! mb_check_encoding($value ?? '', 'UTF-8')) {
          throw ValidationException::withMessages(['name' => 'Invalid encoding']);
      }
      
  3. Grapheme argument validation:

    • Issue: grapheme_str_split() and grapheme_levenshtein() now validate arguments the way the extension does (v1.43.0). Calls that silently coerced previously will now throw.
    • Fix: cast/validate before calling—grapheme_str_split((string) $value)—and add a test with non-string input.
  4. BCMath strictness:

    • Issue: v1.43.0 fixes bcmath number validation. Strings like ' 1.0', '1e3', or '' are rejected like native, so lenient legacy input paths break.
    • Fix: normalise with trim() + is_numeric() before BCMath calls; store decimals as strings in the DB, not floats.
  5. array_find returns null, not false:

    • Issue: falsy-value confusion—0, '', false, and null all fail a naive if (!$result).
    • Fix: compare strictly, and use array_find_key when null is itself a legitimate stored value:
      $key = array_find_key($items, $callback);
      $found = $key !== null;
      
  6. PCRE version prerequisites:

    • Issue: grapheme_str_split / \X matching needs PCRE ≥10.44 on some shared hosts.
    • Fix: fall back explicitly:
      $clusters = @grapheme_str_split($s) ?: preg_split('/\X/u', $s);
      
  7. PDO driver subclasses / ODBC quoting:

    • Issue: odbc_connection_string_should_quote() was realigned in v1.43.0—if you copy-pasted its earlier (divergent) output into config, regenerate it.
    • Fix: verify with PDO::getAvailableDrivers() and PDO::getAttribute(PDO::ATTR_DRIVER_NAME) in an integration test.
  8. #[Deprecated] on old runtimes:

    • Issue: the attribute needs PHP 8.0+ to be meaningful; the polyfill loads on 7.2+, where it's inert.
    • Fix: pair it with Laravel's deprecation helper for runtime warnings.
  9. Performance:

    • Issue: polyfilled hot loops cost single-digit percentages vs. native 8.4 functions.
    • Fix: don't micro-optimise—on 8.4 the polyfill steps aside automatically. Cache at the query layer instead.

Debugging

  1. Confirm what's installed:
    composer show symfony/polyfill-php84
    
    Check the version is ≥1.43.0 before trusting the alignment fixes.
  2. Find accidental shadowing: grep -r "function array_find" app/ — a userland definition wins over the polyfill and reintroduces divergence.
  3. Diff polyfill vs. native behaviour: run the same fixture set on a PHP 8.4 container and your 8.3 container; any mismatch is either a stale polyfill or your own override.
  4. Encoding issues: log mb_check_encoding($input, 'UTF-8') and PCRE_VERSION in a middleware when grapheme/normalizer output looks wrong.
  5. Deprecation warnings: ensure error_reporting(E_ALL) in local/CI, otherwise #[Deprecated] silently passes.

Config Quirks

  1. Autoloading: the polyfill bootstraps via Composer's files autoload. Never require it manually—you'll double-register constants on some platforms.
  2. Conditional loading (rarely needed, useful when auditing): guard on the platform version rather than a hard require:
    if (PHP_VERSION_ID < 80400) {
        require __DIR__.'/../vendor/symfony/polyfill-php84/bootstrap.php';
    }
    
    In practice Composer already does this—treat the snippet as a debugging tool, not a default.
  3. Composer scripts: surface version drift early rather than at runtime:
    "scripts": {
        "post-install-cmd": ["@php artisan polyfill:doctor"]
    }
    
    // app/Console/Commands/PolyfillDoctor.php (register in routes/console.php or via withCommands)
    $this->line('PHP: '.PHP_VERSION.' | PCRE: '.PCRE_VERSION);
    $this->line('polyfill-php84: '.(\Composer\InstalledVersions::getPrettyVersion('symfony/polyfill-php84') ?? 'missing'));
    
  4. Version pinning: the v1.38.1 → v1.43.0 range contains four behaviour-alignment bug fixes. Use ^1.43 in composer.json so a composer update can't leave you on a pre-alignment release that behaves differently from production PHP 8.4.
  5. Upgrade note: none of these releases introduce breaking API changes for consumers—the fixes move the polyfill toward native. The real risk is the opposite direction: code that depended on the old, laxer validation. Re-run your suite against PHP 8.4 in CI after bumping.
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.
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator