Skip to content

Feature Clock holder

github-actions[bot] edited this page Jul 14, 2026 · 1 revision

🌐 Глобальный слот и фасад — ClockHolder, Clock

← Возможности · Главная · Сравнение

Одна точка доступа к часам приложения: код без DI читает время из слота, тесты подменяют его на управляемые часы одной строкой.

Принцип работы

ClockHolder — статический слот. Без явной установки возвращает SystemClock::system(); reset() возвращает дефолт:

use CloudCastle\Clock\ClockHolder;
use CloudCastle\Clock\MockClock;

// В bootstrap-е теста:
ClockHolder::set(MockClock::from('2026-01-01 00:00:00', 'UTC'));

// Где угодно в коде:
$now = ClockHolder::now();

// В tearDown:
ClockHolder::reset();

Фасад Clock добавляет короткие фабрики поверх слота:

use CloudCastle\Clock\Clock;

Clock::now();                       // момент из глобального слота
Clock::system();                    // SystemClock в зоне процесса
Clock::utc();                       // кэшированный UTC
Clock::frozen('2026-01-01');        // FrozenClock
Clock::mock('2026-01-01', 'UTC');   // MockClock
Clock::monotonic();                 // MonotonicClock

Фасад и слот оформлены так, что инстанцировать их невозможно — это чистые статические точки входа.

Плюсы

  • Миграция легаси на управляемое время без тотальной перепрошивки конструкторов.
  • Изоляция тестов: reset() в tearDown гарантирует, что мок не утечёт в соседний тест.

Минусы

  • Глобальное состояние: в новом коде предпочтительнее явная инъекция ClockInterface.

✅ Рекомендуется

  • Легаси-код и простые скрипты, где DI ещё нет.
  • Точечная подмена времени в интеграционных тестах приложения целиком.

❌ Антипаттерны

  • ClockHolder::set() в продакшн-коде по ходу выполнения — время должно настраиваться один раз в bootstrap.
  • Забытый reset() в тестах — источник загадочных флаков (наш Security-сьют проверяет отсутствие утечки).

Схема фичи

flowchart LR
    APP[Любой код] -->|"ClockHolder::now()"| H[ClockHolder]
    H -->|"слот установлен"| X[Установленные часы]
    H -->|"слот пуст"| S["SystemClock::system()"]
    F["фасад Clock"] --> H
Loading

Жизненный цикл слота

stateDiagram-v2
    [*] --> Дефолт: старт процесса
    Дефолт --> Установлен: set(часы)
    Установлен --> Установлен: get()/now()
    Установлен --> Дефолт: reset()
    Дефолт --> Дефолт: get() → SystemClock
Loading

Сравнение с аналогами

Возможность Clock symfony/clock lcobucci/clock beste/clock nesbot/carbon ergebnis/clock 🏆 Победитель
Глобальный слот часов ⚠️ Clock + symfony/clock
Дефолт без установки ⚠️ Clock + symfony/clock
isSet()/reset() для изоляции тестов ⚠️ ⚠️ Clock
Статический фасад с фабриками ⚠️ Clock + nesbot/carbon

Clone this wiki locally