cloudcastle / uuid
Все идентификаторы для PHP 8.1+: UUID 1-8 (RFC 9562), ULID, NanoID, Snowflake и Sonyflake — с PSR-20 часами, девятью формами сериализации и жёсткой валидацией
Requires
- php: >=8.1
- psr/clock: ^1.0
Requires (Dev)
- cloudcastle/clock: ^1.0
- deptrac/deptrac: ^3.0 || ^4.0
- ergebnis/composer-normalize: ^2.45
- friendsofphp/php-cs-fixer: ^3.75
- godruoyi/php-snowflake: ^3.0
- hidehalo/nanoid-php: ^2.0
- icanhazstring/composer-unused: ^0.9
- infection/infection: ^0.29 || ^0.33
- php-parallel-lint/php-parallel-lint: ^1.4
- phpdocumentor/shim: ^3.7
- phpmd/phpmd: ^2.15
- phpstan/extension-installer: ^1.4
- phpstan/phpstan: ^1.12 || ^2.1
- phpstan/phpstan-deprecation-rules: ^1.2 || ^2.0
- phpstan/phpstan-phpunit: ^1.4 || ^2.0
- phpstan/phpstan-strict-rules: ^1.6 || ^2.0
- phpunit/phpunit: ^10.5 || ^11.5
- psalm/plugin-phpunit: ^0.19 || ^0.20
- ramsey/uuid: ^4.7
- rector/rector: ^1.2 || ^2.0
- roave/security-advisories: dev-latest
- robinvdvleuten/ulid: ^5.0
- squizlabs/php_codesniffer: ^3.12 || ^4.0
- symfony/uid: ^6.4 || ^7.0
- vimeo/psalm: ^6.0
- webmozart/assert: ^1.11
Suggests
- cloudcastle/clock: Управляемое время для детерминированных временных идентификаторов (v1/v6/v7, ULID, Snowflake) в тестах
This package is auto-updated.
Last update: 2026-07-15 09:03:03 UTC
README
Все идентификаторы для PHP 8.1+ в одном пакете: UUID версий 1–8 (RFC 9562), ULID, NanoID, Snowflake и Sonyflake. PSR-20 часы во всех временных генераторах, девять форм сериализации, жёсткая валидация ввода — функциональный суперсет пяти сравниваемых библиотек.
Установка
composer require cloudcastle/uuid
Требуется PHP 8.1+. Единственная runtime-зависимость — интерфейс psr/clock.
Быстрый старт
<?php use CloudCastle\Uuid\{Uuid, Ulid, NanoIdFactory, SnowflakeFactory}; // UUID: случайный и сортируемый. Uuid::uuid4()->toString(); // 'e2b0dd0e-1c2d-4f6a-…' Uuid::uuid7()->toBytes(); // 16 байт → BINARY(16), порядок = порядку создания // Разбор любой формы: канон / hex / Base58 / ULID-форма / URN / байты. $uuid = Uuid::fromString($input); // мусор → типизированное исключение $uuid->toBase58(); // короткая ссылка $uuid->toUlid(); // мост в ULID без перекодирования // Другие семейства. Ulid::generate()->toString(); // '01ARYZ6S41…' — монотонный ULID (new NanoIdFactory())->generate(); // 'V1StGXR8_Z5jdHi6B-myT' (new SnowflakeFactory(1, 7))->generate(); // BIGINT для распределённых систем
// Киллер-фича: детерминизм в тестах — PSR-20 часы во ВСЕХ генераторах. use CloudCastle\Clock\MockClock; use CloudCastle\Uuid\UuidFactory; $factory = new UuidFactory(clock: MockClock::from('2026-01-01 00:00:00', 'UTC')); $factory->uuid7()->timestampMs(); // ровно 1767225600000 — в каждом прогоне
Больше сценариев — в wiki: на каждую возможность есть отдельная страница с примерами и сравнением с аналогами.
Возможности
Все версии UUID (v4, v7, v1/v6, v3/v5, v2 DCE, v8, Nil/Max), девять форм сериализации, ULID с мостом в UUID, NanoID, Snowflake, Sonyflake и полный детерминизм в тестах: функционально пакет покрывает возможности всех пяти сравниваемых аналогов вместе взятых.
Сводное сравнение с аналогами (генерируется автоматически из tools/features-data.php,
победитель вычисляется по фактам поддержки):
Сгенерировано из tools/features-data.php (факты о поддержке). Легенда: ✅ полностью · ⚠️ частично · 🔌 адаптер · ❌ нет · — неприменимо.
Версии UUID (RFC 9562)
| Функция | Uuid | ramsey/uuid | symfony/uid | robinvdvleuten/ulid | hidehalo/nanoid-php | godruoyi/php-snowflake | 🏆 Победитель |
|---|---|---|---|---|---|---|---|
| UUID v1 — время Григория + узел | ✅ | ✅ | ✅ | — | — | — | Паритет |
| UUID v2 — DCE Security (домен + локальный ID) | ✅ | ✅ | ❌ | — | — | — | Uuid + ramsey/uuid |
| UUID v3 / v5 — имя в пространстве имён (MD5/SHA-1) | ✅ | ✅ | ✅ | — | — | — | Паритет |
| UUID v4 — случайный | ✅ | ✅ | ✅ | — | — | — | Паритет |
| UUID v6 — переупорядоченное время (сортируемый v1) | ✅ | ✅ | ✅ | — | — | — | Паритет |
| UUID v7 — миллисекунды Unix (сортируемый) | ✅ | ✅ | ✅ | — | — | — | Паритет |
| UUID v8 — пользовательские 122 бита | ✅ | ✅ | ✅ | — | — | — | Паритет |
| Nil и Max UUID | ✅ | ✅ | ✅ | — | — | — | Паритет |
| Монотонность v7 в пределах миллисекунды | ✅ | ✅ | ✅ | — | — | — | Паритет |
Формы сериализации UUID
| Функция | Uuid | ramsey/uuid | symfony/uid | robinvdvleuten/ulid | hidehalo/nanoid-php | godruoyi/php-snowflake | 🏆 Победитель |
|---|---|---|---|---|---|---|---|
| Каноническая 8-4-4-4-12 | ✅ | ✅ | ✅ | — | — | — | Паритет |
| 16 сырых байт (BINARY-хранение) | ✅ | ✅ | ✅ | — | — | — | Паритет |
| Hex-строка (32 символа) | ✅ | ✅ | ✅ | — | — | — | Паритет |
| Base58 (22 символа) | ✅ | ❌ | ✅ | — | — | — | Uuid + symfony/uid |
| Base32/Crockford — форма ULID (26 символов) | ✅ | ❌ | ✅ | — | — | — | Uuid + symfony/uid |
| URN «urn:uuid:…» | ✅ | ✅ | ❌ | — | — | — | Uuid + ramsey/uuid |
| Десятичное 128-битное число | ✅ | ✅ | ❌ | — | — | — | Uuid + ramsey/uuid |
| GUID Microsoft (little-endian поля) | ✅ | ✅ | ❌ | — | — | — | Uuid + ramsey/uuid |
| Фигурная форма «{uuid}» | ✅ | ⚠️ | ❌ | — | — | — | Uuid |
| Умный fromString() — любая форма по длине | ✅ | ❌ | ✅ | — | — | — | Uuid + symfony/uid |
| Интроспекция: версия, вариант, метка, узел, последовательность | ✅ | ✅ | ⚠️ | — | — | — | Uuid + ramsey/uuid |
ULID
| Функция | Uuid | ramsey/uuid | symfony/uid | robinvdvleuten/ulid | hidehalo/nanoid-php | godruoyi/php-snowflake | 🏆 Победитель |
|---|---|---|---|---|---|---|---|
| Генерация ULID | ✅ | — | ✅ | ✅ | — | — | Паритет |
| Монотонный режим в пределах миллисекунды | ✅ | — | ✅ | ❌ | — | — | Uuid + symfony/uid |
| Бинарная форма 16 байт | ✅ | — | ✅ | ❌ | — | — | Uuid + symfony/uid |
| Метка времени из ULID | ✅ | — | ✅ | ✅ | — | — | Паритет |
| Мост ULID ↔ UUID (байты 1:1) | ✅ | — | ✅ | ❌ | — | — | Uuid + symfony/uid |
| Верхний и нижний регистр вывода | ✅ | — | ⚠️ | ✅ | — | — | Uuid + robinvdvleuten/ulid |
| Nil и Max ULID | ✅ | — | ✅ | ❌ | — | — | Uuid + symfony/uid |
NanoID
| Функция | Uuid | ramsey/uuid | symfony/uid | robinvdvleuten/ulid | hidehalo/nanoid-php | godruoyi/php-snowflake | 🏆 Победитель |
|---|---|---|---|---|---|---|---|
| Генерация NanoID (стандартный алфавит) | ✅ | — | — | — | ✅ | — | Паритет |
| Произвольный алфавит и длина | ✅ | — | — | — | ✅ | — | Паритет |
| Несмещённая отбраковочная выборка | ✅ | — | — | — | ✅ | — | Паритет |
| Валидация алфавита (дубликаты, мультибайт) | ✅ | — | — | — | ❌ | — | Uuid |
Snowflake и Sonyflake
| Функция | Uuid | ramsey/uuid | symfony/uid | robinvdvleuten/ulid | hidehalo/nanoid-php | godruoyi/php-snowflake | 🏆 Победитель |
|---|---|---|---|---|---|---|---|
| Snowflake (раскладка Twitter 41/5/5/12) | ✅ | — | — | — | — | ✅ | Паритет |
| Sonyflake (раскладка Sony 39/8/16) | ✅ | — | — | — | — | ✅ | Паритет |
| Разбор идентификатора на поля | ✅ | — | — | — | — | ✅ | Паритет |
| Настраиваемая эпоха | ✅ | — | — | — | — | ✅ | Паритет |
| Обнаружение отката часов без ожидания | ✅ | — | — | — | — | ⚠️ | Uuid |
| Перенос при переполнении последовательности без сна | ✅ | — | — | — | — | ⚠️ | Uuid |
Тестируемость и источники
| Функция | Uuid | ramsey/uuid | symfony/uid | robinvdvleuten/ulid | hidehalo/nanoid-php | godruoyi/php-snowflake | 🏆 Победитель |
|---|---|---|---|---|---|---|---|
| PSR-20 часы во всех временных генераторах | ✅ | ⚠️ | ❌ | ❌ | — | ⚠️ | Uuid |
| Подменяемый источник случайности | ✅ | ✅ | ❌ | ❌ | ✅ | ⚠️ | Uuid + ramsey/uuid + hidehalo/nanoid-php |
| Полный детерминизм в тестах (время + случайность) | ✅ | ⚠️ | ❌ | ❌ | ⚠️ | ⚠️ | Uuid |
| Явный момент генерации (в прошлом/будущем) | ✅ | ✅ | ✅ | ✅ | — | ❌ | Uuid + ramsey/uuid + symfony/uid + robinvdvleuten/ulid |
| Единый контракт идентификаторов + сквозное сравнение | ✅ | ❌ | ⚠️ | ❌ | ❌ | ❌ | Uuid |
| Экранирование управляющих символов в ошибках | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | Uuid |
Зависимости и вес
| Функция | Uuid | ramsey/uuid | symfony/uid | robinvdvleuten/ulid | hidehalo/nanoid-php | godruoyi/php-snowflake | 🏆 Победитель |
|---|---|---|---|---|---|---|---|
| Одна runtime-зависимость (psr/clock — только интерфейс) | ✅ | ❌ | ⚠️ | ✅ | ✅ | ✅ | Uuid + robinvdvleuten/ulid + hidehalo/nanoid-php + godruoyi/php-snowflake |
| Без polyfill и брендированных зависимостей | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ | Uuid + robinvdvleuten/ulid + hidehalo/nanoid-php + godruoyi/php-snowflake |
| Все пять семейств идентификаторов в одном пакете | ✅ | ❌ | ⚠️ | ❌ | ❌ | ❌ | Uuid |
Производительность
Замеры генерируются автоматически из composer compare: каждая пара
«библиотека × сценарий» выполняется в отдельном PHP-процессе (память одной
библиотеки не влияет на замеры другой), одинаковые циклы для всех, медиана
из 7 прогонов, Xdebug выключен. Отрыв лидера меньше 2 % честно помечается
как «Паритет лидеров».
Память меряется с байтовой точностью в тех же изолированных процессах:
добавленная пиковая память за сценарий. Дополнительно потребление памяти
самого пакета контролируется нагрузочными тестами (tests/Load — бюджеты
на 100 000+ операций).
Сгенерировано из composer compare (PHP 8.1.34). Правки в блоке будут перезаписаны.
| Сценарий | Uuid | ramsey/uuid | symfony/uid | robinvdvleuten/ulid | hidehalo/nanoid-php | godruoyi/php-snowflake | 🏆 Победитель |
|---|---|---|---|---|---|---|---|
| UUID v4: генерация до канонической строки | 1 046 205 ops/s | 610 239 ops/s | 1 018 006 ops/s | — | — | — | Uuid |
| UUID v7: генерация до канонической строки | 371 194 ops/s | 249 140 ops/s | 314 415 ops/s | — | — | — | Uuid |
| UUID v5: имя в пространстве DNS до строки | 1 180 795 ops/s | 169 722 ops/s | 742 033 ops/s | — | — | — | Uuid |
| UUID: разбор канонической строки в объект | 1 881 107 ops/s | 3 495 373 ops/s | 1 542 031 ops/s | — | — | — | ramsey/uuid |
| UUID: сериализация в Base58 | 267 701 ops/s | — | 99 551 ops/s | — | — | — | Uuid |
| UUID: разбор строки до 16 байт (для BINARY-хранения) | 1 827 324 ops/s | 1 986 579 ops/s | 850 262 ops/s | — | — | — | ramsey/uuid |
| ULID: генерация до канонической строки | 344 694 ops/s | — | 326 323 ops/s | 275 941 ops/s | — | — | Uuid |
| ULID: разбор строки в объект | 549 310 ops/s | — | 1 583 402 ops/s | 1 758 765 ops/s | — | — | robinvdvleuten/ulid |
| ULID: генерация до 16 байт (для BINARY-хранения) | 541 988 ops/s | — | 237 421 ops/s | — | — | — | Uuid |
| ULID: порядковое сравнение двух значений | 8 731 642 ops/s | — | 7 952 315 ops/s | — | — | — | Uuid |
| NanoID: генерация 21 символа | 1 413 007 ops/s | — | — | — | 530 293 ops/s | — | Uuid |
| Snowflake: генерация до десятичной строки | 552 896 ops/s | — | — | — | — | 81 348 ops/s | Uuid |
| Snowflake: разбор идентификатора на поля | 3 017 522 ops/s | — | — | — | — | 1 139 132 ops/s | Uuid |
Память — добавленная пиковая память процесса за сценарий (классы библиотеки + объекты + операции), меньше — лучше:
| Сценарий | Uuid | ramsey/uuid | symfony/uid | robinvdvleuten/ulid | hidehalo/nanoid-php | godruoyi/php-snowflake | 🏆 Победитель |
|---|---|---|---|---|---|---|---|
| UUID v4: генерация до канонической строки | 0.0 КБ | 163.7 КБ | 0.0 КБ | — | — | — | Паритет лидеров |
| UUID v7: генерация до канонической строки | 0.0 КБ | 164.5 КБ | 0.0 КБ | — | — | — | Паритет лидеров |
| UUID v5: имя в пространстве DNS до строки | 0.0 КБ | 218.8 КБ | 0.0 КБ | — | — | — | Паритет лидеров |
| UUID: разбор канонической строки в объект | 0.0 КБ | 0.0 КБ | 0.0 КБ | — | — | — | Паритет лидеров |
| UUID: сериализация в Base58 | 0.0 КБ | — | 0.0 КБ | — | — | — | Паритет лидеров |
| UUID: разбор строки до 16 байт (для BINARY-хранения) | 0.0 КБ | 0.0 КБ | 0.0 КБ | — | — | — | Паритет лидеров |
| ULID: генерация до канонической строки | 0.0 КБ | — | 0.0 КБ | 0.0 КБ | — | — | Паритет лидеров |
| ULID: разбор строки в объект | 0.0 КБ | — | 0.0 КБ | 0.0 КБ | — | — | Паритет лидеров |
| ULID: генерация до 16 байт (для BINARY-хранения) | 0.0 КБ | — | 0.0 КБ | — | — | — | Паритет лидеров |
| ULID: порядковое сравнение двух значений | 0.0 КБ | — | 0.0 КБ | — | — | — | Паритет лидеров |
| NanoID: генерация 21 символа | 0.0 КБ | — | — | — | 0.0 КБ | — | Паритет лидеров |
| Snowflake: генерация до десятичной строки | 0.0 КБ | — | — | — | — | 0.0 КБ | Паритет лидеров |
| Snowflake: разбор идентификатора на поля | 0.0 КБ | — | — | — | — | 0.0 КБ | Паритет лидеров |
Качество
Пороги ниже проставляются автоматически из конфигов пакета при генерации
документации (composer docs:sync):
Сгенерировано из конфигов проекта — правьте infection.json.dist / phpmd.xml / tools/coverage-check.php / composer.json, не таблицу.
| Порог | Значение |
|---|---|
Mutation MSI (minMsi) |
≥ 98% |
Mutation Covered MSI (minCoveredMsi) |
≥ 98% |
| Mutation timeout | 120 с |
| Покрытие строк — проект | ≥ 98% |
| Покрытие строк — каждый файл | ≥ 98% |
| Класс: цикломатическая сложность | ≤ 50 |
| Класс: полей | ≤ 15 |
| Класс: методов | ≤ 25 |
| Класс: public-методов | ≤ 20 |
| PHP (runtime) | ≥ 8.1 |
| PHP (CI-матрица) | 8.1–8.5 |
Строгость контроля качества против аналогов (значения — из конфигов, автоматически):
Сгенерировано из конфигов пакета (composer docs:sync). Уровни Uuid — из phpstan.neon / psalm.xml / infection.json.dist / phpmd.xml / deptrac.yaml; по аналогам — заявленный инструментарий из их composer.json (Composer-дистрибутивы аналогов конфигов качества не содержат, поэтому их уровни — «н/д»).
| Контроль качества | Uuid | ramsey/uuid | symfony/uid | robinvdvleuten/ulid | hidehalo/nanoid-php | godruoyi/php-snowflake | 🏆 Победитель |
|---|---|---|---|---|---|---|---|
| PHPStan | ✅ level max + strict-rules | ✅ (уровень: н/д) | ❌ | ❌ | ❌ | ✅ (уровень: н/д) | Uuid (уровень задокументирован) |
| Psalm | ✅ errorLevel 1 | ❌ | ❌ | ❌ | ❌ | ❌ | Uuid |
| Мутационное тестирование (Infection) | ✅ minMSI 98% (факт: 0 выживших) | ❌ | ❌ | ❌ | ❌ | ❌ | Uuid |
| PHPMD | ✅ 10 правил | ❌ | ❌ | ❌ | ❌ | ❌ | Uuid |
| Deptrac (архитектурные слои) | ✅ 5 слоёв | ❌ | ❌ | ❌ | ❌ | ❌ | Uuid |
| Rector (dry-run в CI) | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | Uuid |
| Код-стайл (PSR-12: phpcs + cs-fixer) | ✅ | ✅ (уровень: н/д) | ❌ | ❌ | ✅ (уровень: н/д) | ❌ | Uuid (уровень задокументирован) |
| Покрытие строк (порог на файл) | ✅ 98% (факт: 100%) | н/д | н/д | н/д | н/д | н/д | Uuid |
| Конфиги качества в дистрибутиве | ✅ поставляются | ❌ | ❌ | ❌ | ❌ | ❌ | Uuid |
composer ci # полный пайплайн качества composer check # быстрые проверки перед коммитом composer test # тесты (unit + integration + security + load + performance)
Заключение: когда что выбирать
Сильные стороны cloudcastle/uuid — пять семейств идентификаторов в одном
пакете (единственная библиотека с UUID 1–8, ULID, NanoID, Snowflake и Sonyflake
сразу), PSR-20 часы и подменяемая случайность во всех генераторах (байт-в-байт
воспроизводимая генерация в тестах), девять форм сериализации, читающих «диалекты»
и ramsey (URN, десятичная, GUID), и symfony (Base58, Base32), байтовая модель
значений с мгновенным toBytes() и жёсткая граница ввода с экранированием
управляющих символов в ошибках.
Производительность: лидер в 11 из 13 сценариев — NanoID ×2.7 к hidehalo, Snowflake ×6.8 и разбор ×2.6 к godruoyi, Base58 ×2.7 и UUID v5 +59 % к symfony, v7 +18 %, генерация ULID +6 % до строки и +128 % до 16 байт. Два сценария честно уступают ленивым парсерам: ramsey при «разборе строки» возвращает обёртку без немедленного декодирования (наш разбор сразу материализует и валидирует байты), robinvdvleuten хранит подстроки ULID без декода и проверки диапазона. Память: 0.0 КБ добавленной пиковой во всех сценариях (байтовая точность).
Слабые стороны — пакет моложе конкурентов; экосистемные интеграции (Doctrine-типы, Symfony-нормализаторы) пока отдельными пакетами не поставляются.
Честные рекомендации:
- Нужны несколько семейств идентификаторов, тестируемость времени,
BINARY-хранение —
cloudcastle/uuid: всё в одном пакете. - Глубокая экосистема Doctrine/legacy вокруг только UUID —
ramsey/uuid. - Проект на Symfony, нужен UUID/ULID со строковым выводом —
symfony/uid. - Минимальный ULID без бинарной формы —
robinvdvleuten/ulid. - Только NanoID —
hidehalo/nanoid-php. - Snowflake с Redis/Laravel-резолвером —
godruoyi/php-snowflake.
Документация
- Wiki — руководство пользователя
- Возможности — страница на каждую фичу
- Сравнение с аналогами
- Архитектура — схемы работы пакета
- API-документация
Контакты
- Email — alex-4-17@yandex.ru
- VK — https://vk.com/leha_zorin
- Telegram — @CloudCastle85
- Телефон — +79872763991
- Сетка — https://set.ki/LdYRz76
Поддержать проект
Реквизиты для поддержки автора — в DONATE.md.
Contributors
Спасибо всем, кто вносит вклад в проект: