1. BRSF

    Posted

    BRSF
Changes in title
+【PHP】名前空間とトレイトを同時に使用する場合
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,256 @@
+PHP初心者、初級者だと初めて聞く存在だと思いますが、名前空間とトレイトというものがあります。
+
+- [名前空間](https://qiita.com/7968/items/1e5c61128fa495358c1f)
+- [トレイト](https://qiita.com/kazuhsat5/items/6ced7492daaddf1cd3d9)
+
+では、今更ではあるのですが、この**名前空間とトレイトを同時に使う**場合(実務的な機会があるのかどうかはわかりませんが…)はどうすればいいのかを調査してました。すると、色々と注意する部分があるようなので、備忘録としてプログラムと解説を置いておきます。
+
+なお、本記事はオブジェクト指向を熟知しているPHP中級者以上を前提としています。また、名前空間とトレイトも知らない人は、参考記事を熟読しておいてください。
+
+##実例
+【要件定義】各都道府県の果物と野菜をそれぞれ調べたい。名前空間にはそれぞれfruits、vegitableと定義され、その中に各地方の名称となったトレイト(kanto、kinkiなど)があり、その中に各都道府県のメンバ(kantoならgunma()、tochigi()など)が用意されている。
+
+つまり、このような状態です
+
+```PHP:PHP
+ namespace fruits
+ {
+ trait Kanto
+ {
+ public function tochigi(){
+ $this -> fruits = "いちご";
+ }
+
+ public function gunma(){
+ $this -> fruits = "りんご";
+ }
+ }
+ }
+
+ namespace vegitable
+ {
+ trait Kanto
+ {
+ public function tochigi(){
+ $this -> vegi = "かんぴょう";
+ }
+
+ public function gunma(){
+ $this -> vegi = "キャベツ";
+ }
+ }
+ }
+```
+
+### メンバのエイリアス指定
+ここで気をつけないといけないのは、トレイト名ならびにメンバ名が同一であるため、このままブラウザで表示しようとするとtraitの規約違反でコリジョンエラーを起こしてしまいます。そこで、各メンバに対しエイリアスを指定する必要があります。
+
+→ [[PHP] こんなときどうする?trait編](https://qiita.com/sengoku/items/42ab8c850a2085b22d4e)
+
+これを参考にして、以下のようにメンバ名を別名に定義します。
+まずは、名前空間の外側を無名の名前空間で囲みます(名前空間の外側だとエラーになります)。
+そして別名のメンバを必ずトレイト内のメンバと**オーバーライド**させるようにします。
+
+→ [オーバーライドについて](http://www.objective-php.net/basic/override)
+
+```PHP:PHP
+ namespace
+ {
+ class Crops
+ {
+ //public $fruits;
+ //public $vegi;
+ //トレイト内で重複するメンバがないようにすること
+ use fruits\kanto, vegitable\kanto{
+ fruits\kanto::tochigi as f_tochigi;
+ vegitable\kanto::tochigi as v_tochigi;
+ fruits\kanto::gunma as f_gunma;
+ vegitable\kanto::gunma as v_gunma;
+ }
+ //必ずメンバをオーバーライドさせること
+ public function tochigi(){
+ $this -> f_tochigi();
+ $this -> v_tochigi();
+ }
+
+ public function gunma(){
+ $this -> f_gunma();
+ $this -> v_gunma();
+ }
+ }
+ }
+```
+
+### エイリアスの定義
+これだと、名前空間が煩雑なので、すっきりさせるためにエイリアスを定義します。
+
+```PHP:PHP
+ namespace
+ {
+ //名前空間のエイリアス定義はクラスの外側で行う
+ use fruits\kanto as f_kanto;
+ use vegitable\kanto as v_kanto;
+ class Crops
+ {
+ //public $fruits;
+ //public $vegi;
+ //トレイト内で重複するメンバがないようにすること
+ use f_kanto, v_kanto{
+ f_kanto::tochgi as f_tochigi;
+ v_kanto::gunma as v_tochigi;
+ f_kanto::tochigi as f_gunma;
+ v_kanto::gunma as v_gunma;
+ }
+ //必ずメンバをオーバーライドさせること
+ public function tochigi(){
+ $this -> f_tochigi();
+ $this -> v_tochigi();
+ }
+
+ public function gunma(){
+ $this -> f_gunma();
+ $this -> v_gunma();
+ }
+ }
+ }
+```
+
+### ゲッタの設定
+値を引き出せるようにゲッタをクラス内に設定します。
+
+```PHP:PHP
+ namespace
+ {
+ //名前空間のエイリアス定義はクラスの外側で行う
+ use fruits\kanto as f_kanto;
+ use vegitable\kanto as v_kanto;
+ class Crops
+ {
+ //public $fruits;
+ //public $vegi;
+ //トレイト内で重複するメンバがないようにすること
+ use f_kanto, v_kanto{
+ f_kanto::tochgi as f_tochigi;
+ v_kanto::gunma as v_tochigi;
+ f_kanto::tochigi as f_gunma;
+ v_kanto::gunma as v_gunma;
+ }
+ //必ずメンバをオーバーライドさせること
+ public function tochigi(){
+ $this -> f_tochigi();
+ $this -> v_tochigi();
+ }
+
+ public function gunma(){
+ $this -> f_gunma();
+ $this -> v_gunma();
+ }
+ //ゲッタの指定(共通でデータを抽出できる)
+ public function getter(){
+ $fruits = $this -> fruits;
+ $vegi = $this -> vegi;
+ return [$fruits,$vegi];
+ }
+
+ }
+ }
+```
+
+### インスタンスからメンバの値を取り出す
+あとはインスタンスを指定して、メンバにアクセスすればデータを取得できます。
+
+```PHP:PHP
+ $Crops = new Crops(); //インスタンス生成
+ $Crops -> tochigi();
+ list($fruits,$vegi) = $Crops -> getter();
+ echo "【栃木】果物:{$fruits}、野菜:{$vegi}<br>";
+ $Crops -> gunma();
+ list($fruits,$vegi) = $Crops -> getter();
+ echo "【群馬】果物:{$fruits}、野菜:{$vegi}<br>";
+```
+
+ブラウザなどでレビューをかけると
+
+```
+【栃木】果物:いちご、野菜:かんぴょう
+【群馬】果物:りんご、野菜:キャベツ
+```
+
+このように表示させることができます。
+
+## 全体の構造
+このようになっています。traitの中はkinkiになっており、メンバの中身も違いますが動作は同じです。また、traitやメンバの中をどんどん増やしていくことができます。その際には必ず逐一エイリアスも指定して、コリジョンを起こさないようにしてください。
+
+```PHP:PHP
+ namespace fruits
+ {
+ trait Kinki
+ {
+ public function wakayama(){
+ $this -> fruits = "うめ";
+ }
+
+ public function nara(){
+ $this -> fruits = "かき";
+ }
+ }
+ }
+
+ namespace vegitable
+ {
+ trait Kinki
+ {
+ public function wakayama(){
+ $this -> vegi = "しょうが";
+ }
+
+ public function nara(){
+ $this -> vegi = "みょうが";
+ }
+ }
+ }
+
+ namespace
+ {
+ //エイリアスを指定する場合はクラスの外側で
+ use fruits\Kinki as f_kinki;
+ use vegitable\Kinki as v_kinki;
+ class Crops
+ {
+ public $fruits;
+ public $vegi;
+ //トレイト内で重複するメンバがないようにすること
+ use f_kinki, v_kinki{
+ f_kinki::wakayama as f_wakayama;
+ v_kinki::wakayama as v_wakayama;
+ f_kinki::nara as f_nara;
+ v_kinki::nara as v_nara;
+ }
+ //必ずメンバをオーバーライドさせること
+ public function wakayama(){
+ $this -> f_wakayama();
+ $this -> v_wakayama();
+ }
+
+ public function nara(){
+ $this -> f_nara();
+ $this -> v_nara();
+ }
+
+ public function getter(){
+ $fruits = $this -> fruits;
+ $vegi = $this -> vegi;
+ return [$fruits,$vegi];
+ }
+ }
+
+ $Crops = new Crops();
+ $Crops -> wakayama();
+ list($fruits,$vegi) = $Crops -> getter();
+ echo "【和歌山】果物:{$fruits}、野菜:{$vegi}<br>";
+ $Crops -> nara();
+ list($fruits,$vegi) = $Crops -> getter();
+ echo "【奈良】果物:{$fruits}、野菜:{$vegi}<br>";
+ }
+
+```