Skip to content

Clock

composer require quillstack/clock

A clock based on PSR-20: Clock, with one which stands still for tests.

Why this exists

Code that calls time() cannot be tested at a particular moment, and code that takes a clock can. That is the whole of PSR-20 — one method, now(), returning a DateTimeImmutable — and this is one class that reads the system clock and one that does not move.

It is here because several packages in this framework need to know what time it is and none of them should be asking the operating system directly: the cache decides whether an entry expired, the queue decides whether a job is due. Both are tested by handing them a clock that says it is a particular Tuesday.

Requirements

  • PHP 8.1 or newer

Installation

shell
composer require quillstack/clock

Usage

Anything deciding when something happened, or whether it has expired, takes a clock rather than reading the wall clock where it stands. SystemClock is that wall clock:

php
use Quillstack\Clock\SystemClock;

$cache = new ArrayCache(new SystemClock());

FrozenClock stands still until it is moved, so a test watches something expire without waiting for it:

php
use Quillstack\Clock\FrozenClock;

$clock = new FrozenClock();
$cache = new ArrayCache($clock);

$cache->set('key', 'value', 60);
$clock->sleep(61);

$cache->get('key'); // null

It is in the sources rather than the tests, because anything taking a clock will want it.

Benchmark

Measured with quillstack/benchmark on a thousand calls to now(). Runs are interleaved and unconcurrent, each figure is the median of five, and PHP is 8.5.7.

Version
quillstack/clockv0.6.0
symfony/clockv7.4.8
lcobucci/clock3.6.0
Per call
lcobucci/clock156 ns
quillstack/clock161 ns
symfony/clock217 ns

These are the same number. All three do one thing — construct a DateTimeImmutable — and what the table measures is mostly how long PHP takes to do that. Sixty nanoseconds between the first and the last is not a reason to choose anything, and this benchmark exists to say so rather than to claim a win.

Pick on what surrounds the interface instead: symfony/clock brings a MockClock you can advance by an interval, a global Clock façade and a now() function; lcobucci/clock has a frozen clock too. This has a system clock, a frozen one, and no third file.

Tests

shell
composer test

The rest of Quillstack

This is one component of Quillstack, a PHP framework which is as simple to use as it is strict about what it does.

License

MIT. See LICENSE.

Released under the MIT License.