PHP8.1で、交差型という新しい型が登場しました。
最初、『交差? なんぞや?』と思いましたが、なんてことない、PHP8.0で追加されたunion型の『かつ(&)』バージョンです。
これも分かりづらい?
大丈夫です。コードを見れば一発で分かります。
交差型は、すべてを満たすので '&' でつなぐ
if文などの条件には、複数条件をつなぐ演算子『||(または)』『&&(かつ)』がありますよね?
それのデータ型バージョンがunion型と交差型です。
型の場合は、パイプ(|)とアンパサンド(&)がそれぞれひとつだけ。
意味も条件のときと同じ。『|(または)』『&(かつ)』
そりゃ、同じですよね? ちがったらブーイングの嵐です。
union型はPHP8.0で追加されました。
そしてPHP8.1で『&』バージョンの交差型が追加されました。
交差型の説明を言葉でするとたったこれだけ。
これ、日本語名が分かりにくい。交差って言われるとイメージが湧かない。
交差型でインタフェースの型を厳密にチェックする
ここからは実際にコードを動かしてみましょう。交差型の一番の使いどころはインタフェースです。
インタフェースは継承もでき、クラスにいくつもimplementsできます。しかし、クラスの型として使用するときはひとつしか指定できませんでした。
これが交差では厳密でピンポイントに型を指定できます。
インタフェースの親子関係はこうなってるとします。
ParentTest │ ┌──────────┐ Child1 Child2 │ │ ┌────┐ ┌────┐ Child_1_1 Child_1_2 Child_2_1 Child_2_2 |
赤線の型だけを受け入れるコードはこちら。
test()を使ってコードを実行してみましょう。もちろん、実行するPHPのバージョンは8.1です。
まずは、型が唯一合うものから。
交差型は&なので、functionのパラメータで指定した3つのインタフェースをすべてimplementsしたクラスしか受け付けません。
それ以外はすべて TypeError例外が発生します。
3つのうちいくつか欠けたもの、同じ親をもつインタフェース、全共通の親インタフェースなどいろんなパターンも実行してみましょう。
もちろん結果はすべて、TypeError例外です。
もうこのへんでいいでしょう。&(かつ)なんだから最初のコード以外通るわけがないので。
ちなみに、同じ条件のパラメータ制限をPHP7以前でやろうとすればこうなります。
このコードの場合、すべての共通の親がいるので(ParentTest)、objectはParentTestに変えてもいいですが、共通の親を持たないことも考えてobject型にしました。
どれだけコードがスリムになるのか分かるでしょう。
最後に型定義で親を指定して、その子を渡してみましょう。
一見、同じ条件のパラメータが通過するのでOKに見えますが、Child1の子が欠けたときも通るし、親のChild1をimplementsしたのも通ります。
制限がゆるくなってるのが分かるでしょう。
PHP公式ドキュメント
クラスの型は交差型を使う意味がない
インタフェースの話ばかりしてクラスはどうした? と思った人もいたでしょう。
じつはクラスでは、交差型を使う意味がありません。
ParentTest │ ┌──────────────┐ Child1 Child2 │ │ ┌─────┬─────┐ ┌─────┐ GChild_1_1 GChild_1_2 GChild_1_3 GChild_2_1 GChild_2_2 |
クラスはピラミッド構造の階層になっていて、クラスが継承できる親クラスは1つです。
クラスの型を定義するのは自身の型か親の型だけ。上記の赤線部分に制限したければ、union型を使います。
気をつけないといけないのは、if文の条件とちがって交差型とunion型の混同はできません。
もちろん、()を付けて優先度をコントロールもできない。
これが交差型の現状です。
複数のクラスを交差型で定義すると、それを通過するクラスは存在しえないので、つねにTypeError例外が出るバグになってしまいます。
親と子の交差型は通りますが、その定義には意味がありません。
(それなら子のクラスの定義だけでいい。)
クラスとインタフェースが混ざった交差型は使えるので、そこでコントロールしてもいいでしょう。
PHP公式ドキュメント
int型とbool型を交差型で指定するとどうなるのか?
ふと、intとboolで交差型したらどうなるんだろうと思いましたが、交差型で使えるのは定義されたクラスとインタフェースだけです。
useを使ったエイリアスも定義されたとはいえないので使えません。
となると実質インタフェースだけに使うんじゃないかな?
それでも十分だけど。
PHP公式ドキュメント