iliaal/fast_uuid 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

iliaal/fast_uuid

Composer 安装命令:

pie install 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.

README 文档

README

Tests Windows Build Version License: BSD-3-Clause Follow @iliaa

fast_uuid: RFC 9562 UUIDs for PHP in pure C, 11x to 57x faster than ramsey/uuid

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. Benchmarks: BENCHMARKS.md.

⚡ Why it's 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

  • 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

The quickest path is 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

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

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\UuidInterface, JsonSerializable, Stringable.

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

  • 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 >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

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)

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 (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, the per-version Rfc4122\UuidV1UuidV8 / NilUuid / MaxUuid / Nonstandard\Uuid classes, Rfc4122\UuidV2 with getLocalDomain() / getLocalIdentifier() / getLocalDomainName(), Rfc4122\UuidV6 with fromUuidV1() / toUuidV1(), Rfc4122\Fields (FieldsInterface), Type\Hexadecimal, Type\Integer, the codecs (StringCodec, OrderedTimeCodec, TimestampFirstCombCodec, TimestampLastCombCodec, GuidStringCodec), Guid\Guid, the providers (RandomGeneratorInterface, NodeProviderInterface, TimeGeneratorInterface + defaults), and the validators (GenericValidator, NonstandardValidator).

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. Factory decode methods honor the active codec: with GuidStringCodec, fromString(), fromBytes(), fromHexadecimal(), and fromInteger() interpret input as GUID mixed-endian data; use the default StringCodec for network-order integer/hex identity. 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

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:

Operation fast_uuid (obj) fast_uuid (proc) ramsey/uuid PECL uuid
v4 gen→string 12.6 19.5 1.10 0.47
v1 gen→string 12.3 16.5 0.29 8.22
v7 gen→string 12.1 19.8 0.66 n/a
parse→16 bytes 23 36 3.18 5.28

Speedup 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 operation fast_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.

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

Build instructions, the stub-to-arginfo workflow, and the test conventions are in 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

Report a vulnerability by email to ilia@ilia.ws. Details and scope are in SECURITY.md.

🔗 Native PHP extensions

Companion native PHP extensions:

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

License

BSD-3-Clause. See LICENSE.

Follow @iliaa on XBlog • If this sped up your UUID generation, ⭐ star it!

iliaal/fast_uuid 适用场景与选型建议

iliaal/fast_uuid 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 2 次下载、GitHub Stars 达 20, 最近一次更新时间为 2026 年 06 月 01 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「extension」 「uuid」 「guid」 「rfc4122」 「rfc9562」 「uuid7」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 iliaal/fast_uuid 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 iliaal/fast_uuid 我们能提供哪些服务?
定制开发 / 二次开发

基于 iliaal/fast_uuid 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 2
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 20
  • 点击次数: 41
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 20
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: BSD-3-Clause
  • 更新时间: 2026-06-01