symfony/polyfill-uuid
Symfony polyfill for the PHP uuid extension. It provides the uuid_* functions on PHP installations without ext-uuid, so applications and libraries can use UUID helpers without requiring the extension. Lightweight, MIT-licensed, and maintained by Symfony.
What this actually is. symfony/polyfill-uuid is a pure-PHP shim that defines the uuid_* function family when PHP's ext-uuid is not installed. It is not an application-level UUID library — it exists so code and libraries written against the extension's procedural API keep working on hosts where that extension is absent. When ext-uuid is present, the polyfill defers to the native functions. For a TPM, the right mental model is compatibility insurance, not a feature dependency.
Architecture fit. Excellent fit for Laravel/Symfony estates because it is function-level, not framework-level: no service provider, no config, no DI wiring, no runtime hooks. It slots under Str/Eloquent usage only to the extent that the underlying code path calls uuid_* functions — worth verifying, since Laravel's Str::uuid() historically delegates to ramsey/uuid rather than the extension. The genuine value is for legacy libraries, third-party SDKs, and older in-house code that call uuid_generate_v4() or uuid_create() directly, and for teams standardizing a database-UUID strategy across heterogeneous environments (shared hosting, Docker, Lambda, CI images built without PECL).
Integration feasibility. Very high. One Composer line, and it is frequently already present transitively through Symfony's polyfill bundle — meaning the "adoption" may be a pinning and policy exercise rather than a new dependency. No migration of call sites, no API surface to learn, no data model change. The realistic integration cost is measured in hours, not sprints.
Technical risk. Low absolute risk, but not zero, and the risk profile is subtle enough that a TPM should name it explicitly:
uuid_compare()/uuid_create() conformance, constant alignment with native, duplicate v1 UUIDs within the same microsecond, UUID v6/v7 and vendor-type support added only in v1.43. That is a healthy project actively closing gaps, but it means "polyfill == extension" is a maintained claim, not a settled fact. Any code that depends on exact byte-level output or comparison semantics should have contract tests.random_bytes(). Air-gapped builders, minimal containers without SYS_RANDOM, and some CI runners can fail or degrade. This is the single most likely production surprise.ramsey/uuid.Key questions for the team.
uuid_* functions actually invoked, and via which libraries? (Determines whether this is a pin-and-document task or a genuine new dependency.)ext-uuid, or is environment variance the problem we're solving?ext-uuid becomes available — do we keep the polyfill as a floor, or drop it for performance?Stack fit. Well-matched to a Laravel/Symfony monolith or a fleet of services sharing a Composer baseline. Neutral with respect to hosting model, which is the point: the same code path works on a legacy VM, a managed PaaS, a container, or a function runtime. It imposes no opinions on autoloading, caching, or database schema.
Migration path. Treat this as an inventory-then-standardize exercise rather than a rewrite:
uuid_* call sites and any hand-rolled fallbacks (e.g., md5(uniqid()) shims, conditional function_exists guards, copied snippet generators).ramsey/uuid), or delete (dead code superseded by the polyfill).Compatibility. The polyfill targets a wide PHP range, so it is safe across a mixed fleet during a PHP upgrade window — that is arguably its strongest PM-relevant property: it decouples "upgrade PHP" from "fix UUID code." Two caveats to plan around. First, because it auto-defers to native, behavior can shift silently when an environment gains ext-uuid; pin the polyfill version and add tests that assert output shape rather than exact values. Second, the polyfill tracks Symfony's release train, so lockfile discipline and scheduled update reviews matter more than usual for a package this quiet.
Sequencing. Add and pin the dependency → land parity tests in a non-production environment → roll environment by environment (dev, staging, prod) → then, and only then, remove bespoke fallback code. Removing fallbacks before the polyfill is proven in every target environment inverts the risk. Set an explicit exit criterion up front (e.g., "enable ext-uuid in base images once throughput exceeds X UUIDs/sec, or once all runtimes are PHP 8+ and PECL is permitted") so the dependency has a defined review point rather than becoming permanent by inertia.
Maintenance. Near-zero. Symfony maintains it, releases are frequent and mostly small, and the MIT license clears legal review quickly. The 685-star count and "readme, releases"-only maturity signal a utility consumed transitively rather than a destination project — low community surface area but also low churn. The reported zero dependents is almost certainly an artifact of how transitive Composer usage is counted; do not read it as abandonment.
Support. This package reduces support load by removing a class of environment-specific defects ("works locally, fails on the build box"). The trade is that documentation is thin — the README delegates to the umbrella polyfill docs. Budget a short internal runbook: what it does, why it's pinned, how to test entropy, and when to drop it. That runbook is the actual operational deliverable for a TPM here.
Scaling. Scales horizontally without issue since generation is per-process and stateless. Watch two things: raw throughput ceilings on UUID-dense workloads, and — if v1 UUIDs are in play — the node/timestamp-sharing behavior across containers, where APCu-backed state can behave differently than on a single long-lived host.
Failure modes to instrument.
random_bytes() exceptions under load or in restricted containers. Detect via error-rate alerting on UUID generation paths in staging and canary.Ramp-up. Effectively zero for engineers — the API is the extension's API and the install is one line. The onboarding effort belongs to the TPM and platform side: establishing the "why is this here," the pinning policy, and the conditions under which we retire it. Total organizational cost is measured in a few hours of coordination against a recurring, hard-to-diagnose class of cross-environment bugs — a favorable trade that is easy to defend and easy to reverse.
How can I help you explore Laravel packages today?