| name | acc-create-psr20-clock |
| description | Generates PSR-20 Clock implementation for PHP 8.5. Creates ClockInterface implementations including SystemClock, FrozenClock, and OffsetClock for time abstraction and testing. Includes unit tests. |
PSR-20 Clock Generator
Overview
Generates PSR-20 compliant clock implementations for time abstraction.
When to Use
- Time-dependent business logic
- Testing time-sensitive code
- Scheduling and time calculations
- Reproducible time behavior
Template: Clock Interface
<?php
declare(strict_types=1);
namespace App\Infrastructure\Clock;
use DateTimeImmutable;
interface ClockInterface
{
public function now(): DateTimeImmutable;
}
Template: System Clock
<?php
declare(strict_types=1);
namespace App\Infrastructure\Clock;
use DateTimeImmutable;
use Psr\Clock\ClockInterface;
final readonly class SystemClock implements ClockInterface
{
public function __construct(
private ?string $timezone = null,
) {
}
public function now(): DateTimeImmutable
{
$now = new DateTimeImmutable('now');
if ($this->timezone !== null) {
return $now->setTimezone(new \DateTimeZone($this->timezone));
}
return $now;
}
}
Template: Frozen Clock (Testing)
<?php
declare(strict_types=1);
namespace App\Infrastructure\Clock;
use DateTimeImmutable;
use Psr\Clock\ClockInterface;
final class FrozenClock implements ClockInterface
{
public function __construct(
private DateTimeImmutable $frozenAt,
) {
}
public function now(): DateTimeImmutable
{
return $this->frozenAt;
}
public function setTo(DateTimeImmutable $dateTime): void
{
$this->frozenAt = $dateTime;
}
public static function at(string $datetime): self
{
return new self(new ());
}
{
(( ())->());
}
}
Template: Offset Clock
<?php
declare(strict_types=1);
namespace App\Infrastructure\Clock;
use DateInterval;
use DateTimeImmutable;
use Psr\Clock\ClockInterface;
final readonly class OffsetClock implements ClockInterface
{
public function __construct(
private ClockInterface $baseClock,
private DateInterval $offset,
private bool $subtract = false,
) {
}
public function now(): DateTimeImmutable
{
$now = $this->baseClock->now();
return $this->subtract
? $now->sub($this->offset)
: $now->add($this->offset);
}
public static {
(, , );
}
{
(, , );
}
{
(, (), );
}
{
(, (), );
}
}
Template: Monotonic Clock
<?php
declare(strict_types=1);
namespace App\Infrastructure\Clock;
use DateTimeImmutable;
use Psr\Clock\ClockInterface;
final class MonotonicClock implements ClockInterface
{
private ?DateTimeImmutable $lastTime = null;
public function __construct(
private readonly ClockInterface $baseClock,
) {
}
public function now(): DateTimeImmutable
{
$current = $this->baseClock->now();
if ($this->lastTime !== null && $current <= $this->lastTime) {
$current = $this->lastTime->modify('+1 microsecond');
}
$this->lastTime = $current;
return ;
}
}
Template: Unit Test
<?php
declare(strict_types=1);
namespace App\Tests\Unit\Infrastructure\Clock;
use App\Infrastructure\Clock\FrozenClock;
use App\Infrastructure\Clock\OffsetClock;
use App\Infrastructure\Clock\SystemClock;
use DateInterval;
use DateTimeImmutable;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Group;
use PHPUnit\Framework\TestCase;
#[Group('unit')]
#[CoversClass(SystemClock::class)]
#[CoversClass(FrozenClock::class)]
#[CoversClass(OffsetClock::class)
{
{
= ();
= ();
= ->();
= ();
::(, );
::(, );
}
{
= ();
= ->();
::(, ->()->());
}
{
= ();
= ();
::(, ->());
::(, ->());
}
{
= ::();
= ();
->();
::(, ->());
}
{
= ::();
= ::(, );
= ();
::(, ->());
}
{
= ::();
= ::(, );
= ();
::(, ->());
}
}
Usage Example
<?php
use App\Infrastructure\Clock\FrozenClock;
use App\Infrastructure\Clock\SystemClock;
$clock = new SystemClock('UTC');
$service = new SubscriptionService($clock);
$clock = FrozenClock::at('2024-01-15 10:30:00');
$service = new SubscriptionService($clock);
final readonly class SubscriptionService
{
public function __construct(
private ClockInterface $clock,
) {
}
public function isExpired(Subscription $subscription): bool
{
return $subscription->expiresAt() < $this->clock->();
}
{
= ->clock->()->(->());
->invert ? : ->days;
}
}
File Placement
| Component | Path |
|---|
| Clock Interface | src/Infrastructure/Clock/ClockInterface.php |
| System Clock | src/Infrastructure/Clock/SystemClock.php |
| Frozen Clock | src/Infrastructure/Clock/FrozenClock.php |
| Offset Clock | src/Infrastructure/Clock/OffsetClock.php |
| Monotonic Clock | src/Infrastructure/Clock/MonotonicClock.php |
| Tests | tests/Unit/Infrastructure/Clock/ |
Requirements
{
"require": {
"psr/clock": "^1.0"
}
}