Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
29
Help us understand the problem. What is going on with this article?
@suin

ジェネリクスがないPHPでも配列中身のタイプヒントを可能にする「Splat Operator」

More than 3 years have passed since last update.

PHP7現在ではジェネリクスっぽいタイプヒントが書けない。したがって、配列の中身の型が決まっている関数でも、タイプヒントにはarrayを受け取ることを明示するのが最大限だ。

ジェネリクスに対応している言語であれば、doSomething(array<DateTime> $dates): voidのように配列の中の型まで固められる。このおかげで、事前条件チェックが効いて期待しない型の混入にも気づきやすいが、PHPではそうもいかない。なかなか歯がゆいものがある。

<?php

/**
 * @param DateTime[] $dates
 */
function doSomething(array $dates): void
{
}

$dates = [
    new DateTime('today'),
    new DateTime('tomorrow'),
    new DateTime('yesterday'),
    null, // 🔥DateTimeじゃないものが紛れている🔥
];

doSomething($dates);

このコードは実行してもエラーにならない。

phpdoc(関数の上のコメント)にDateTime[]と書いてあるが、IDEや静的解析ツールではこれを見て検査してくれるかもしれないが、PHP実行時には何の拘束力にもならない。

PHP7.1ではstringなどのタイプヒントも実装され、いよいよphpdocでのドキュメントなしでも、関数に何を渡したら良いかを伝えられるコードが書きやすくなった。一方で、配列を受け取る関数ではまだまだphpdocを書かないとユーザやIDEに関数の仕様を伝えにくいという別の問題もある。

配列の中身をタイプヒントする裏ワザ

極めて限定的な局面になるが、配列の中身の型を明示する方法がPHPにもある。Splat Operatorを使う方法だ。...がそれだ。これは可変個引数の関数を実装するためのものだが、タイプヒントとも組み合わせることができる。

先程のコードをSplat Operatorで実装しなおすと次のようなコードになる。

<?php

function doSomething(DateTime... $dates): void
{
}

$dates = [
    new DateTime('today'),
    new DateTime('tomorrow'),
    new DateTime('yesterday'),
    null, // 🔥DateTimeじゃないものが紛れている🔥
];

doSomething(...$dates);

コレを実行すると関数呼出し時にエラーになる。

PHP Fatal error: Uncaught TypeError: Argument 4 passed to doSomething() must be an instance of DateTime, null given

Splat Operatorはあくまで可変個引数関数を実装するための機構なので限界はある。まず、配列を複数受け取る関数ではこの裏ワザは使えない。f(array $a)f(A... $a)に書き換えできるが、f(array $a, array $b)f(A... $a, B... $b)とはできない。

また、Splat Operatorは最後の引数にしか使えない。f(string $a, array $b)f(string $a, A... $b)に書き換えできるが、引数が逆のf(array $a, string $b)f(A... $a, string $b)と書くことはできない。

限定的な場面でしか使えないが、arrayとだけタイプヒントに書くよりは固いコードが書けそうではある。

29
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
suin
Qiita 4位/TypeScript入門書執筆中/TypeScripterのための座談会「YYTypeScript」主催/『実践ドメイン駆動設計』書籍邦訳レビュア/分報Slack考案/YYPHP主催/CodeIQマガジン執筆/株式会社クラフトマンソフトウェア創設/Web自動テスト「ShouldBee」の開発/TypeScript/DDD/OOP
craftsman_software
「インフラの心配は、もうおしまい」 インフラ運用を自動化し、手作業を限りなくゼロにする会社

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
29
Help us understand the problem. What is going on with this article?