PHP Manual 読書会(13回目)(クラスとオブジェクト5)

PHPに慣れる為に週1ぐらいで更新していきます。PHP Manualを読んで実験して行きます。

前回:[PHP Manual 読書会(12回目)(クラスとオブジェクト4)](http://qiita.com/amesho/items/f4142bb33116042c5bd1)

## [オブジェクト インターフェイス](http://php.net/manual/ja/language.oop5.interfaces.php)

> インターフェイスを実装するには、implements 演算子を使用し、 このインターフェイスに含まれる全てのメソッドを実装する必要があります。 実装されていない場合、致命的エラーとなります。 各インターフェイスをカンマで区切って指定することで、 クラスは複数のインターフェイスを実装することができます。

### インターフェースの実装

+ 複数のインターフェースが実装できる
+ implementsで宣言されたmethodが実装されている必要がある

```php
<?php

interface myInterface {
    public function method1();
    public function method2();
}

interface myInterface2 {
    public function method3();
    public function method4();
}

class MyClass implements myInterface, myInterface2 {
}
```

結果

```
PHP Fatal error:  Class MyClass contains 4 abstract methods and must therefore be declared abstract or implement the remaining methods (myInterface::method1, myInterface::method2, myInterface2::method3, ...)
```

### インターフェースの継承

インターフェースは継承できる

```php
<?php

interface myInterface {
    public function method1();
    public function method2();
}

interface myInterface2 extends myInterface {
    public function method3();
    public function method4();
}

class MyClass implements myInterface2 {
    public function method1() {}
    public function method2() {}
    public function method3() {}
    public function method4() {}
}
```

## [トレイト](http://php.net/manual/ja/language.oop5.traits.php)


> トレイトは、PHP のような単一継承言語でコードを再利用するための仕組みのひとつです。 トレイトは、単一継承の制約を減らすために作られたもので、 いくつかのメソッド群を異なるクラス階層にある独立したクラスで再利用できるようにします。 トレイトとクラスを組み合わせた構文は複雑さを軽減させてくれ、 多重継承や Mixin に関連するありがちな問題を回避することもできます。

> トレイトはクラスと似ていますが、トレイトは単にいくつかの機能をまとめるためだけのものです。 トレイト自身のインスタンスを作成することはできません。 昔ながらの継承に機能を加えて、振る舞いを水平方向で構成できるようになります。 つまり、継承しなくてもクラスのメンバーに追加できるようになります。

+ 再利用可能なメソッド群を保持しておける
+ 複数のトレイトをひとつのクラスに追加するには、use 文でカンマ区切りで指定


```php
<?php

trait myTrait {
    function method1() {}
    function method2() {}
}

trait myTrait2 {
    function method3() {}
    function method4() {}
}

class myClass {
    use myTrait,myTrait2;
}

$obj = new myClass();

$obj->method1();
```

### 衝突の解決

> 同じ名前のメンバーを含む複数のトレイトを追加するときには、 衝突を明示的に解決しておかないと fatal エラーが発生します。
> 同一クラス内での複数のトレイト間の名前の衝突を解決するには、 insteadof 演算子を使って そのうちのひとつを選ばなければなりません。
> この方法はひとつのメソッドだけしか使えませんが、 as 演算子を使うと、 メソッドのいずれかにエイリアスを追加できます。 as 演算子はメソッドをリネームするわけではないので、 その他のメソッドにも何も影響を及ぼさないことに注意しましょう。

```php
<?php

trait myTrait {
    function method1() {
        echo "myTrait\n";
    }
    function method2() {
        echo "myTrait\n";
    }
}

trait myTrait2 {
    function method1() {
        echo "myTrait2\n";
    }
    function method2() {
        echo "myTrait2\n";
    }
}

class myClass {
    use myTrait,myTrait2 {
        myTrait2::method1 insteadof myTrait;
        myTrait::method2 insteadof myTrait2;
        myTrait2::method2 as method3;
    }
}

$obj = new myClass();

$obj->method1();
$obj->method2();
$obj->method3();
```

結果

```
myTrait2
myTrait
myTrait2
```

### メソッドの可視性の変更

> as 構文を使うと、 クラス内でのメソッドの可視性も変更することができます。

```php
<?php

trait myTrait {
    public function method1() {
        echo "myTrait\n";
    }
}

class myClass {
    use myTrait {
        method1 as protected;
    }
}

$obj = new myClass();

$obj->method1();
```

```
PHP Fatal error:  Uncaught Error: Call to protected method myClass::method1() from context ''
```

### トレイトを組み合わせたトレイト

> クラスからトレイトを使えるのと同様に、トレイトからもトレイトを使えます。 トレイトの定義の中でトレイトを使うと、 定義したトレイトのメンバーの全体あるいは一部を組み合わせることができます。


```php
<?php

trait myTrait {
    public function method1() {
        echo "myTrait\n";
    }
}

trait myTrait2 {
    public function method2() {
        echo "myTrait2\n";
    }
}

trait myTrait3 {
    use myTrait, myTrait2;
}

class myClass {
    use myTrait3;
}

$obj = new myClass();

$obj->method1();
$obj->method2();
```

```
myTrait
myTrait2
```

### トレイトのメンバーの抽象化

abstractで抽象メソッドを指定できる。

```php
<?php

trait myTrait {
    function method1() {
        echo "myTrait\n";
    }
    abstract function method2();
}

class myClass {
    use myTrait;
}

$obj = new myClass();
```

実装しないと殺されます。

```
PHP Fatal error:  Class myClass contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (myClass::method2)
```

### プロパティ

```php
<?php

trait myTrait {
    public $hoge = "hoge";
}

class myClass {
    use myTrait;
}

$obj = new myClass();

echo $obj->hoge . "\n";
```

結果

```
hoge
```