1. BRSF

    No comment

    BRSF
Changes in body
Source | HTML | Preview
@@ -1,311 +1,311 @@
-PHP初心者、初級者だと初めて聞く存在だと思いますが、PHPには名前空間トレイトという仕組みがあります。
+PHP初心者、初級者だと初めて聞く存在だと思いますが、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 = "キャベツ";
}
}
}
```
### メンバのエイリアス指定
ここで気をつけないといけないのは、トレイト名ならびにメンバ名が同一であるため、このままブラウザで表示しようとするとトレイトの規約違反で**コリジョンエラー**(同じトレイト名やメンバー名にしていると、何を呼び出していいのかプログラムで判断できない)を起こしてしまいます。そこで、各メンバに対しエイリアスを指定する必要があります。
→ [[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::tochigi 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>";
```
ブラウザなどでレビューをかけると
```
【栃木】果物:いちご、野菜:かんぴょう
【群馬】果物:りんご、野菜:キャベツ
```
このように表示させることができます。
## 全体の構造
備忘録として作成した原本プログラムはこのようになっています。トレイトの中はkinkiも入っており、メンバの中身もトレイトごとに違いますが、動作は全く同じです。また、トレイトやメンバの中をどんどん増やしていくことができます。その際には必ず逐一エイリアスも指定して、コリジョンを起こさないようにしてください。
```PHP:PHP
<?php
namespace fruits
{
trait Kanto
{
public function tochigi(){
$this -> fruits = "いちご";
}
public function gunma(){
$this -> fruits = "りんご";
}
}
trait Kinki
{
public function wakayama(){
$this -> fruits = "うめ";
}
public function nara(){
$this -> fruits = "かき";
}
}
}
namespace vegitable
{
trait Kanto
{
public function tochigi(){
$this -> vegi = "かんぴょう";
}
public function gunma(){
$this -> vegi = "キャベツ";
}
}
trait Kinki
{
public function wakayama(){
$this -> vegi = "しょうが";
}
public function nara(){
$this -> vegi = "みょうが";
}
}
}
namespace
{
//エイリアスを指定する場合はクラスの外側で
use fruits\Kanto as f_kanto;
use vegitable\Kanto as v_kanto;
use fruits\Kinki as f_kinki;
use vegitable\Kinki as v_kinki;
class Crops
{
public $fruits;
public $vegi;
//トレイト内で重複するメンバがないようにすること
use f_kanto{
f_kanto::tochigi as f_tochigi;
f_kanto::gunma as f_gunma;
}
use v_kanto{
v_kanto::tochigi as v_tochigi;
v_kanto::gunma as v_gunma;
}
use f_kinki{
f_kinki::wakayama as f_wakayama;
f_kinki::nara as f_nara;
}
use v_kinki{
v_kinki::wakayama as v_wakayama;
v_kinki::nara as v_nara;
}
//必ずメンバをオーバーライドさせること
public function tochigi(){
$this -> f_tochigi();
$this -> v_tochigi();
}
public function gunma(){
$this -> f_gunma();
$this -> v_gunma();
}
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 -> tochigi();
list($fruits,$vegi) = $Crops -> getter();
echo "【栃木】果物:{$fruits}、野菜:{$vegi}<br>";
$Crops -> gunma();
list($fruits,$vegi) = $Crops -> getter();
echo "【群馬】果物:{$fruits}、野菜:{$vegi}<br>";
$Crops -> wakayama();
list($fruits,$vegi) = $Crops -> getter();
echo "【和歌山】果物:{$fruits}、野菜:{$vegi}<br>";
$Crops -> nara();
list($fruits,$vegi) = $Crops -> getter();
echo "【奈良】果物:{$fruits}、野菜:{$vegi}<br>";
}
```
```
【栃木】果物:いちご、野菜:かんぴょう
【群馬】果物:りんご、野菜:キャベツ
【和歌山】果物:うめ、野菜:しょうが
【奈良】果物:かき、野菜:みょうが
```