🇷🇺 Русский · 🇬🇧 English · 🇩🇪 Deutsch · 🇫🇷 Français · 🇪🇸 Español · 🇮🇹 Italiano
ClockAwareTrait — setter clock injection
Purpose
A trait for services: setClock() + protected now(); falls back to the global clock when unset. Parity with symfony ClockAwareTrait, but with no container required.
What for and how to use
Lightweight managed time for existing classes: mix in the trait, in tests call setClock(new MockClock(...)).
Example
final class ReportService
{
use ClockAwareTrait;
public function build(): Report
{
return new Report(generatedAt: $this->now());
}
}
// In a test:
$service->setClock(FrozenClock::from('2026-01-01', 'UTC'));
Anti-patterns
For new services constructor injection of ClockInterface is clearer than a setter.
Lifecycle
flowchart LR
A[Service + ClockAwareTrait] -->|now()| B{clock set?}
B -->|yes| C[Injected clock]
B -->|no| D[ClockHolder global]
Feature comparison with competitors
| Aspect | 🏆 CloudCastle | symfony | carbon | lcobucci | beste | ergebnis |
|---|---|---|---|---|---|---|
| Setter clock injection | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
| Fallback to the global clock | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
| No container required | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
Protected now() for subclasses | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
| Total | 🏆 4 | 3 | 0 | 0 | 0 | 0 |
🇷🇺 Русский · 🇬🇧 English · 🇩🇪 Deutsch · 🇫🇷 Français · 🇪🇸 Español · 🇮🇹 Italiano