PHPでクラスを多重継承したいなって思ったらトレイトを使用しよう!

レガシーな環境を引きずって開発している人なんかはずっと「PHPはクラスの多重継承が出来ないよね」って思っているのではないでしょうか。あ、僕もそう思っていましたけどね。

なんとPHP5.4からはトレイトという機能を使って多重継承をすることが出来るようになったんです!ってクラス自体を継承するわけではないので多重継承ではないのですが、多重継承でやりたかったあんなことやこんなことが出来るようになったよと言うことなので試してみました。

多重継承出来ないという現象

まずは以下のクラスがあったとします。

<?php
class A
{
    function hoge1()
    {
        echo "abc";
    }
}

class B
{
    function hoge2()
    {
        echo "def";
    }
}

多重継承したいなぁって思って、次の様にします。

<?php
class C extends A,B
{
    function hoge3()
    {
        echo "ghi";
    }
}

エラーになります。

PHP Parse error:  syntax error, unexpected ',', expecting '{' in /Users/sawarame_yasushi/workspace/document/PHP/test.php on line 18

Parse error: syntax error, unexpected ',', expecting '{' in /Users/sawarame_yasushi/workspace/document/PHP/test.php on line 18

構文エラーです。クドいようですがPHPではクラスの多重継承は出来ません。

トレイトに置き換えてみる

クラスを多重継承したいなぁって思った場合は下記のようにトレイトに置き換えることで実現できます。

<?php
trait A
{
    function hoge1()
    {
        echo "abc";
    }
}

trait B
{
    function hoge2()
    {
        echo "def";
    }
}

class C
{
    use A,B;
    function hoge3()
    {
        echo "ghi";
    }
}

継承したいclassをtraitに変更しました。クラスCでは使用したいトレイトをuseを使ってカンマ区切りで追加します。

トレイトを追加したクラスCを使ってみます。

<?php
$piyo = new C();
$piyo->hoge1();
$piyo->hoge2();
$piyo->hoge3();

実行結果

abcdefghi

出来ました!

ただ、注意しなければいけないのはトレイト自体のインスタンスは作成出来ないというところです。つまりA・Bを単独で使用することは出来ません。

PHPのマニュアルにトレイトの詳しい使い方が書いてあります。クラスでできることはほぼ出来そうですね。

以下、その他気づいたことです。

トレイトにトレイトを追加可能

トレイトにトレイトを追加することも可能です。

<?php
trait A
{
    function hoge1()
    {
        echo "abc";
    }
}

trait B
{
    use A;
    function hoge2()
    {
        echo "def";
    }
}

class C
{
    use B;
    function hoge3()
    {
        echo "ghi";
    }
}

$piyo = new C();
$piyo->hoge1();
$piyo->hoge2();
$piyo->hoge3();

実行結果

abcdefghi

autoload可能

未定義のトレイトは未定義のクラスとしてちゃんと捕まえることが出来ました。

<?php
spl_autoload_register(function($class)
{
    var_dump($class);
});

class C
{
    use B;
}

実行結果

string(1) "B"
PHP Fatal error:  Trait 'B' not found in /Users/sawarame_yasushi/workspace/document/PHP/test.php on line 9

Fatal error: Trait 'B' not found in /Users/sawarame_yasushi/workspace/document/PHP/test.php on line 9

まとめ

クラスをそのまま置き換えるっていうわけにはいかないですが、今後abstractなクラスを作成する際にはトレイトを検討してみるといいと思います。

最後に

今回の記事とは関係ない話ですが、会社のブログに寄稿させて頂きました。
PHPのジェネレータを使ってコード簡素化&メモリ節約する方法

こちらもPHPネタです。

会社のブログとの住み分けをどうしようか考えています。

コメントを残す