Help us understand the problem. What is going on with this article?

PHPのトレイトをいまさら使う

More than 3 years have passed since last update.

主務(会社)が変わり、環境がPHP5.6へと変わったのでトレイトを利用してみる。

トレイトとは

PHPマニュアルでは、トレイト(trait)を下記のように説明している。

トレイトは、PHP のような単一継承言語でコードを再利用するための仕組みのひとつです。 

まぁ、簡単に言えば、使い回すことができるクラスの部品のようなもの。

実際に使ってみると

<?php

trait Run
{
    public function run()
    {
        echo 'Brrrrr...' . PHP_EOL;
    }
}

class CarA
{
    use Run;
}

class CarB
{
    use Run;
}

$carA = new CarA();
$carA->run();

$carB = new CarB();
$carB->run();

"Brrrrr..."の出力部分をトレイトで共通化して、各クラスで読み込む。
この時点で既に無限の可能性を感じ始める。

<?php

trait Run
{
    public function run()
    {
        echo 'Brrrrr...' . PHP_EOL;
    }
}

trait Sound
{
    public function sound()
    {
        echo 'honk!' . PHP_EOL;
    }
}

class CarA
{
    use Run, Sound;
}

class CarB
{
    use Run;
}

$carA = new CarA();
$carA->run();
$carA->sound();

$carB = new CarB();
$carB->run();

複数のtraitを利用する場合。
多重継承っぽい。

ただ、複数のtraitを読み込んだ場合に、同名メソッドや変数はどうなるか?といった問題がある。
もちろん、この回避方法も用意されている。

<?php

trait Run
{
    public function run()
    {
        echo 'Brrrrr...' . PHP_EOL;
    }
}

trait RunFast
{
    public function run()
    {
        echo 'Wheeeee...' . PHP_EOL;
    }
}

class CarA
{
    use Run, RunFast {
        Run::run insteadof RunFast;
        // RunFast::run insteadof Run;
        RunFast::run as runFast;
    }
}

$carA = new CarA();
$carA->run();
$carA->runFast();

insteadofでどちらのメソッドを優先して利用するかが指定できる。
またasでエイリアスを張ることでもう一方のメソッドも利用できる。

こんな感じでマニュアルに書かれている通りでも十分に便利。
でも、おそらくデザインパターン中とかで利用したりすればもっと柔軟にいろいろ書けるような気がする。

<?php

/**
 * 文字列表示トレイト
 */
trait DisplayTrait
{
    /**
     * 文字列を表示する
     *
     * @return void
     */
    public function display()
    {
        echo $this->_msg . PHP_EOL;
    }
}

/**
 * 文字列加工トレイト
 */
trait ProcessTrait
{
    /**
     * 文字列を加工する
     *
     * @return void
     */
    public function process()
    {
        $this->_msg = sprintf('===== %s =====', $this->_msg);

        return $this;   // ※もちろんselfは使えないよ
    }
}

/**
 * インターフェース
 */
interface Sample
{
    /**
     * 文字列を表示する
     *
     * @return void
     */
    public function display();
}

/**
 * HogeSample
 */
class HogeSample implements Sample //extends SampleBase
{
    use ProcessTrait, DisplayTrait; # (擬似的)多重継承が可能に

    /**
     * 表示メッセージ
     *
     * @var
     */
    protected $_msg = 'Hoge';
}

/**
 * PiyoSample
 */
class PiyoSample implements Sample //extends SampleBase
{
    use DisplayTrait;

    /**
     * 表示メッセージ
     *
     * @var
     */
    protected $_msg = 'Piyo';
}

/**
 * ファクトリ
 */
class SampleFactory
{
    /**
     * オブジェクト生成
     *
     * @param string $type タイプ
     * @return SampleInterface
     * @throws InvaliParameterException タイプの指定が正しくない場合
     */
    public static function create($type)
    {
        switch ($type) {
            case 'hoge':
                return new HogeSample();
            case 'piyo':
                return new PiyoSample();
            default:
                throw new InvalidParameterException();
        }
    }
}

// 実行結果: ===== Hoge =====
SampleFactory::create('hoge')->process()->display();

これまで抽象クラスを膨らませていたこと(抽象クラスの数を増やすこと)で耐えていたファクトリパターンもすっきり。
trait中のメソッドでインターフェースの実装を行う。

トレイト便利だなー。

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
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  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
ユーザーは見つかりませんでした