特集・コラム

メニュー

PHPer上級者になるために知っておきたいこと

vol.70 ‐ 『トレイトについて その1』

投稿日時:2015/06/03 11:06

カテゴリ: PHPer上級者になるために知っておきたいこと

試験のPHP対象バージョンが「5.3」の中、5.4系で盛り込まれた仕様のお話で恐縮ではありますが。
今回から数回にわたって、トレイト(trait)についてお話をさせていただければ、と思います。

 
traitとは、特徴や特色、特性の事を言いまして、文脈によっては「習性」「体質」「素質」
なんて訳されかたをされたりもします…なんていうボケはおいておきまして。
物凄く大雑把には、「多重継承」と呼ばれる系譜の、テクニックであったり技術であったり
技法であったり実装であったりするもの、のうちのひとつです。
 

今回の一連のコラムでは、まずはストレートな実例を。
 

そこからもうちょっと「概念的な」部分、そこから一瞬横道にそれて「どんな事が出来るのか」の
バリエーションを見つつ、「多重継承」についても、少し書いていきたいと思います(行動宣言)。
 

割と単純かつ使い勝手の良いところで「アクセサ」及び
「プロパティのtypoブロック」あたりがよいかと思いますので、実装をみつつ、
traitについて簡単に理解をしていきたいと思います。

コラム62でやりました「__callによるアクセサ」を、ふと思い出してみましょう。
 


  public function __construct() {
    

$this->data_ = array();
    $this->propertys_ = array (
        'foo' => 1,
        'bar' => 1,
    );
  }
  public function __call($name, 

$param) {
    //
    //
    if ( (0 === strncmp($name, 'get_', 4))||(0 === strncmp($name, 'set_', 4)) ) {
      list($type, $k) = 

explode('_', $name, 2);
      if (false === isset($this->propertys_[$k])) {
        // XXX 適宜エラー処理
        throw new Exception('

えらー');
      }
      // else
      if ('set' === $type) {
        $this->data_[$k] = $param[0];
      } else {
        return $this->data_

[$k];
      }
    } else {
      // XXX 適宜エラー処理
      throw new Exception('えらー');
    }
  }
//private:
private $propertys_;
private 

$data_;

 

こんなんですね。
ちなみにpropertys_で「keyに変数名的なものを持っている」のは、単純に検索コストを考えての事です。
検索コスト周りについては、こーゆー感じのコードを書いてみると、何となく見えてくるかと思いますので参考まで。

えらいこと雑ですが(苦笑


$awk = array();
$s = 'a';
for($i = 0; $i < 1000; $i ++) {
  $awk[] = $s ++; // 後置のインクリメン

ト。お仕事では使わないこと!
}
$awk2 = array_flip($awk);
// 値の線形検索
$t = microtime(true);
for($i = 0; $i < 100; $i ++) {
  

in_array("sf", $awk); // 1000個作ると真ん中が大体sfあたりなので
}
var_dump( microtime(true) - $t );
echo "\n";
// hash keyの

hash検索
$t = microtime(true);
for($i = 0; $i < 100; $i ++) {
  $awk["sf"]; // 1000個作ると真ん中が大体sfあたりなので。hash検索

だから位置関係ないけど
}
var_dump( microtime(true) - $t );
echo "\n";

 

あるいはもうちょっと本質的には
「連想配列をハッシュ配列とも呼称するhashってのはそもそもhash検索から来ている」あたりを基点に
「ハッシュとは、ハッシュ関数とは、ハッシュ値とは、ハッシュ検索とは、なんぞや?」
という辺りを一度、きちんと学んでみるのもよいかもしれません。
 

いずれにしても、「valueの値を検索する」よりも「key/indexの値を検索する」ほうが、
実装的に”圧倒的にコストが安い”ってのは、把握/理解をしておくと便利です。
 

閑話休題
 

本題に戻しましょう。
さて、とあるクラス hoge を作成します。
(注:プロパティについて。行数を少し短くしたかったので直接初期化してますが、業務であれば、
コンストラクタなどで初期化した方がより丁寧かとは思います)
 


class hoge {
  

public function __call($name, $param) {
    //
    if ( (0 === strncmp($name, 'get_', 4))||(0 === strncmp($name, 'set_', 4)) ) {
 

     list($type, $k) = explode('_', $name, 2);
      if (false === isset($this->propertys_[$k])) {
        // XXX 適宜エラー処理
        

throw new Exception('えらー');
      }
      // else
      if ('set' === $type) {
        $this->data_[$k] = $param[0];
      } else {
        

return $this->data_[$k];
      }
    } else {
      // XXX 適宜エラー処理
      throw new Exception('えらー');
    }
  }
  private $data_ = 

array();
  private $propertys_ = array (
      'hoge_1' => 1,
      'hoge_2' => 1,
  );
}

別のクラスfooを作成します。


class foo {
  public function __call($name, $param) {
    //
    if ( (0 === strncmp($name, 'get_', 4))||(0 === 

strncmp($name, 'set_', 4)) ) {
      list($type, $k) = explode('_', $name, 2);
      if (false === isset($this->propertys_[$k])) {
       

 // XXX 適宜エラー処理
        throw new Exception('えらー');
      }
      // else
      if ('set' === $type) {
        $this->data_[$k] = 

$param[0];
      } else {
        return $this->data_[$k];
      }
    } else {
      // XXX 適宜エラー処理
      throw new Exception('え

らー');
    }
  }
  private $data_ = array();
  private $propertys_ = array (
      'foo_1' => 1,
      'foo_2' => 1,
  );
}

 

勿論これくらいでしたら、__callあたりを親クラスに切り出して継承させてもよいのですが。
traitでも書けます、ってことで、実際に書いてみましょう。


trait accessor {
  public function __call($name, $param) {
    //
    if ( (0 === strncmp($name, 'get_', 

4))||(0 === strncmp($name, 'set_', 4)) ) {
      list($type, $k) = explode('_', $name, 2);
      if (false === isset($this-

>propertys_[$k])) {
        // XXX 適宜エラー処理
        throw new Exception('えらー');
      }
      // else
      if ('set' === $type) {
       

 $this->data_[$k] = $param[0];
      } else {
        return $this->data_[$k];
      }
    } else {
      // XXX 適宜エラー処理
      throw 

new Exception('えらー');
    }
  }
  private $data_ = array();
}
//
class foo {
  // 
  use accessor;

  //
  private $propertys_ = array (
      

'foo_1' => 1,
      'foo_2' => 1,
  );
}

 

さて。一番基本的な書式をみていただいたところで。
次回、もう少し深い所に、ずずずいっと踏み込んでいってみましょう。

お仕事のご紹介には、まずヒューマンリソシアへの登録が必要です。
ヒューマンリソシア人材派遣サイトの便利な機能 ・お気に入りの派遣求人のブックマーク ・登録会への予約 ・有給休暇の管理 ・WEB給与明細の確認 ・お気に入りの情報をメール受信
登録会の入力手続きをあらかじめおこなえます。

ヒューマンリソシア派遣サービスに 登録する 無料

ページトップへ戻る
ヒューマンリソシア派遣サービスに 登録する 無料
ページトップへ戻る