2011年9月11日日曜日

PHPでオブジェクトから別のオブジェクトへプロパティをコピーする

こんにちは、matsuiです。

今回は弊社でソーシャルアプリを開発していく中で作成された共通処理の一部を紹介していきたいと思います。

ご紹介する内容は、指定されたオブジェクト間で同じ名前で定義されているプロパティの中身をコピーするというものです。

弊社内で使われているフレームワークでは、処理のレイヤーごとにデータを受け渡すためのオブジェクトを使ってやり取りしています。
そのような構造をとっているため処理のレイヤーを越える際に、オブジェクト間のデータの詰め替え作業が発生し、開発効率の低下を招く可能性がありました。
開発効率をできる限り下げないようにするために、下記のような「自動的に詰め替え作業を行う共通処理」を作成し、詰め替え作業のコストの削減を図っています。

----------------------------------------------------------------------
 /**
 * 指定されたオブジェクトに定義されているプロパティを詰め替える.
 *
 * 引数に指定された両方オブジェクトを比較し、同一のプロパティが存在した場合に第一引数のオブジェクトから第二引数のオブジェクトに値をコピーする。
 *
 * @param unknown_type $sourceDto
 * @param unknown_type $targetDto
 */
public static function copyProperties($sourceDto, $targetDto)
{
    if ($sourceDto === null || $targetDto === null) {
        return null;
    }
  
    $targetPropertyList = get_class_vars(get_class($targetDto));
  
    foreach ($targetPropertyList as $key => $value) {
        if (property_exists($sourceDto, $key)) {
            $targetDto->$key = $sourceDto->$key;
        }
    }
  
    return $targetDto;
  
}
----------------------------------------------------------------------

なお、お気づきの方もいらっしゃるかもしれませんが、
ご紹介した処理では、正確には「値のコピー」になっていない場合があります。

それはプロパティの中身が参照型と呼ばれる形式になっている場合です。
詳しい説明は割愛しますが、オブジェクト型などに代表される参照型の場合、参照先のオブジェクト自体が複製されるわけではなく、参照先オブジェクトへの参照がコピーされることになります。

さらにオブジェクトがネストされていた場合などは、「シャロー(shallow)コピー」と「ディープ(deep)コピー」の話も絡んできます。

記述された処理が思うような動きをしなかった場合は、参照型・シャローコピー・ディープコピーといった概念について確認していただいた方が良いかもしれません。

追記
PHP(Zend Engine)ではzvalという概念を持ち変数を管理しています。
そのため、変数の代入すら本来の値のコピーではないようです…それは今現在のZend Engineの実装の話なのでここでは取り上げませんが、興味のある方は調べてみるのも面白いと思います。

0 件のコメント:

コメントを投稿