PHP konečně dostává vlastní typ pro dobu trvání, třídu Time\Duration.
Ten problém zná asi každý. sleep() bere sekundy, usleep() mikrosekundy, stream_set_timeout() sekundy plus mikrosekundy zvlášť a v konfiguraci knihoven se potkáte s obojím. Samotné číslo přitom neřekne nic:
<?php
$timeout = 500; // sekund? milisekund? mikrosekund?
V novince u verze PHP 8.6 je to vidět na první pohled:
<?php
use Time\Duration;
$timeout = Duration::fromMilliseconds(500);
Jak se Duration vytváří?
Třída je final readonly a nemá veřejný konstruktor. Místo něj má pojmenované tovární metody:
<?php
use Time\Duration;
Duration::fromNanoseconds(1500);
Duration::fromMicroseconds(250);
Duration::fromMilliseconds(500);
Duration::fromSeconds(30);
Duration::fromMinutes(15);
Duration::fromHours(2);
Duration::fromIso8601DurationString('PT1H30M');
Uvnitř drží tři veřejné vlastnosti: $seconds, $nanoseconds (0 až 999 999 999) a $negative.
Jak se s tím počítá?
<?php
use Time\Duration;
$sekunda = Duration::fromSeconds(1);
$pulSekundy = $sekunda->divideBy(2);
$pulDruhySekundy = $sekunda->add($pulSekundy);
var_dump($pulDruhySekundy->seconds); // int(1)
var_dump($pulDruhySekundy->nanoseconds); // int(500000000)
K dispozici jsou add(), sub(), multiplyBy(), divideBy(), negate() a absolute(). Všechny vrací novou instanci, objekt samotný je neměnný (immutable):
<?php
use Time\Duration;
$zpetne = Duration::fromHours(1)->negate();
var_dump($zpetne->negative); // bool(true)
var_dump($zpetne->absolute()->seconds); // int(3600)
A porovnávání?
Třída má vlastní obsluhu porovnání, takže operátory fungují přímo:
<?php
use Time\Duration;
$timeout = Duration::fromSeconds(30);
$limit = Duration::fromMinutes(1);
var_dump($timeout < $limit); // bool(true)
Pro řazení je tu statická compare(), kterou jde rovnou předat jako first-class callable:
<?php
use Time\Duration;
$doby = [
Duration::fromMinutes(5),
Duration::fromMilliseconds(200),
Duration::fromHours(1),
];
usort($doby, Duration::compare(...));
RFC prošlo v poměru 35 : 1 (a 2 se zdrželi). V samostatném hlasování se ještě rozhodovalo o pojmenování metod a vyhrály plné názvy multiplyBy a divideBy nad zkratkami.
Mně to přijde jako jedna z nejužitečnějších věcí v 8.6. Napsat si takovou třídu umí každý, jenže si ji dneska každá knihovna píše po svém a předávat mezi nimi dobu trvání je otrava.