-
-
Notifications
You must be signed in to change notification settings - Fork 0
Feature Clock determinism
github-actions[bot] edited this page Jul 15, 2026
·
1 revision
Киллер-фича пакета: все временные генераторы (UUID v1/v6/v7, ULID,
Snowflake, Sonyflake) принимают PSR-20 часы, а все случайные —
RandomSourceInterface. Подменили обе зависимости — генерация
воспроизводима байт в байт. Ни один из пяти аналогов так не умеет.
use CloudCastle\Clock\MockClock; // cloudcastle/clock (suggest)
use CloudCastle\Uuid\{UuidFactory, UlidFactory, SnowflakeFactory};
$clock = MockClock::from('2026-01-01 12:00:00', 'UTC');
$uuid = new UuidFactory(clock: $clock);
$ulid = new UlidFactory(clock: $clock);
$snow = new SnowflakeFactory(1, 2, clock: $clock);
$uuid->uuid7()->timestampMs(); // ровно 1767268800000
$ulid->generate()->timestampMs(); // ровно 1767268800000
$snow->generate()->timestampMs(); // ровно 1767268800000
$clock->advance(1.5); // виртуальные +1.5 секунды
$uuid->uuid7()->timestampMs(); // ровно 1767268801500Полная воспроизводимость — вместе с детерминированной случайностью:
use CloudCastle\Uuid\Contract\RandomSourceInterface;
final class SeededRandom implements RandomSourceInterface { /* ваша последовательность */ }
$factory = new UuidFactory(clock: $clock, random: new SeededRandom(…));
$factory->uuid7()->toString(); // одна и та же строка при каждом прогоне тестаЧасы не передали? Работает быстрый системный путь (microtime()) —
абстракция бесплатна для продакшна.
- Снапшот-тесты идентификаторов: сравнение строк вместо регулярных выражений.
- Замороженное время не ломает уникальность: монотонные счётчики продолжают работу.
- Никаких глобальных моков
time()и патчей функций.
- Часы задаются на фабрику, не на вызов — для «переносного» момента есть параметр
$at.
- Тесты репозиториев/фикстур с предсказуемыми ключами.
- Бэкфил данных прошлым временем:
MockClock+ advance по расписанию.
-
sleep()в тестах в ожидании новой миллисекунды — продвиньте MockClock.
flowchart TB
PSR["Psr\Clock\ClockInterface"] --> UF[UuidFactory] & LF[UlidFactory] & SF[SnowflakeFactory] & YF[SonyflakeFactory]
RS["RandomSourceInterface"] --> UF & LF & NF[NanoIdFactory]
UF & LF & SF & YF -->|"clock = null"| FAST["microtime() — быстрый путь"]
sequenceDiagram
participant T as Тест
participant M as MockClock
participant F as Фабрики
T->>M: from('2026-01-01', 'UTC')
T->>F: new …Factory(clock: M)
T->>F: generate()/uuid7()
F->>M: now() — виртуальный момент
F-->>T: идентификатор с точной меткой
T->>M: advance(3600)
T->>F: generate() — ровно +1 час
| Возможность | Uuid | ramsey/uuid | symfony/uid | robinvdvleuten/ulid | godruoyi/php-snowflake | 🏆 Победитель |
|---|---|---|---|---|---|---|
| PSR-20 часы во всех генераторах | ✅ | ❌ | ❌ | Uuid | ||
| Подмена источника случайности | ✅ | ✅ | ❌ | ❌ | Uuid + ramsey/uuid | |
| Байт-в-байт воспроизводимость | ✅ | ❌ | ❌ | Uuid | ||
| Бесплатный системный путь без часов | ✅ | ✅ | ✅ | ✅ | ✅ | Паритет |
CloudCastle Uuid · · PHP 8.1+
GitHub · Packagist · Releases · Discussions · Issues
Email · Telegram · VK · Сетка · 💜 Поддержать проект
Исходники Wiki — каталог wiki/ в репозитории (синхронизация через GitHub Actions)