【PHP】PHP8.1はインターフェイスの継承時に衝突したインターフェイスのメソッドの交差型を計算しない

  • 2022年4月26日
  • PHP

 題の通りです。これが問題になる時は滅多にないですし、問題になっても継承して作りたかったインターフェイスの代わりに継承元のインターフェイスらを実装すると都度宣言すればよいだけですので、さしたる問題ではないのですが私的に期待した挙動と異なっていたので紹介します。

 PHP8.1 では交差型が使える様になりました。交差型とは型の AND 演算です。&で連なった型全てを満たす型を示します。

PHP: 型宣言 – Manual#交差型

 例えば次のコードを実行した場合、PHP8.1以降では動作しますが PHP8.0 以前では文法エラーになります。

<?php
class TypeA {}
class TypeB {}

interface hasMethodA {
    public function method(): TypeA & TypeB;
}

Online PHP editor | output for aDUGK#上記コード実行デモ

また PHP8.0 から使えるunion型というものもあります。こちらはTypeA | TypeBの様に記述して型の OR 演算をします。
PHP: 型宣言 – Manual#union 型

 交差型とunion型の二種類が使えるのであれば次の様に自動で最小限の型を計算することを期待しますし、クラスで複数のインターフェイスを実装した際は実際そうなります。

<?php

interface HasMethodReturnIntOrString
{
    public function methodA(): int|string;
}
interface HasMethodReturnIntOrFloat
{
    public function methodA(): int|float;
}

/**
 * 返り値が int|string 型であるメソッド methodA の実装を約束するインターフェイスと
 * 返り値が int|float 型であるメソッド methodA の実装を約束するインターフェイスの
 * 両方を実装するクラス
 */
class HasMethodReturnInt implements HasMethodReturnIntOrString, HasMethodReturnIntOrFloat
{
    /**
     * 返り値が int|string 型 と int|float 型の両方を満たすメソッド
     * つまり (int|string) & (int|float) の計算結果である int 型の値を返すメソッド
     * @return int
     */
    public function methodA(): int
    {
        return 0;
    }

//   片方の型を満たせない場合↓の様にPHPがエラーを出力します
//   Fatal error: Declaration of HasMethodReturnInt::methodA(): string must be compatible with HasMethodReturnStringOrFloat::methodA(): int|float in ***\tmp.php on line 28
//    public function methodA(): string|int
//    {
//        return 0;
//    }
}

Online PHP editor | output for 9MjGI#↑のデモ

 PHP ではインターフェイスを定義する時、また別のインターフェイスを継承できる機能があります。この継承では複数のインターフェースをまとめて継承すると定義できます。

PHP: オブジェクト インターフェイス – Manual

 これを使う時もクラスの複数のインターフェイスの実装と同様に型の計算を行ってよしなに型を計算して欲しいのですが残念ながらそううまくいきません。次の様にエラーとなります。

<?php

interface HasMethodReturnIntOrString
{
    public function methodA(): int|string;
}
interface HasMethodReturnIntOrFloat
{
    public function methodA(): int|float;
}
// Fatal error: Declaration of HasMethodReturnIntOrString::methodA(): string|int must be compatible with HasMethodReturnIntOrFloat::methodA(): int|float in /in/IUQBd on line 5
interface HasMethodReturnInt extends HasMethodReturnIntOrString, HasMethodReturnIntOrFloat
{
}

Online PHP editor | output for ODQds#↑のデモ

 なぜか HasMethodReturnIntOrString の methodA は HasMethodReturnIntOrFloat の methodA を満たす必要があるとエラーがでます。想像止まりですが、内部的には HasMethodReturnIntOrFloat を継承した HasMethodReturnIntOrString の一時インターフェースとでもいうべきものを作り、それをまた HasMethodReturnInt に継承しようとする、段階的な継承をしているのやもしれません。

 これが問題になる時はそうそうありませんが、例の様にちょっと期待と異なる挙動をするというそんな話です。

>株式会社シーポイントラボ

株式会社シーポイントラボ

TEL:053-543-9889
営業時間:9:00~18:00(月〜金)
住所:〒432-8003
   静岡県浜松市中央区和地山3-1-7
   浜松イノベーションキューブ 315
※ご来社の際はインターホンで「316」をお呼びください

CTR IMG