symfony/polyfill-php84
Symfony Polyfill for PHP 8.4 features on older runtimes. Adds functions like array_find/any/all, bcdivmod, fpow, grapheme_str_split, mb_* trim/ucfirst/lcfirst, Deprecated attribute, cURL HTTP/3 constants, PDO driver subclasses, and ReflectionConstant.
Installation: Update to the latest version via Composer:
composer require symfony/polyfill-php84:^1.38.0
For development-only usage:
composer require --dev symfony/polyfill-php84:^1.38.0
First Use Case:
Leverage improved mb_* polyfills (e.g., mb_rtrim with Unicode awareness):
use Symfony\Polyfill\Php84\mb_rtrim;
$trimmed = mb_rtrim('hello🌍', ' ', 'UTF-8');
// Now correctly handles grapheme clusters (e.g., emojis)
Where to Look First:
mb_* and grapheme_str_split improvements for edge cases.PDO stubs) affect your app.Unicode-Aware String Handling:
Use fixed mb_* functions for grapheme clusters (e.g., emojis, combining characters):
use Symfony\Polyfill\Php84\mb_rtrim;
use Symfony\Polyfill\Php84\mb_trim;
$text = "hello🌍\n";
$trimmed = mb_trim($text, "\n", 'UTF-8'); // Now handles emojis correctly
PDO Stub Improvements:
If using PDO stubs, test with:
$pdo = new PDO('mysql:host=localhost;dbname=test');
$pdo->setAttribute(PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT, false);
// No longer throws errors if PHP is built without the constant.
Null Handling in mb_*:
Pass null safely to polyfilled mb_* functions:
use Symfony\Polyfill\Php84\mb_substr;
$result = mb_substr(null, 0, 1, 'UTF-8'); // Returns null (previously might error)
Grapheme Cluster Splitting:
Use grapheme_str_split for accurate Unicode splitting (fixed for PCRE < 10.44):
use Symfony\Polyfill\Php84\grapheme_str_split;
$split = grapheme_str_split("a👨👩👧👦b"); // ['a', '👨👩👧👦', 'b']
Testing Unicode Edge Cases:
Add tests for grapheme clusters and mb_* functions:
test('mb_rtrim handles emojis', function () {
$text = "hello🌍\n";
$result = mb_rtrim($text, "\n", 'UTF-8');
expect($result)->toBe("hello🌍");
});
PDO Configuration Validation:
Validate PDO stubs in CI/CD:
jobs:
test:
steps:
- run: vendor/bin/phpunit --filter testPDOStub
Gradual Migration to PHP 8.4+ Features:
Replace custom mb_* logic with polyfills incrementally:
// Before (custom):
function custom_mb_rtrim($str, $chars, $encoding) { ... }
// After:
use Symfony\Polyfill\Php84\mb_rtrim;
Laravel Validation Rules: Extend validation with Unicode-aware polyfills:
use Symfony\Polyfill\Php84\mb_strlen;
use Illuminate\Validation\Rule;
Rule::macro('unicodeMax', function ($max) {
return function ($attribute, $value, $fail) {
if (mb_strlen($value, 'UTF-8') > $max) {
$fail('The :attribute may not be greater than '.$max.' characters.');
}
};
});
Custom Helpers for grapheme_str_split:
Encapsulate usage in a helper:
// app/Helpers/StringHelper.php
namespace App\Helpers;
use Symfony\Polyfill\Php84\grapheme_str_split;
class StringHelper {
public static function splitGraphemes($string) {
return grapheme_str_split($string);
}
}
Artisan Commands with Unicode: Use polyfills in CLI tools:
use Symfony\Polyfill\Php84\mb_strtoupper;
use Illuminate\Console\Command;
class UppercaseCommand extends Command {
protected $signature = 'app:uppercase {text}';
public function handle() {
$upper = mb_strtoupper($this->argument('text'), 'UTF-8');
$this->info($upper);
}
}
Database Seeding with mb_*:
Handle Unicode in seeders:
use Symfony\Polyfill\Php84\mb_strlen;
$user = User::create([
'name' => 'José🌍',
'slug' => mb_strtolower(mb_substr('José🌍', 0, 10, 'UTF-8'), 'UTF-8'),
]);
PCRE Version Dependencies:
grapheme_str_split may still behave differently on PCRE < 10.44. Test with:
if (version_compare(preg_version(), '10.44', '<')) {
$this->warn('PCRE <10.44 may affect grapheme splitting');
}
PDO Stub Edge Cases:
The ReflectionConstant stub for PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT may cause issues if:
Null Handling in mb_*:
While mb_* functions now accept null, ensure your code handles null returns:
$result = mb_substr(null, 0, 1, 'UTF-8');
if ($result === null) { ... }
Performance with Large Unicode Strings:
Polyfilled mb_* functions may still be slower than native PHP 8.4+. Benchmark:
$largeText = str_repeat("a🌍", 1000);
$start = microtime(true);
mb_strlen($largeText, 'UTF-8');
$time = microtime(true) - $start;
Deprecated Attributes:
The Deprecated attribute remains unchanged but may not trigger warnings in all PHP versions. Test in your target environment.
Undefined Function Errors:
If mb_* or grapheme_str_split fail, ensure:
composer dump-autoload).Symfony\Polyfill\Php84\mb_rtrim).PDO Stub Warnings:
If you see Undefined constant errors for PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT, add a runtime check:
if (!defined('PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT')) {
define('PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT', 0x00000100);
}
Unicode Normalization Issues:
Polyfilled mb_* functions assume UTF-8 input. Validate encoding:
if (!mb_check_encoding($string, 'UTF-8')) {
throw new \InvalidArgumentException('String must be UTF-8 encoded');
}
Autoloading: If polyfills aren’t recognized, regenerate the autoloader:
composer dump-autoload --optimize
Environment-Specific Loading:
Load polyfills conditionally in bootstrap/app.php:
if (version_compare(PHP_VERSION, '8.4.0', '<')) {
require __DIR__.'/../vendor/autoload.php';
}
Laravel Mix: No changes needed for frontend builds, but
How can I help you explore Laravel packages today?