《PHP8上級試験対策》クラス継承・共変性/反変性と多重継承の誤解

  • URLをコピーしました!

はじめに

PHP8の上級試験では、クラス継承に関する「共変性・反変性」や「多重継承の可否」が頻出テーマです。特に「戻り値の型は狭くできる」「引数の型は広げられる」といったルールは混乱しやすいポイント。また、問題文の言い回しによって「多重継承できるのでは?」と誤解しやすいため、正しい仕様を整理しておきましょう。

キーワード: クラス継承 / 共変性 / 反変性 / 多重継承 / Trait / 菱形継承問題

目次

共変性(戻り値の型)

  • 親クラスの戻り値より「狭い型」を子クラスで指定できる。
  • 例)親 int|float → 子 int はOK。
class Hoge {
    public function func(int $num): int|float {
        return $num * M_PI;
    }
}

class Foo extends Hoge {
    public function func(int|float $num): int {
        return intval($num * $num * M_PI);
    }
}

var_dump((new Hoge())->func(10));   // float(31.4159...)
var_dump((new Foo())->func(11.22)); // int(395)

✅ 戻り値が「狭く(int)」、引数が「広く(int|float)」なっており、正しく動作。

反変性(引数の型)

  • 親クラスの引数より「広い型」を子クラスで指定できる。
  • 上記の例で intint|float となっているのが反変性。

多重継承はできない

PHPのクラスは 多重継承をサポートしていません。次のように書くと構文エラーになります。

class Hoge2 {}
class Foo2 {}
class Bar2 extends Hoge2, Foo2 {} // ❌ Parse error

「先に定義されたものが優先される」のはTraitの話

問題文で「先に定義されたほうが優先される」とあるのは クラスの多重継承ではなく、Traitの多重利用の仕様です。

trait T1 {
    public function hello() { echo "T1"; }
}
trait T2 {
    public function hello() { echo "T2"; }
}

class MyClass {
    use T1, T2; // T2 が優先される
}

(new MyClass())->hello(); // "T2"

✅ この挙動が「菱形継承問題を避けるPHPの解決策」。クラスではなくTraitに関する話だと押さえておくことが重要です。

まとめ

  • クラス継承では「戻り値は狭く(共変性)」「引数は広く(反変性)」できる。
  • PHPのクラスは多重継承できず、構文エラーになる。
  • 「先に定義されたものが優先される」のは Traitの仕様

👉 この区別を押さえておくと、試験のひっかけ問題に惑わされずに済みます

この記事が気に入ったら
いいねしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次