Symfony Component Advent Calendar 2022の23日目の記事です。
最初に
SymfonyはPHPのフレームワークのひとつです。しかし、公式サイトの説明文には
Symfony is a set of PHP Components, a Web Application framework, a Philosophy, and a Community — all working together in harmony.
(SymfonyはPHPコンポーネントのセットで、Webアプリケーションフレームワークで、哲学、そしてコミュニティです。それらがハーモニーを奏でながら動作しています。)
と書かれている通り、PHPコンポーネントのセットで、たくさんのコンポーネントを提供しており、それらを組み合わせてひとつのフレームワークとして動作しています。Symfonyのコンポーネントは、Symfony上だけで動作するのではなく、他のPHPフレームワークやアプリケーションでも動作している強力なものが揃っています。
今回はそれらの中から、役立ちそうなもの・お薦めしたいものを紹介していきたいと思います。
※記事内ではautoloadのインポートは省略します。
時間を扱う、"Clock"
Clockは、時間を扱うコンポーネントです。Symfony 6.2から導入されました。
インストール
composer require symfony/clock
これはなに
Clock
コンポーネントは、PSR-20: Clockを拡張した、時間を扱うコンポーネントです。
PSR-20では、ClockInterface
を実装したクラスを用意して、DateTimeImmutable
を返すnow()
を用意しようと定義されています。
SymfonyのClock
コンポーネントは、PSR-20のClockInterface
を拡張した、 独自のClockInterface
を使って、PRS-20にない機能sleep()
, withTimeZone()
を実装しています。
PSR-20のClockInterface
namespace Psr\Clock;
interface ClockInterface
{
/**
* Returns the current time as a DateTimeImmutable Object
*/
public function now(): \DateTimeImmutable;
}
ClockコンポーネントのClockInterface
namespace Symfony\Component\Clock;
use Psr\Clock\ClockInterface as PsrClockInterface;
interface ClockInterface extends PsrClockInterface
{
public function sleep(float|int $seconds): void;
public function withTimeZone(\DateTimeZone|string $timezone): static;
}
now()
は現在時刻を返し、独自のsleep()
は指定された時間スリープ、withTimezone
はタイムゾーンを変更したClock
を返します。
現在時刻を返す
説明するほどでもないかもですが、now()
は現在時刻をDateTimeImmutable
返します。
use Symfony\Component\Clock\NativeClock;
$clock = new NativeClock();
// 現在時刻を返す
echo $clock->now()->format('Y-m-d h:i:s'); // 2022-12-23 07:00:00
// 10秒スリープ
$clock->sleep(10);
// タイムゾーンを変える
$newClock = $clock->withTimeZone('Asia/Tokyo');
当然ながら、オートワイヤリング可能なので、色々な箇所で$now = new DateTimeImmutable()
しなくてよくなります。
class SomeService
{
public function __construct(private readonly ClockInterface $clock)
{
}
publi function someMethod()
{
$item = new Item();
$item
->setName('商品名')
->setPrice(1000)
->setCreatedAt($this->clock->now())
;
}
}
3つのClock
Clock
ではClockInterface
を実装した3つのClockを用意しており、それぞれの用途を定めています。
クラス | 用途 | 備考 |
---|---|---|
NativeClock | 通常利用 | now() を呼ぶごとにその瞬間の時刻を返す |
MockClock | テスト用 |
sleep() はスリープしないnow() は常に同じ時刻を返す |
MonotonicClock | パフォーマンス測定用 | hrtime()を利用 |
NativeClock
とMockClock
のnow()
の違いは、実際のコードを見てもらった方が早いです。NativeClock
は常にメソッド呼び出し時にnew
していて、MockClock
はプロパティのnow
をクローンして返します。
public function now(): \DateTimeImmutable
{
return new \DateTimeImmutable('now', $this->timezone);
}
public function __construct(\DateTimeImmutable|string $now = 'now', \DateTimeZone|string $timezone = null)
{
if (\is_string($timezone)) {
$timezone = new \DateTimeZone($timezone);
}
if (\is_string($now)) {
$now = new \DateTimeImmutable($now, $timezone ?? new \DateTimeZone('UTC'));
}
$this->now = null !== $timezone ? $now->setTimezone($timezone) : $now;
}
public function now(): \DateTimeImmutable
{
return clone $this->now;
}
まとめ
今回は、Clock
を紹介しました。PSR準拠なものを使えるのは魅力的です。
(個人的にはFrozenTime的なメソッドもあったら便利だなと思いました。あ、独自で作れば良いのか)