cybercog/php-unicode
cybercog/php-unicode is a lightweight PHP library for safe Unicode string handling—measure, slice, reverse, and transform UTF-8 text with multibyte-aware functions. Avoid broken characters and encoding bugs when working with emoji, international input, or non-ASCII content in Laravel or plain PHP.
Architecture fit. cybercog/php-unicode is a pure-PHP, dependency-free (apart from ext-mbstring and optional ext-intl) library exposing four immutable value objects — CodePoint, UnicodeString, Grapheme, GraphemeString — built with private constructors, static factories, readonly properties, and declare(strict_types=1). That is a clean fit for Laravel applications that already use value objects and DTOs at request/form/validation boundaries, and it has no framework coupling (no service provider, facade, or global state). It slots into the service layer rather than the HTTP kernel, which keeps the blast radius small.
Integration feasibility. Low effort. Composer install, PSR-4 autoload under Cog\Unicode, PHP 8.1+. The main prerequisites are confirming ext-mbstring in the runtime image and deciding whether to require ext-intl for grapheme-level features. No persistence, queue, or config surface is introduced. A thin internal adapter (e.g., App\Support\UnicodeText) is advisable to decouple application code from the third-party API.
Technical risk. The dominant risk is maturity and adoption, not code quality: 1 GitHub star, 0 dependents, and an evidently single-maintainer project. The codebase has strong internal signals (PHPStan level 9 with strict rules, PHPUnit with data providers, CI over PHP 8.1–8.5 and both prefer-lowest/prefer-stable), but there is no evidence of production use elsewhere. Documentation drift is also visible: the public description advertises a fluent StringObject API while the repository guidance describes CodePoint/UnicodeString instead — a discrepancy that needs verification before committing to an API surface. The release date (2026-03-01) should be validated against Packagist. MIT license is permissive, so vendoring or forking is legally straightforward if the project stalls.
Key questions.
StringObject or the documented immutable UnicodeString/GraphemeString classes — and is StringObject planned, renamed, or removed?ext-intl guaranteed in our production images?UnicodeString::of() allocate one CodePoint per character (memory implications for long inputs)?mb_*?Stack fit. A Laravel 10+/PHP 8.1+ monolith or modular monolith is the intended target. The library is application-layer, not infrastructure-layer, so no new operational component is introduced. It is complementary to Laravel's Str helpers: Laravel is already mb-aware for many operations, so the library's incremental value is at the code-point and grapheme-cluster level — user-perceived character counting, truncation without splitting emoji or combining marks, and encoding conversion.
Migration path. Adopt incrementally at text boundaries rather than wholesale. Start with request normalization and validation (display names, titles, tags, search input), then extend to formatting/padding and comparison utilities. Introduce an internal wrapper class so the third-party types never leak into domain signatures; swapping to a fork or to native mb_*/grapheme_* calls then becomes a one-file change. Existing byte-based call sites (strlen, substr, ucfirst) can be replaced as they are touched, without a big-bang refactor.
Compatibility. PHP 8.1–8.5 is covered by CI. Watch for two concrete gotchas: (1) symfony/polyfill-mbstring does not satisfy an ext-mbstring requirement, so images must ship the real extension; (2) Laravel's official Docker images frequently omit ext-intl, which would make the grapheme classes unavailable at runtime rather than at install time. iconv behavior varies by platform (glibc vs musl), so conversion helpers should be tested on the actual base image. Verify PHPStan and Pint/PHP-CS-Fixer rules do not conflict with the vendor namespace.
Sequencing.
UnicodeText adapter with unit tests pinned to our domain cases.Str behavior.composer.lock.Maintenance. Very low ongoing maintenance if pinned — small surface area, no configuration, no database or network dependencies. The offsetting concern is upstream stewardship: a single-maintainer, near-zero-adoption package should be treated as "effectively ours." Assign an internal code owner, pin the exact version, and schedule a quarterly review of upstream commits and releases.
Support. Community-only support via GitHub issues, with no SLA. This is acceptable for a library of this size provided we accept that fixes may require us to patch a fork. MIT licensing makes that operationally cheap. Budget a small contingency (roughly one to two engineer-days per year) for upstream drift or takeover.
Scaling. Runtime cost is CPU-bound and per-call. The immutable design means each operation returns a new object, and codepoint/grapheme parsing can allocate one object per character — fine for names, titles, labels, and short form fields, potentially expensive on long documents or bulk import pipelines. Recommended guardrail: cap input length before calling into the library and use direct mb_*/grapheme_* for high-volume or bulk workloads. No horizontal-scaling implications beyond normal PHP worker CPU.
Failure modes.
ext-mbstring in a rebuilt image → hard fatal at runtime; gate this with a deploy-time extension check.ext-intl → grapheme classes unavailable; either require it or avoid those classes entirely.iconv conversions; validate and normalize at ingest.StringObject discrepancy) → mitigated by the internal adapter and version pinning.Str in existing code paths → mitigated by regression tests during migration.Ramp-up. Minimal. The API is small and idiomatic, and the immutable value-object style will be familiar to any developer working in a modern Laravel codebase. Expect roughly half a day for a mid-level engineer to be productive, plus a short internal README covering the adapter, the length guardrail, and the rule that large-text processing uses native mb_*. The main onboarding risk is not the API but the absence of external documentation and examples — the internal adapter and its tests should serve as the canonical reference.
How can I help you explore Laravel packages today?