symfony/string
Symfony String component: object-oriented string API that handles bytes, UTF-8 code points, and grapheme clusters consistently. Includes tools for safe string manipulation and normalization, with full docs and contribution resources on symfony.com.
Installation:
composer require symfony/string
No additional configuration is required—just autoload the package.
First Use Case: Convert a string to a slug for URLs:
use Symfony\Component\String\UnicodeString;
$slug = UnicodeString::fromString('Hello World!')->slug();
// Output: 'hello-world'
Key Entry Points:
UnicodeString::fromString(): Wrap any string for Unicode-aware operations.AbstractString methods: Chainable transformations like slug(), title(), ascii(), etc.Inflector utilities: Pluralization (plural()), singularization (singular()), and case conversion.Where to Look First:
src/String/AbstractString.php (core methods) and src/String/Inflector/Inflector.php (linguistic transformations).Chain methods for declarative transformations:
$cleaned = UnicodeString::fromString($userInput)
->trim()
->lower()
->ascii()
->slug();
Use Case: Sanitizing user input for URLs, filenames, or database storage.
Handle grapheme clusters (e.g., emojis with modifiers) and wide characters:
$text = UnicodeString::fromString('👨👩👧👦'); // Family emoji (4 code points, 1 grapheme)
$length = $text->length(); // Returns 1 (grapheme-aware)
$bytes = $text->toBytes(); // Returns raw UTF-8 bytes
Use Case: Displaying character counts accurately for multilingual text (e.g., tweets, comments).
Pluralize/singularize dynamically:
use Symfony\Component\String\Inflector\EnglishInflector;
$inflector = new EnglishInflector();
$plural = $inflector->pluralize('child'); // 'children'
$singular = $inflector->singularize('traces'); // 'trace' (fixed in v8.1.0-RC1)
Use Case: Generating grammar-correct labels in UI (e.g., "1 item" vs. "5 items").
$title = UnicodeString::fromString('user profile page')
->title(); // 'User Profile Page'
$slug = UnicodeString::fromString('My Awesome Post!')
->slug(); // 'my-awesome-post'
Use Case: SEO-friendly URLs or navigation menus.
Unicode-safe startsWith(), endsWith(), and contains():
$str = UnicodeString::fromString('Hello, 世界');
$str->startsWith('Hello'); // true
$str->contains('世'); // true (handles multi-byte characters)
Use Case: Validating file extensions or parsing structured text.
Form Request Validation:
Use UnicodeString to sanitize input before validation:
use Symfony\Component\String\UnicodeString;
public function rules()
{
return [
'title' => 'required|string|max:255',
// Sanitize before validation
'description' => function ($attribute, $value, $fail) {
$cleaned = UnicodeString::fromString($value)
->trim()
->lower()
->ascii();
if ($cleaned->contains('badword')) {
$fail('Invalid content.');
}
},
];
}
Model Attribute Casting:
Cast attributes to UnicodeString in models:
use Symfony\Component\String\UnicodeString;
protected $casts = [
'slug' => UnicodeString::class,
];
// Automatically converts to UnicodeString on access
$post->slug->slug(); // Chaining works
Service Providers:
Bind the Inflector for app-wide use:
$this->app->singleton(EnglishInflector::class, function () {
return new EnglishInflector();
});
Then inject into controllers/services:
public function __construct(private EnglishInflector $inflector) {}
Blade Directives: Create a custom Blade directive for slugs:
Blade::directive('slug', function ($expression) {
return "<?php echo \\Symfony\\Component\\String\\UnicodeString::fromString({$expression})->slug(); ?>";
});
Usage:
<a href="/{{ $post->title | slug }}">{{ $post->title }}</a>
EnglishInflector across requests.$post->slug = UnicodeString::fromString($post->title)->slug();
$post->save();
UnicodeString objects where possible:
$str = UnicodeString::fromString($input);
$slug = $str->slug(); // Reuse $str
$title = $str->title(); // Reuse $str
Zero-Width Characters:
startsWith()/endsWith() may fail on strings starting/ending with zero-width characters (e.g., \u{200B}).->startsWith('...', true) (strict mode) or update to v8.0.4+.Grapheme vs. Code Point Confusion:
length() counts graphemes (e.g., emoji families = 1), while count() counts code points (e.g., emoji family = 4).->length() for display purposes, ->count() for byte/character analysis.Case Conversion Quirks:
lower()/upper() respect locale rules (e.g., Turkish dotted 'i').ascii() replaces non-ASCII characters with ?, which may not be desired for transliteration.
transliterate() (requires symfony/string v6.0+).Inflector Edge Cases:
EnglishInflector::pluralize('matrix') and adjust rules if needed.Serialization Warnings:
UnicodeString objects in v8.0+. Use __serialize()/__unserialize() or convert to strings first.Serializable or use ->toString() before serialization.Emoji Width Calculation:
width() calculations.->width() for monospace text alignment (e.g., terminal output).Inspect String Components:
$str = UnicodeString::fromString('👨👩👧👦');
dump($str->toBytes()); // Raw UTF-8 bytes
dump($str->toGraphemes()); // Array of grapheme clusters
dump($str->toCodePoints()); // Array of Unicode code points
Validate Unicode Input:
Use ->isValid() to check for malformed UTF-8:
if (!$str->isValid()) {
throw new \InvalidArgumentException('Invalid UTF-8 string');
}
Debug Inflector Rules: Override the inflector for custom rules:
$inflector = new EnglishInflector();
$inflector->addRule('matrix', 'matrices'); // Custom pluralization
Performance Profiling:
Compare UnicodeString methods with native PHP (e.g., mb_strtolower()):
$start = microtime(true);
UnicodeString::fromString($text)->lower();
$time1 = microtime(true) - $start;
$start = microtime(true);
mb_strtolower($text, 'UTF-8');
$time2 = microtime(true) - $start;
How can I help you explore Laravel packages today?