symfony/polyfill-intl-grapheme
Native PHP polyfill for the Intl Grapheme functions, for working with UTF-8 grapheme clusters. Provides grapheme_strlen, grapheme_substr, grapheme_strpos/stripos, grapheme_extract, grapheme_str_split, and related helpers when ext-intl isn’t available.
Installation (unchanged):
composer require symfony/polyfill-intl-grapheme:^1.38
Ensure your project targets PHP 8.6+ for native grapheme_strrev() support.
First Use Case (unchanged): Reverse strings with grapheme awareness (e.g., RTL languages, emojis):
use function Symfony\Polyfill\Intl\Grapheme\grapheme_strrev;
$reversed = grapheme_strrev("مدم"); // Arabic palindrome → "مدم" (correct)
$emojiReversed = grapheme_strrev("👨👩👧👦"); // Emoji cluster preserved
Laravel Integration (unchanged):
Add a Str helper macro for consistency:
// app/Helpers/StrHelper.php
use Illuminate\Support\Str;
use function Symfony\Polyfill\Intl\Grapheme\grapheme_strrev;
Str::macro('graphemeReverse', fn($string) => grapheme_strrev($string));
RTL Language Support (unchanged):
$rtlInput = "مرحبا"; // "Hello" in Arabic
$reversed = Str::graphemeReverse($rtlInput); // "ابحرم"
Emoji/Combining Character Handling (unchanged):
$familyEmoji = "👨👩👧👦";
$reversed = Str::graphemeReverse($familyEmoji); // Cluster intact
Grapheme Splitting (new focus):
grapheme_str_split() for reliable grapheme boundaries:
$text = "éléphant";
$clusters = grapheme_str_split($text);
// Now works correctly with PCRE 8 (fixed in v1.38.1)
Palindrome Validation (unchanged):
$isPalindrome = Str::graphemeReverse($input) === $input;
Form Request Validation:
Rule::macro('graphemePalindrome', function () {
return function ($attribute, $value, $fail) {
if (Str::graphemeReverse($value) !== $value) {
$fail('The :attribute must be a grapheme palindrome.');
}
};
});
Blade Directives:
Blade::directive('reverseGraphemes', function ($expression) {
return "<?php echo Str::graphemeReverse({$expression}); ?>";
});
Stringable Trait Extension:
Stringable::macro('reverseGraphemes', function () {
return Str::graphemeReverse($this->value);
});
Search Indexing:
Use grapheme_str_split() for preprocessing RTL tokens:
$tokens = grapheme_str_split($rtlText); // Now reliable with PCRE 8
$reversedTokens = array_map('grapheme_strrev', $tokens);
PHP 8.6 Requirement (unchanged):
grapheme_strrev() is native to PHP 8.6+. Earlier versions require a fallback.PCRE 8 Compatibility (new):
grapheme_str_split() now works correctly with PCRE 8 (fixed in v1.38.1).$text = "éléphant";
$clusters = grapheme_str_split($text);
// Should split into ["é", "l", "é", "p", "h", "a", "n", "t"] (not broken clusters)
Emoji Cluster Edge Cases (unchanged):
$emoji = "👨👩👧👦";
$clusters = grapheme_str_split($emoji);
// Ensure no artificial splits between skin tone and base emoji
Performance in Loops (unchanged):
grapheme_strrev() is slower than strrev() for ASCII text. Cache results or use strrev for ASCII-only paths.Combining Character Order (unchanged):
Verify Grapheme Clusters (updated):
Use grapheme_str_split() to inspect clusters (now reliable with PCRE 8):
$clusters = grapheme_str_split("مدم");
print_r($clusters); // ["م", "د", "م"] (correct)
Compare with intl Extension (unchanged):
Cross-validate results if intl is available:
$polyfillResult = grapheme_strrev($text);
$intlResult = IntlGraphemeClusterIterator::reverse($text);
assert($polyfillResult === $intlResult, "Results mismatch!");
Check PHP/PCRE Version: Ensure compatibility:
php -r "echo PHP_VERSION_ID >= 80600 ? 'PHP 8.6+' : 'Upgrade PHP';"
php -r "echo preg_version() >= '10.42' ? 'PCRE 10.42+' : 'Check PCRE compatibility';"
Custom Fallback Logic (unchanged): Extend for unsupported PHP versions:
function grapheme_strrev($string) {
if (PHP_VERSION_ID >= 80600) {
return \grapheme_strrev($string);
}
return \Symfony\Component\Polyfill\Intl\Grapheme\StringHelper::strrev($string);
}
Laravel Service Provider (unchanged): Register globally for all requests:
Blade::composer('*', function ($view) {
if (PHP_VERSION_ID < 80600) {
$view->share('grapheme_strrev_fallback', true);
}
});
Testing RTL Scenarios (updated): Add test cases for PCRE 8 compatibility:
// tests/Feature/GraphemeSplitTest.php
public function test_pcre8_compatibility()
{
$text = "éléphant";
$clusters = grapheme_str_split($text);
$this->assertCount(8, $clusters);
}
New: Grapheme-Aware String Manipulation:
Leverage grapheme_str_split() for advanced use cases:
// Example: Reverse words in RTL text while preserving graphemes
$rtlText = "مرحبا بالعالم";
$words = grapheme_str_split($rtlText);
$reversedWords = array_reverse($words);
$reversedText = implode('', $reversedWords); // "العالم مرحبا"
How can I help you explore Laravel packages today?