symfony/string
Object-oriented string handling for PHP with unified support for raw bytes, UTF-8 code points, and grapheme clusters. Provides robust, consistent string manipulation utilities as part of the Symfony ecosystem.
Installation:
composer require symfony/string
No configuration is required—just autoload the package.
First Use Case: Convert a string to lowercase and slugify it:
use Symfony\Component\String\UnicodeString;
$string = new UnicodeString('Hello World!');
$slug = $string->lower()->slug();
// Output: 'hello-world'
Key Entry Points:
UnicodeString: Core class for all string operations.Inflector: For pluralization/singularization (e.g., traces → trace).Slugger: Specialized slug generation (e.g., Café au lait → cafe-au-lait).Where to Look First:
Chain methods for common operations:
$string = new UnicodeString(' Hello, WORLD! ');
$cleaned = $string
->trim()
->lower()
->replace(['world' => 'Laravel'])
->slug();
// Output: 'hello-laravel'
Handle grapheme clusters (e.g., emojis, combined characters):
$string = new UnicodeString('👨👩👧👦'); // Family emoji (5 graphemes)
$length = $string->count(); // Returns 5, not 1
Pluralize/singularize dynamically:
use Symfony\Component\String\Inflector\EnglishInflector;
$inflector = new EnglishInflector();
$singular = $inflector->singularize('traces'); // 'trace'
$plural = $inflector->pluralize('child'); // 'children'
Generate SEO-friendly URLs:
$slug = (new UnicodeString('Café au lait!'))
->slug('en', '_'); // 'cafe_au_lait'
Strip tags, escape HTML, or validate formats:
$clean = (new UnicodeString('<script>alert(1)</script>'))
->stripTags();
// Output: ''
Service Provider Binding:
Bind UnicodeString as a singleton for global use:
use Symfony\Component\String\UnicodeString;
public function register()
{
$this->app->singleton(UnicodeString::class, function () {
return new UnicodeString('');
});
}
Form Request Sanitization:
Use in FormRequest validation:
public function rules()
{
return [
'title' => 'required|string|max:255',
'slug' => 'required|string|unique:posts',
];
}
public function prepareForValidation()
{
$this->merge([
'slug' => UnicodeString::fromString($this->title)->slug(),
]);
}
Model Observers: Auto-slugify titles on save:
use Illuminate\Database\Eloquent\Model;
use Symfony\Component\String\UnicodeString;
class Post extends Model
{
protected static function booted()
{
static::saving(function ($post) {
if (empty($post->slug)) {
$post->slug = UnicodeString::fromString($post->title)->slug();
}
});
}
}
Blade Directives: Create custom Blade helpers:
Blade::directive('slug', function ($expression) {
return "<?php echo \\Symfony\\Component\\String\\UnicodeString::fromString({$expression})->slug(); ?>";
});
Usage:
<h1>{{ slug($post->title) }}</h1>
Inflector instances (they’re stateless but heavy to instantiate).UnicodeString::fromString() for bulk operations:
$strings = ['Hello', 'World'];
$slugs = array_map(fn ($s) => UnicodeString::fromString($s)->slug(), $strings);
UnicodeString in PHPUnit tests:
$this->assertEquals(
'hello-world',
UnicodeString::fromString('Hello World')->slug()
);
$this->assertEquals(2, UnicodeString::fromString('👨👩👧👦')->count());
UTF-8 Assumption:
ISO-8859-1) may cause unexpected behavior.$string = UnicodeString::fromString(mb_convert_encoding($rawString, 'UTF-8'));
Grapheme Cluster Quirks:
count() or substring() treat grapheme clusters (e.g., emojis with skin tones) as single units. This may differ from byte-based expectations.$string = UnicodeString::fromString('A👨👩👧👦B');
$string->count(); // 3 (A, emoji, B), not 6
Case-Insensitive Methods:
startsWith()/endsWith() are case-sensitive by default. Use lower()/upper() first if needed:
$string = UnicodeString::fromString('Hello');
$string->startsWith('h'); // false
$string->lower()->startsWith('h'); // true
Deprecated __sleep/__wakeup:
UnicodeString subclasses (deprecated since Symfony 7.4). Use __serialize()/__unserialize() instead.Slugger Locale Dependencies:
slug('en') vs. slug('es')). Omit the locale for default behavior:
$string->slug(); // Uses default locale
Performance with Large Strings:
replace() or trim() may be slow for very long strings (e.g., >1MB). Consider preprocessing or chunking:
$string->chunk(1000)->map(fn ($chunk) => $chunk->slug());
Inspect String Data:
Use toString(), toBytes(), or toGraphemeClusters() to debug:
$string = UnicodeString::fromString('Café');
$string->toBytes(); // [0x43, 0x61, 0xC3, 0xA9]
$string->toGraphemeClusters(); // ['C', 'a', 'f', 'é']
Enable Strict Typing: Enable PHP’s strict types to catch type-related issues early:
declare(strict_types=1);
Check for Zero-Width Characters:
Methods like startsWith() may fail on strings ending with zero-width characters (e.g., \u{200B}). Trim or normalize first:
$string = UnicodeString::fromString("Hello\u{200B}");
$string->trim()->startsWith('H'); // true
Custom Inflectors:
Extend AbstractInflector for domain-specific rules:
use Symfony\Component\String\Inflector\AbstractInflector;
class CustomInflector extends AbstractInflector
{
protected function getRules(): array
{
return [
'plural' => [
'rule' => '/(quiz)$/i',
'replacement' => '$1zes',
],
];
}
}
Subclassing UnicodeString:
Create domain-specific string handlers:
class DomainString extends UnicodeString
{
public function to
How can I help you explore Laravel packages today?