PHP初心者がオブジェクト指向で学んだこと

## オブジェクト指向って何なん？
「オブジェクト指向プログラミング(Object Oriented Programming)」という単語は、アラン・ケイが創りだしたもの。
→ あらんけい？誰？

![スクリーンショット 2016-07-03 16.13.37.png](https://qiita-image-store.s3.amazonaws.com/0/109866/cc9d87c4-fc1e-dd5f-1375-8b421c7081df.png)


### 安蘭けい

![スクリーンショット 2016-07-03 16.06.37.png](https://qiita-image-store.s3.amazonaws.com/0/109866/4422072a-bf9d-5975-a114-935850d42502.png)

*日本の女優。元宝塚歌劇団星組トップスター。血液型AB型、公称身長167cm。愛称は「とうこ」。滋賀県甲賀郡（現・湖南市）出身。所属事務所はホリプロ、所属レコード会社はポニーキャニオン。*
→ つまり、**美魔女**。オブジェクト指向とは関係ない。
参考 : https://ja.wikipedia.org/wiki/%E5%AE%89%E8%98%AD%E3%81%91%E3%81%84


### アラン・ケイ

![スクリーンショット 2016-07-03 16.21.38.png](https://qiita-image-store.s3.amazonaws.com/0/109866/19f6146f-c451-d45b-5484-3efb59842827.png)

*アメリカ合衆国の計算機科学者、教育者、ジャズ演奏家。パーソナルコンピュータの父、と言われることもある。主に、オブジェクト指向プログラミングとユーザインタフェース設計に関する初期の功績で知られている。*
→　つまり、**電卓の人**。
参考 : https://ja.wikipedia.org/wiki/%E3%82%A2%E3%83%A9%E3%83%B3%E3%83%BB%E3%82%B1%E3%82%A4

## クラスとオブジェクト
人間（にんげん、英:human being）を例にとっていきます。

* [comment] 人間とは何か定義する　と深く考えると哲学的な話になってしまうで、割愛します。

**人間を設計することについて、詳しくはこちらを！**

![スクリーンショット 2016-07-03 16.36.34.png](https://qiita-image-store.s3.amazonaws.com/0/109866/4eba3c7a-5d5f-bdc4-35a1-f08734448cea.png)


### クラス
人間の設計図（遺伝子情報）をクラスとして定義していきます。
設計図を元に人間を生み出すには、new 演算子を使います。

```php

class Human {
}
$hmA = new Human;
$hmB = new Human;
```

製造された物体のことを**オブジェクト**や**インスタンス**と呼ぶ。

#### オブジェクトとインスタンスって何なん？
*PHPのオブジェクト指向プログラミングでは、まず最初に「クラス」というものを作ります。これは指示書・設計図になります。そしてその設計図（クラス）から「インスタンス（オブジェクト）」を作ります。インスタンスとオブジェクトは、ほぼ同じ意味で、「実体」ということです。*
→ モヤモヤ。PHPプログラミングにおいて区別する必要はないってことでいいんですかね？  
参考 : http://ponk.jp/php/basic/object

### プロパティ
*プロパティとは、オブジェクト指向プログラミングで使用されるオブジェクトが保持している、そのオブジェクトの性質を表すデータ。例えば、画像データのオブジェクトならば、高さや幅などのデータをプロパティとして持っている。*
http://e-words.jp/w/%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3.html

人間なのにhmAとhmBには違いがないので、名前を定義するためのプロパティを用意します。  
$name の前に **public** をつけることで、クラスの外からでもアクセスすることができます。  
**private** をつけるとクラス外部からのアクセスを遮断することができます。

```php

class Human {
	public $name;
}
$hmA = new Human;
$hmA->name = '山田';
$hmB = new Human;
$hmB->name = '柳田';

echo $hmA->name; // 山田
echo $hmB->name; // 柳田
```

## メソッド
クラスに所属する関数のようなもの。
Human クラスに人間の機能を定義します。

```php

class Human {
	public $name;
	public function phisycal() {
		return '体力';
	}
	public function eat() {
		return '食べる';
	}
	public function sleep() {
		return '寝る';
	}
}
```

山田と柳田は walk(), eat(), sleep() などの人間が基本的に持っている機能を持つことになります。

**Getter, Setter の説明は今回省略します。**

### コンストラクタ
__construct でメソッドを定義すると、インスタンス生成時に自動的にコールされる。
今回は名前をセットするようにします。

```php

class Human {
	private $name = '';
	public function __construct($name) {
		$this->setName($name);
	}
	// 名前をセットする
	public function setName($name) {
		if(is_string($name)) {
			$this->name = $name;
		} else {
			echo '選手名鑑に載っていません';
		}
	}
	// 名前を取得する
	public function getName() {
		return $this->name;
	}
}

$hmA = new Human('山田');
$hmB = new Human('柳田');

echo $hmA->getName(); // 山田
echo $hmB->getName(); // 柳田
```

## 継承
### extends
他のクラスから機能を引き継ぐ

```php

class Human {
	public function phisycal() {
		return '体力';
	}
	public function eat() {
		return '食べる';
	}
	public function sleep() {
		return '寝る';
	}
}

class proBaseballPlayer extends Human {
	// オーバーライド
	public function phisycal() {
		return 'ありあまる体力';
	}
	public function eat() {
		return 'いっぱい食べる';
	}
}
```
プロ野球選手は体力や食べる量は一般の人より多いが、寝るのは一般の人と変わらない。

### abstract
基本的な機能を提供し、継承したあとに実装する。
複数の派生先クラスで、一部の実装が異なる場合に利用。

```php

abstract class proBaseballPlayer {
	abstract public function position();
	abstract public function pitch();
	abstract public function meet();
}

class Giita extends proBaseballPlayer {
	public function position() {
		return 'Outfielder';
	}
	public function meet() {
		return 'A';
	}
}

class kdkr extends proBaseballPlayer {
	public function position() {
		return 'Outfielder';
	}
	public function meet() {
		return 'D';
	}
}

class Ohtani extends proBaseballPlayer {
	public function position() {
		return 'pitcher & Outfielder';
	}
	public function pitch() {
		return 'A';
	}
	public function meet() {
		return 'B';
	}
}
```
参考資料 : 実況パワフルプロ野球2016  
http://www.baseless.org/data/source/2016/work.html

### インターフェイス
不特定のクラスを共通の方法で、取り扱えるようにしたい場合。
interfaceをimplementsしたクラスは機能が一律になってて信頼できる。

```php

interface Baseball {
	// インターフェイスでは、実装を伴うメソッドやプロパティの宣言はできない
	public function run();
	public function batting();
	public function fielding();
}

class juniorHighBaseballPlayer implements Baseball {
	public function run() {
		return 'D';
	}
	public function batting() {
		return 'D';
	}
	public function fielding() {
		return 'D';
	}
}

class proBaseballPlayer implements Baseball {
	public function run() {
		return 'A';
	}
	public function batting() {
		return 'S';
	}
	public function fielding() {
		return 'S';
	}
}
```
野球では最低限、走る・打つ・守るを行うため。

## 名前空間
http://www.objective-php.net/basic/namespace
### 名前空間とは
クラスをディレクトリ構造のように階層的に分類することが出来る仕組み。異なる名前空間同士では同じ名前のクラスを定義できるようになる。

### 名前空間の定義
定義方法はいくつかあるが、最も一般的なのはクラス定義ファイルの頭に namespace キーワードで定義する方法。

```php

<?php
namespace Hawks;
class startingMember {

}
?>
```

```php

<?php
namespace Carp;
class startingMember {

}
?>
```

#### 利用方法は2種類ある
1.フルパスでクラス名指定

```php

$stamen = new \Hawks\startingMember();

```

2.先に利用宣言をする

```php

// use キーワードを利用する
use \Hawks\startingMember;

$stamen = new startingMember();

```

#### 別名の割当

```php

use \Hawks\startingMember;
use \Carp\startingMember;

$stamen = new startingMember();
```
この場合だと、どちらの startingMember() なのかわからなくなってしまい Fatal error が出てしまうので、別名を割り当てる必要がある。

```php

use \Hawks\startingMember as HawksStamen;
use \Carp\startingMember as CarpStamen;

$stamen = new HawksStamen();
```

#### 深い階層の名前空間
（例）baseballTeamという名前空間の下にある、PacificLeagueという名前の下に、更にHawksという名前空間があり、その中に、startingMemberクラスを定義する。

```php

namespace baseballTeam\PacificLeague\Hawks;
class startingMember {
}
```

これを利用するには、

```php

use baseballTeam\PacificLeague\Hawks\startingMember;
$stamen = new startingMember();
```

とする。

**では、クラスが増えた場合にはどうするか？**

```php

use baseballTeam\PacificLeague\Hawks\startingMember;
use baseballTeam\PacificLeague\Hawks\benchMember;
use baseballTeam\PacificLeague\Hawks\farmTeam;
use baseballTeam\PacificLeague\Hawks\coach;

$stamen = new startingMember();
$bench = new benchMember();
$farm = new farmTeam();
$coach = new coach();
```

このままではクラスが増える度にuseとnewをセットすることになるので、途中階層までの名前空間をuseするとコードがスッキリする。

```php

use baseballTeam\PacificLeague\Hawks;

$stamen = new Hawks\startingMember();
$bench = new Hawks\benchMember();
$farm = new Hawks\farmTeam();
$coach = new Hawks\coach();
```

## 静的プロパティ / 静的メソッド

* static キーワードを指定することで静的なプロパティ/メソッドが定義できます。
* 静的なプロパティ/メソッドはオブジェクトを生成せずに呼び出します。
* 静的なプロパティ/メソッドにはそれぞれ「クラス名::プロパティ名」「クラス名::メソッド名」の形式でアクセスします。

```php

<?php
class HogeClass {
　static $hoge = "静的データ";
　static function hogeMethod() {
　　return "静的メソッド";
　}
}

print HogeClass::$hoge . "\n";
print HogeClass::hogeMethod() . "\n";
```


## 例外処理
正規の処理フローからは外れ、そのまま処理続行が出来ないような状況
### 書き方
```php
<?php

try {
    throw new Exception('エラーが発生しました');
} catch (Exception $e) {

}

?>
```
* tryブロックでエラーが発生した場合、catchブロックに処理が飛ぶ。
* tryブロックでエラーが発生しなかったら、catchブロックは無視されて以降の処理に進む
* 明示的にthrowしないと、例外処理は実行されない

### 例外処理の活用

```php
<?php

class Deffence {
    public static function kensei($runner = 0) {
        if($runner <= 3 && $runner >= 0) {
            // try~catch構文
            try {
                if ($runner == 0) {
                    throw new Exception('牽制しようとしました！' . '<br>');
                }
                echo '牽制しました！！';
            } catch (Exception $e) {
                echo $e->getMessage();
                echo '牽制できませんでした...';
            }
            
        } else {
            echo 'ランナーを把握できませんでした。';
        }
    }
}

Deffence::kensei();
```

参考サイト :  
http://www.objective-php.net/basic/exception

## trait
### traitとは
PHP5.4から追加されたもので、モジュールをクラスとは別にまとめて管理することができます。
変数や関数をtraitに作成し、他のクラスで使い回して利用するという感じです。
PHPの単一継承を和らげるという効果があります。
traitの仕組み自体はクラスと似ていますが、インスタンスにできないという点が大きく異なります。

参考サイト :  
http://wp.tech-style.info/archives/309

### 使い方
* class の代わりに trait を利用する。
* traitを使用するときはクラス内でuse宣言を行う。

```php

trait Output {
  public $str = 'hello ';

  public function echoTrait() {
    echo 'trait!';
  }
}

class Test {
  //使うtraitを宣言する
  use Output;
}

//Testインスタンスを作成し、Testクラスからtraitを利用する。
$test = new Test();
//変数の呼び出し
echo $test->str;  //hello
//関数の呼び出し
$test->echoTrait();  //trait!
```

### trait in trait もイケる

```php

//TripleThreeトレイト
trait TripleThree {
	public function echo333() {
    echo 'トリプルスリー!';
  }
}

//TripleCrownトレイト
trait TripleCrown {
  public function echoTripleCrown() {
    echo '3冠王！';
  }
}

//TripleThreeとTripleCrownを組み合わせたトレイト
trait FifthCrown {
	use TripleThree, TripleCrown;
}

class Yamada {
  //使うtraitを宣言する
  use FifthCrown;
}

$yamada = new Yamada();
$yamada->echo333();  //トリプルスリー!
$yamada->echoTripleCrown(); //3冠王！
```

### 複数のトレイトを使用した際に関数名が被るとエラーになってしまう...

#### 2刀流trait
片方の関数を選択する方法

```php

//Picherトレイト
trait Picher {
  function setPosition() {
    return '投手!';
  }
}
//Inputトレイト
trait Fielder {
  function setPosition() {
    return '野手!';
  }
}
//名前の衝突が起こってしまったクラス
class Ohtani {
  use Picher, Fielder {
    //Fielder の setPosition じゃなくて Picher の setPosition 使います宣言
    Picher::setPosition insteadof Fielder;
  }
}

$ohtani = new Ohtani();	 // ホテルの名前みたい
echo $ohtani->setPosition(); // 投手!
```

#### 超2刀流trait
両方の関数を共存させる方法

```php

//Picherトレイト
trait Picher {
  function setPosition() {
    return '投手!';
  }
}
//Fielderトレイト
trait Fielder {
  function setPosition() {
    return '野手!';
  }
}
//野手と投手のポジションが被ってしまったパターン
class Ohtani {
  use Picher, Fielder {
    //PicherのsetPositionじゃなくてFielderのsetPositionを使います宣言
    Fielder::setPosition insteadof Picher;
    //Picher の setPosition は mountPosition という名前になります宣言
    Picher::setPosition as mountPosition;
  }
}

$ohtani = new Ohtani(); // ホテルの名前みたい
echo $ohtani->setPosition();  //野手!
echo $ohtani->mountPosition();  //投手!
```