symfony/string
Symfony String offers an object-oriented API for working with text, handling bytes, UTF-8 code points, and grapheme clusters in a unified way. It provides convenient, encoding-safe methods for slicing, comparing, searching, and manipulating strings.
Build vs. buy: buy, and the decision is nearly free. symfony/string is a leaf-level library with no container, kernel, or event dispatcher — its only dependencies are polyfills. In a Laravel codebase it is very likely already in your vendor tree transitively (Symfony Console depends on it), so the real decision is not "do we add a dependency" but "do we standardize on the API we already ship." Verify with composer why symfony/string before the architecture conversation; if it is present, adoption cost is documentation and code review, not procurement or security onboarding.
Feature decisions it unblocks:
AsciiSlugger (with locale-aware transliteration) is the defensible answer for product/SEO slugs on non-English catalogs, where Str::slug() degrades into transliteration surprises. Directly informs whether your catalog, CMS, or marketplace can launch in ES/DE/FR markets without a custom slug service.substr. UnicodeString + TruncateMode lets you promise "never split a character or an emoji" as a product guarantee rather than a bug backlog item.width() (grapheme/emoji/escape-sequence aware, tracking Unicode releases) is the deciding input for fixed-width report exports, CLI tables, receipt/PDF layouts, and any "does this fit?" UI rule. This is the capability with no credible one-line replacement.camel(), kebab(), pascal(), title()/localeTitle() and inflectors (EN, plus ES) decide whether naming is a convention enforced in code or a per-team style guide — relevant for API field naming, generated scaffolding, and permission/role keys.match()/lazy-string helpers support decisions on fuzzy search, dedupe of product/customer names, and "did you mean" behavior — cheaply, without standing up a search service.Roadmap inputs. Releases track the Symfony train (5.4 → 8.1) with frequent patch drops; recent work is concentrated exactly where product risk lives: emoji width, CJK jamo, OSC/BEL terminal sequences, multibyte splice(), inflector edge cases. That tells you (a) the library is actively hardened, and (b) Unicode display correctness is a moving target — treat it as a maintained capability, not a one-time feature.
Roadmap sequencing. It is a primitive, not a platform. Adopt it inside the small number of surfaces that touch user-visible text (slugs, previews, exports, search) rather than mandating it repo-wide; a project-wide ByteString migration is a refactor with no product upside.
Adopt when most of these are true:
mb_* calls scattered across the codebase with inconsistent assumptions about bytes vs. code points vs. graphemes.Look elsewhere when:
Str already covers the need. For ASCII-ish slugs, limit, title, plural, random, and basic case conversion, Illuminate\Support\Str is sufficient and adds no API surface. Do not migrate working code for its own sake.intl/ICU territory (Collator, NumberFormatter, MessageFormatter) or symfony/translation's message catalogs, not this library.Adoption criteria checklist: confirm it is already vendored · pin the major version against your PHP floor · identify the 2–3 call sites with real product value · add a fixture set of emoji/CJK/accented strings to CI so a patch release that changes width() behavior fails loudly.
To executives (30 seconds). This is a small, MIT-licensed, actively maintained Symfony library for handling text correctly across languages and emoji. It is almost certainly already installed in our application, so we are standardizing on something we ship rather than buying anything new. It buys us three things we currently handle inconsistently: correct slugs in non-English markets, previews and notifications that never break a character in half, and text that fits in reports and exports. Cost is a version pin and a few days of engineering focus; the alternative is per-team string handling that keeps producing low-grade international bugs.
To engineering leads. Leaf-level library, polyfill-only dependencies, no framework coupling — it runs identically in HTTP, queue, and CLI contexts. It gives us an explicit unit model (ByteString / CodePointString / UnicodeString) so "length" stops being ambiguous, plus width() for display columns and locale-aware slugging/inflection. We will not do a repo-wide migration: we adopt it at the handful of call sites that touch user-visible text. Two guardrails: pin the major to our PHP floor (8.x needs PHP 8.4+; 7.x/6.4 are still maintained), and commit emoji/CJK/accent fixtures to CI because Unicode width tables move between releases — recent patch notes show exactly that churn.
To design and content partners. We can now make UI promises we previously couldn't keep — truncation that respects grapheme clusters, titles that respect locale, layouts sized in real display columns rather than character counts. Expect fewer "the ellipsis ate the emoji" defects and better-looking non-English slugs.
Ask. One owner, one version pin, three pilot call sites (slugs, truncation, export/table width), a Unicode fixture suite in CI. Revisit in a quarter with defect data from those surfaces; if the wins don't materialize, reverting is a composer remove away.
How can I help you explore Laravel packages today?