PHPackages                             iliaal/fast\_uuid - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. iliaal/fast\_uuid

ActivePhp-ext[Utility &amp; Helpers](/categories/utility)

iliaal/fast\_uuid
=================

Fast RFC 9562 UUID generation (v1/v2/v3/v4/v5/v6/v7/v8 + nil/max) as a PHP C extension, with a ramsey/uuid-shaped object API and procedural fast-path functions.

0.4.0(2w ago)217BSD-3-ClausePHPPHP &gt;=8.1CI passing

Since Jun 1Pushed 1w agoCompare

[ Source](https://github.com/iliaal/fast_uuid)[ Packagist](https://packagist.org/packages/iliaal/fast_uuid)[ RSS](/packages/iliaal-fast-uuid/feed)WikiDiscussions master Synced 1w ago

READMEChangelog (8)DependenciesVersions (10)Used By (0)

fast\_uuid
==========

[](#fast_uuid)

[![Tests](https://github.com/iliaal/fast_uuid/actions/workflows/tests.yml/badge.svg)](https://github.com/iliaal/fast_uuid/actions/workflows/tests.yml)[![Windows Build](https://github.com/iliaal/fast_uuid/actions/workflows/release-windows.yml/badge.svg)](https://github.com/iliaal/fast_uuid/actions/workflows/release-windows.yml)[![Version](https://camo.githubusercontent.com/853b8ae159efbb8c6089e6ec17d3d7324df10dd2b049297c2b4503d941215b87/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f696c6961616c2f666173745f75756964)](https://github.com/iliaal/fast_uuid/releases)[![License: BSD-3-Clause](https://camo.githubusercontent.com/5b18cec5d64abf4a1fb017b12bcf376f4f1aa4c91aa28a9669664f8b2666eb62/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4253442d2d332d2d436c617573652d677265656e2e737667)](https://opensource.org/licenses/BSD-3-Clause)[![Follow @iliaa](https://camo.githubusercontent.com/a54521c97521f05fbadec4bd9bcba96ff1eeaffe756a6d7338b47a628cdeb39b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f466f6c6c6f772d40696c6961612d3030303030303f7374796c653d666c6174266c6f676f3d78266c6f676f436f6c6f723d7768697465)](https://x.com/intent/follow?screen_name=iliaa)

[![fast_uuid: RFC 9562 UUIDs for PHP in pure C, 11x to 57x faster than ramsey/uuid](images/fast_uuid-hero.jpg)](images/fast_uuid-hero.jpg)

A high-performance PHP C extension for RFC 9562 / RFC 4122 UUID generation, **11x to 57x faster than `ramsey/uuid`** on v1/v4/v7 generation and 7x to 11x faster on parsing. It produces versions 1, 2 (DCE Security), 3, 4, 5, 6, 7, 8, plus nil and max. The engine is pure C (no C++/libstdc++). The object API mirrors `ramsey/uuid` under the `FastUuid` namespace, and procedural functions give a zero-allocation fast path for the hottest call sites.

Full API reference with runnable examples: [docs/index.html](docs/index.html). Benchmarks: [BENCHMARKS.md](BENCHMARKS.md).

⚡ Why it's fast
---------------

[](#-why-its-fast)

- **Batched CSPRNG**: `getrandom()` is amortized across ~500 v4s via an 8 KB per-thread buffer instead of one syscall per UUID. ramsey's per-call `random_bytes()` is the usual bottleneck.
- **No property table**: the object is 16 inline bytes plus a lazily-cached canonical string. No `HashTable`, no declared properties, custom create/free/clone/compare/cast handlers.
- **SIMD hex formatter**: x86-64 uses a runtime-dispatched SSSE3 `pshufb`-LUT path, and ARM64 uses a NEON table-lookup path. Both turn 16 bytes into 32 hex in a handful of vector ops, with a scalar LUT fallback for other architectures.
- **Procedural path**: `uuid_v4()` and friends return a `zend_string` with no object allocation, for ORM inserts and cache keys.

Requirements
------------

[](#requirements)

- PHP 8.1 through 8.6, NTS or ZTS. PHP 8.1/8.2/8.3 build via small `#if PHP_VERSION_ID` polyfills.
- x86-64 and ARM64 get the SIMD formatter automatically; other architectures fall back to the scalar path. No build flags needed either way.
- No external libraries. v1 and v6 use an internal RFC-compliant generator with a random node (multicast bit set, per RFC 9562 §5.1). v3 and v5 use PHP's bundled MD5/SHA1.

📦 Install
---------

[](#-install)

The quickest path is [PIE](https://github.com/php/pie), which resolves a prebuilt binary for your platform (Windows `x86`/`x64` `NTS`/`TS`, Linux glibc `x86_64`/`arm64`, macOS `arm64`) and falls back to a source build otherwise:

```
pie install iliaal/fast_uuid
```

Then enable it with `extension=fast_uuid` in your `php.ini`.

🛠️ Build from source
--------------------

[](#️-build-from-source)

```
phpize
./configure --enable-fast-uuid
make
make test
php -d extension="$(pwd)/modules/fast_uuid.so" -r 'echo \FastUuid\Uuid::uuid4(), "\n"; echo uuid_v7(), "\n";'
```

The arginfo header is generated from `fast_uuid.stub.php`. To regenerate after editing the stub:

```
php /path/to/php-src/build/gen_stub.php fast_uuid.stub.php
```

Object API: `FastUuid\Uuid`
---------------------------

[](#object-api-fastuuiduuid)

Static factories (all return `FastUuid\UuidInterface`):

```
uuid1(int|string|null $node = null, ?int $clockSeq = null)
uuid2(int $localDomain, int|string|null $localIdentifier = null, int|string|null $node = null, ?int $clockSeq = null)
uuid3(UuidInterface|string $ns, string $name)
uuid4()
uuid5(UuidInterface|string $ns, string $name)
uuid6(int|string|null $node = null, ?int $clockSeq = null)
uuid7(int|DateTimeInterface|null $dateTime = null)   // int = unix milliseconds
uuid8(string $bytes)                       // 16 raw bytes
fromString(string $uuid)                   // canonical, urn:uuid:, {braced}, bare 32-hex, any case
fromBytes(string $bytes)                   // 16 raw bytes
fromInteger(string $integer)               // decimal string
fromHexadecimal(Stringable|string $hex)    // 32 hex chars; Stringable covers ramsey's Type\Hexadecimal
fromDateTime(DateTimeInterface $dt, int|string|null $node = null, ?int $clockSeq = null)
isValid(string $uuid): bool

```

Instance methods:

```
toString(): string        __toString(): string      getBytes(): string        getHex(): string
getUrn(): string          getVersion(): ?int        getVariant(): int         getInteger(): string
getDateTime(): DateTimeImmutable                     getFields(): array        equals(mixed): bool
compareTo(mixed): int     jsonSerialize(): string   getTimestampMillis(): int
toBytes(): string         toHexadecimal(): string   toUrn(): string           toInteger(): string

```

- `toBytes()` / `toHexadecimal()` / `toUrn()` / `toInteger()` are aliases of `getBytes()` / `getHex()` / `getUrn()` / `getInteger()`, matching the `get*`→`to*` naming of the newer `ramsey/identifier` library.
- `getTimestampMillis()` returns the embedded timestamp as unix milliseconds for RFC time-based versions (v1, v2, v6, v7) and is much cheaper than `getDateTime()` since it builds no object; it throws `UnsupportedOperationException` for non-time-based versions and non-RFC variants.
- `Uuid::uuid7()` accepts a unix-millisecond `int` as well as a `DateTimeInterface`, which skips the DateTime machinery entirely. The procedural `uuid_v7_at(int $unixMillis)` is the fastest explicit-timestamp form.
- UUIDv7 carries sub-millisecond precision (RFC 9562 §6.2 Method 3): the sub-ms fraction is encoded in `rand_a` and a monotonic counter lives in `rand_b`, so v7s generated within the same millisecond still sort in time order (the tie-breaking counter is per process, or per thread under ZTS, so ~244 ns ties across threads or processes carry no order). `getDateTime()` reads back at millisecond precision, matching `ramsey/uuid`.
- `getVariant()` returns `0` (NCS), `2` (RFC 4122), `6` (Microsoft), `7` (future); `getVersion()` is `null` for nil/max and non-RFC variants.
- `getDateTime()` works for RFC time-based versions (v1, v2, v6, v7) and throws `FastUuid\Exception\UnsupportedOperationException` for non-time-based versions and non-RFC variants.
- `getFields()` returns an associative array of hex strings (`time_low`, `time_mid`, `time_hi_and_version`, `clock_seq_hi_and_reserved`, `clock_seq_low`, `node`). For the ramsey-shaped `FieldsInterface` / `Type` objects, use the compat layer below.
- `equals()` and `compareTo()` accept another UUID object (native, a compat wrapper, or any `Stringable` whose string form parses as a UUID) or its canonical string.
- `var_dump()` shows the value as a virtual `uuid` property, and `var_export()` output rebuilds through `Uuid::__set_state()`.

Constants: `NIL`, `MAX`, `NAMESPACE_DNS`, `NAMESPACE_URL`, `NAMESPACE_OID`, `NAMESPACE_X500`, `DCE_DOMAIN_PERSON`, `DCE_DOMAIN_GROUP`, `DCE_DOMAIN_ORG`.

Implements `FastUuid\UuidValueInterface`, which extends the lightweight `FastUuid\UuidInterface` namespace marker with the complete native instance contract. Factory return types use `UuidValueInterface`, while existing userland `UuidInterface` implementations remain valid namespace arguments.

DCE Security (v2)
-----------------

[](#dce-security-v2)

```
$u = \FastUuid\Uuid::uuid2(\FastUuid\Uuid::DCE_DOMAIN_PERSON);   // local id auto-fills from POSIX uid
$u->getVersion();        // 2
$u = \FastUuid\Uuid::uuid2(\FastUuid\Uuid::DCE_DOMAIN_GROUP, 4242);
```

The local identifier occupies bytes 0 to 3 (big-endian); the local domain is stored in byte 9. With domain PERSON or GROUP and a null identifier, the extension uses the process uid or gid; on Windows, where there is no POSIX uid/gid, an explicit `localIdentifier` is required.

Exceptions
----------

[](#exceptions)

- `FastUuid\Exception\InvalidArgumentException` (extends `\InvalidArgumentException`): a bad length, node, or integer.
- `FastUuid\Exception\InvalidUuidStringException` (extends the above): an unparseable UUID string.
- `FastUuid\Exception\UnsupportedOperationException` (extends `\LogicException`, matching `ramsey/uuid` 4.x): raised by `getDateTime()` on a non-time-based version.

Out-of-range factory inputs are rejected, not silently truncated: a v7 timestamp past the 48-bit millisecond field, a `fromDateTime` instant outside the v1 Gregorian window, a non-canonical or &gt;128-bit decimal string for `fromInteger`, a node outside `0..2^48-1`, a clock sequence outside `0..0x3fff`, or `uuid2` without an explicit local identifier for a non-PERSON/GROUP domain all throw `InvalidArgumentException`.

Procedural API
--------------

[](#procedural-api)

```
uuid_v1() uuid_v3($ns, $name) uuid_v4() uuid_v4_fast() uuid_v5($ns, $name) uuid_v6() uuid_v7() uuid_v8($bytes)
uuid_v7_at($unixMillis)  // v7 from a unix-millisecond int (no DateTime)
uuid_v1_bin() uuid_v4_bin() uuid_v6_bin() uuid_v7_bin() uuid_v4_fast_bin()  // raw 16 bytes, no string
uuid_v3_bin($ns, $name) uuid_v5_bin($ns, $name) uuid_v8_bin($bytes) uuid_v7_at_bin($unixMillis)
uuid_v4_batch($n) uuid_v7_batch($n)          // array of $n canonical strings
uuid_v4_bin_batch($n) uuid_v7_bin_batch($n)  // array of $n raw 16-byte values
uuid_to_bin($uuid)   // canonical/parsed string -> 16 raw bytes
uuid_from_bin($bytes)// 16 raw bytes -> canonical string
uuid_is_valid($uuid) // bool
fast_uuid_random_bytes($length) // batched CSPRNG bytes, $length > 0

```

`uuid_v4_fast()` uses a non-cryptographic xoshiro256\*\* PRNG. Use it only for non-security IDs. Batch count is capped at 100,000 UUIDs per call, and `fast_uuid_random_bytes()` is capped at 16 MiB per call.

ramsey/uuid compatibility layer (`FastUuid\Compat`)
---------------------------------------------------

[](#ramseyuuid-compatibility-layer-fastuuidcompat)

`compat/` is a PSR-4 (`FastUuid\Compat\`) companion package (`iliaal/fast-uuid-compat`) that provides the cold-path ramsey ergonomics on top of the C engine. It ships in this repo's `compat/` directory and is not on Packagist yet; install it as a Composer [path repository](https://getcomposer.org/doc/05-repositories.md#path) (`composer config repositories.fast-uuid-compat path /path/to/fast_uuid/compat && composer require iliaal/fast-uuid-compat:@dev`) or autoload `FastUuid\Compat\` to `compat/src/`. It provides: `UuidFactory` / `UuidFactoryInterface`, the per-version `Rfc4122\UuidV1`…`UuidV8` / `NilUuid` / `MaxUuid` / `Nonstandard\Uuid` classes, `Rfc4122\UuidV2` with `getLocalDomain()` / `getLocalIdentifier()` / `getLocalDomainName()`, `Rfc4122\UuidV6` with `fromUuidV1()` / `toUuidV1()`, `Rfc4122\Fields` and `Nonstandard\Fields` (`FieldsInterface`), `Type\Hexadecimal` / `Type\Integer` with their `TypeInterface` / `NumberInterface` contracts, the codecs (`StringCodec`, `OrderedTimeCodec`, `TimestampFirstCombCodec`, `TimestampLastCombCodec`, `GuidStringCodec`), `Guid\Guid`, the providers (`RandomGeneratorInterface`, `NodeProviderInterface`, `TimeGeneratorInterface` + defaults), and the validators (`GenericValidator`, `NonstandardValidator`). Compat UUIDs implement both modern magic serialization and Ramsey's legacy `Serializable` methods. Node arguments accept `Type\Hexadecimal`, and UUIDv2 local identifiers accept `Type\Integer`.

Generation stays on the pure-C fast path; supplying a custom `RandomGeneratorInterface` / `TimeGeneratorInterface` / `NodeProviderInterface` intentionally routes off it where needed (ramsey behaviour) so application-supplied generators win. Custom node providers feed `uuid1()`, `uuid2()`, `uuid6()`, and `fromDateTime()` when no explicit node is passed. The compat `Uuid::uuid7()` facade also accepts a unix-millisecond `int`, matching the core object API. Decoded UUID objects retain the factory's active codec for strings, bytes, and serialization. `GuidStringCodec` swaps the first three fields in text but keeps `encodeBinary()` and `decodeBytes()` in RFC network order, matching ramsey/uuid; `Guid\Guid::getBytes()` exposes Microsoft's mixed-endian byte order. `OrderedTimeCodec` and the COMB codecs change their documented binary storage order. Migration from `ramsey/uuid` is largely a `use` swap from `Ramsey\Uuid\Uuid` to `FastUuid\Compat\Uuid`. The compat package has no external dependencies beyond the extension itself.

📊 Benchmarks
------------

[](#-benchmarks)

Throughput against `ramsey/uuid` 4.9.2 and the PECL `uuid` extension 1.3.0 (libuuid-backed). PHP 8.4.22 NTS, non-debug, no sanitizers; SSSE3 hex formatter active (x86-64). Each operation runs 300,000 iterations after a 20,000-iteration warmup; reported figure is the best of 40 runs. Million ops/sec, higher is better:

Operationfast\_uuid (obj)fast\_uuid (proc)ramsey/uuidPECL uuidv4 gen→string12.6**19.5**1.100.47v1 gen→string12.3**16.5**0.298.22v7 gen→string12.1**19.8**0.66n/aparse→16 bytes23**36**3.185.28Speedup over `ramsey/uuid`: v4 11.5x to 17.7x, v1 42x to 57x, v7 18.3x to 30x, parse 7.2x to 11.3x.

Generating many at once amortizes the per-call overhead. The batch functions return an array of 100 per call; procedural binary forms (`uuid_v4_bin()` etc.) skip canonical formatting and return raw 16-byte strings. Million UUIDs/sec:

Batch operationfast\_uuid (proc)`uuid_v4_batch`22.5`uuid_v7_batch`25`uuid_v4_bin_batch`25`uuid_v7_bin_batch`**29**The `fast_uuid` operations are fast enough (~50 ns) that scheduler noise dominates a single run, so read the `fast_uuid` columns as order-of-magnitude, not three-significant-digit (roughly ±10% run-to-run). `ramsey/uuid` (~900 ns) and PECL (~2 µs) reproduce to within ~3%. Full table, the ARM64/NEON numbers, the timestamp/DateTime API breakdown, and how to reproduce are in [BENCHMARKS.md](BENCHMARKS.md).

Testing
-------

[](#testing)

```
make test                                  # run-tests.php against the built .so
```

The suite (`tests/*.phpt`) covers every version, all parse forms, per-version `getDateTime`, fields/integer, node/clockSeq, the exception hierarchy, the procedural functions, the SIMD formatter, and the full compat layer. Verified green on PHP 8.1 / 8.2 / 8.3 / 8.4 / 8.4-ZTS / 8.5 / 8.6 (0 compiler warnings) and clean under an ASan/UBSan-instrumented build.

Contributing
------------

[](#contributing)

Build instructions, the stub-to-arginfo workflow, and the test conventions are in [CONTRIBUTING.md](CONTRIBUTING.md). Run the suite against more than one PHP version when you touch C, and add an ASan/UBSan run for any change to a parse, format, or generation path.

Security
--------

[](#security)

Report a vulnerability by email to . Details and scope are in [SECURITY.md](SECURITY.md).

🔗 Native PHP extensions
-----------------------

[](#-native-php-extensions)

Companion native PHP extensions:

- **[php\_excel](https://github.com/iliaal/php_excel)**: native Excel I/O via LibXL. 7-10× faster than PhpSpreadsheet, full XLS/XLSX with formulas, formatting, and styling.
- **[mdparser](https://github.com/iliaal/mdparser)**: native CommonMark + GFM markdown parser via md4c. 15-30× faster than pure-PHP libraries.
- **[php\_clickhouse](https://github.com/iliaal/php_clickhouse)**: native ClickHouse client speaking the wire protocol directly. Picks up where SeasClick left off.
- **[pdo\_duckdb](https://github.com/iliaal/pdo_duckdb)**: PDO driver for DuckDB, analytical SQL in your PHP stack.
- **[fastjson](https://github.com/iliaal/fastjson)**: drop-in faster `ext/json`, backed by yyjson. 6× encode, 2.7× decode, 5× validate.
- **[phpser](https://github.com/iliaal/phpser)**: decoder-optimized binary serializer for cache workloads. Faster than igbinary on packed numerics and DTO batches.
- **[fastchart](https://github.com/iliaal/fastchart)**: native chart-rendering extension. 38 chart types behind one fluent OO API, SVG-canonical with PNG/JPG/WebP and optional PDF output.
- **[statgrab](https://github.com/iliaal/statgrab)**: system statistics (CPU, memory, disk, network) via libstatgrab, no parsing /proc by hand.
- **[phonetic](https://github.com/iliaal/phonetic)**: native phonetic name matching (Double Metaphone, Beider-Morse, Daitch-Mokotoff, NYSIIS, Match Rating), the encoders PHP core lacks.

License
-------

[](#license)

BSD-3-Clause. See [LICENSE](LICENSE).

---

[Follow @iliaa on X](https://x.com/iliaa) • [Blog](https://ilia.ws) • If this sped up your UUID generation, ⭐ star it!

###  Health Score

41

—

FairBetter than 87% of packages

Maintenance97

Actively maintained with recent releases

Popularity14

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity38

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~5 days

Total

8

Last Release

15d ago

PHP version history (2 changes)0.1.0PHP &gt;=8.3

0.2.0PHP &gt;=8.1

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/2838354?v=4)[iliaa](/maintainers/iliaa)[@iliaa](https://github.com/iliaa)

---

Top Contributors

[![iliaal](https://avatars.githubusercontent.com/u/158724?v=4)](https://github.com/iliaal "iliaal (63 commits)")

---

Tags

guidphpphp-extensionrfc9562uuiduuidguidextensionrfc4122rfc9562uuid7

### Embed Badge

![Health badge](/badges/iliaal-fast-uuid/health.svg)

```
[![Health](https://phpackages.com/badges/iliaal-fast-uuid/health.svg)](https://phpackages.com/packages/iliaal-fast-uuid)
```

###  Alternatives

[webpatser/laravel-uuid

Laravel integration for webpatser/uuid - High-performance drop-in UUID replacements (15% faster than Ramsey). Provides Str macros, HasUuids trait, facades, and casts. RFC 4122/9562 compliant.

1.8k17.9M141](/packages/webpatser-laravel-uuid)[ekreative/uuid-extra-bundle

Paramconverter, Normalizer and Form Type for Ramsey Uuid

18170.8k](/packages/ekreative-uuid-extra-bundle)[infocyph/uid

UUID (RFC 9562), ULID, Snowflake ID, Sonyflake ID, and TBSL generator for PHP.

116.0k1](/packages/infocyph-uid)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
