あっさりと

ソフトウェアや技術話など諸々

PHPのtraitを使ってラク出来た件

はじめに

traitを使って既存の動作にほぼ影響を与えず機能追加出来たパターンが有った。
使い方例をメモ。

元々有ったコード

ClassBase.php

class ClassBase
{
    private $value;
    
    static function getBody(){
        return "";
    }
    
    static function getObjcet()
    {
        $className = __CLASS__;
        return new $className(static::makeArg());
    }
    
    static function makeArg()
    {
        // バイト長を返却
        return strlen(static::getBody());
    }
    
    function __construct($value)
    {
        $this->value = $value;
    }
    
    function echoValue(){
        echo $this->value, PHP_EOL;
    }
}

ClassA.php

class ClassA extends ClassBase 
{
    static function getBody()
    {
        return "body";
    }

 〜
 色々なメソッド
}
$obj_classA = ClassA::getObjcet();
$obj_classA->echoValue(); // 4



要件(前提条件)

・バイト長では無く特定要素でjsonエンコードした情報を出力する処理を追加する。
・既存のバイト長を出力する処理も残す
・既存の動作にほぼ影響を与えないようにする(既存変更影響のテスト工数はあまり取れない)
・メソッド名(echoValue)は同じで動作させる。


今回は使えなかった解決方法

・ClassBaseを変更
 → 多くのクラスで継承されているので影響範囲が大きく手を入れにくい状態
・ClassBaseを継承する新たなクラスを作成
 → ClassA内のメソッドも使用する場合があるので同じコードをコピペで入れたくない


traitを使って解決

TraitCommon.php

trait TraitCommon
{
    static function makeArg()
    {
        $json = [];
        $json["hoge"] = static::getBody();
        // jsonに変更
        return json_encode($json);
    }
}

ClassTraitA.php

class ClassTraitA extends ClassA 
{
    use TraitCommon;
}

既存処理に影響を与えず追加処理を用意出来た。

$obj_classA = ClassA::getObjcet();
$obj_classA->echoValue(); // 4

$obj_traitA = ClassTraitA::getObjcet();
$obj_traitA->echoValue(); // {"hoge":"body"}


ClassBaseを継承したClassBやClassCが有っても同じように共通処理として簡単に展開していける。