1. BRSF

    No comment

    BRSF
Changes in body
Source | HTML | Preview
@@ -1,256 +1,256 @@
-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 = "キャベツ";
}
}
}
```
### メンバのエイリアス指定
ここで気をつけないといけないのは、トレイト名ならびにメンバ名が同一であるため、このままブラウザで表示しようとすると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>";
}
```