PHPオブジェクト指向入門（前半）

# **コンセプト**

オブジェクト指向プログラミング未経験者～理解を深めたい人、ノンケ～ホモまで幅広くカバーするつもり。多分。

# **クラスとオブジェクト（初級）**

唐突ですが、量産型のロボットの設計・製造について考えてみましょう。

|ロボ太郎|ロボ次郎|
|:----:|:---:|
|![ロボ太郎](https://qiita-image-store.s3.amazonaws.com/0/25060/5cac1d87-4cb7-adc2-3252-f279aad07c4a.png)|![ロボ次郎](https://qiita-image-store.s3.amazonaws.com/0/25060/5cac1d87-4cb7-adc2-3252-f279aad07c4a.png)|

<del>イラストで初心者を釣る</del>

## **クラス**

まず、ロボットの設計図を **クラス** として定義します。設計図をもとにロボットを製造するには、 **new** 演算子を使います。製造された物体のことを **オブジェクト** や **インスタンス** と呼びます。ここではこれらの用語を区別せずに用いることにします。

**[Yahoo!知恵袋 - オブジェクトとインスタンスの違い](http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1210773382)**

```php:Robotクラス
class Robot { }
```

```php:実行コード
$a = new Robot;
$b = new Robot;
```

ここまでは直感的に理解できますね。

## **プロパティ**

最初の画像では

- ロボ太郎
- ロボ次郎

と勝手に呼び分けていましたが、実際は

- 変数 `$a` に代入されたロボット
- 変数 `$b` に代入されたロボット

の違いしかありませんでした。名前のないロボットも可哀そうなので、名前を記録するための **プロパティ** を確保してやりましょう。

```php:Robotクラス
class Robot {
    public $name;
}
```

```php:実行コード
$a = new Robot;
$a->name = 'ロボ太郎';
$b = new Robot;
$b->name = 'ロボ次郎';

echo $a->name; // ロボ太郎;
echo $b->name; // ロボ次郎;
```

さて、何やらごちゃごちゃしてきました。焦らずちょっとずつ見ていきましょう。

### **`public` って何？**

アクセス権を表現するためのキーワードです。 **`public`** はどこからでもアクセス可能なことを意味します。<ins>プロパティの定義には、アクセス権の明示が必要です。</ins>

### **`->` って何？**

**アロー演算子** と呼ばれます。インスタンスのプロパティを参照する演算子です。

### **何で `$a->name` なの？ `$a->$name` じゃないの？**

…PHPという言語ではそう決められているからです、としか言えませんね。

ちなみに `$a->$name` は、プロパティの<ins>名前</ins>に対して `$name` に代入されている値を指定するという意味です。以下の2つは等価です。

```php
echo $a->name;
```

```php
$property = 'name';
echo $a->$property;
```

### **代入する前にはどうなってるの？**

`NULL` が設定されています。インスタンス生成時に設定される値を `NULL` 以外にしたければ、初期値の設定が必要です。

```php:初期値を空文字列に設定する
class Robot {
    public $name = '';
}
```

以降はこの記述を使用します。

## **カプセル化**

製品というものは、やっぱり外装がしっかりしている方が安心ですよね。パソコンでマザーボードをさらけ出したまま使っている人はほとんどいないでしょう。外部からの衝撃で簡単に壊れてしまいそうですしね。メーカーにもそういう使い方をした場合は「サポート対象外」であると告げられることだろうと思います。

プログラミングにおいて、外部からのアクセスを禁止し、内部に隠蔽してしまうことを **カプセル化** といいます。（厳密な定義とは少し異なりますが、この段階ではそういう説明にしておきます）

このロボットの例で例えましょう。PHPの変数はデータの型を気にせずどんなものでも好き勝手代入することが出来ますが、もし `$name` に **配列** が代入されちゃったら何か嫌な感じですね。それをあたかも文字列であるかのように見なして表示しようとしたら **Notice: Array to string conversion** 等のエラーが発生しちゃいますし。

それでは、勝手に名前を魔改造されるのが嫌なのでアクセス権を **`private`** にしてみましょう！ <ins>`private` は外部からのアクセスを全て遮断します。</ins>

```php:Robotクラス
class Robot {
    private $name = '';
}
```

```php:実行コード
$a = new Robot;
$a->name = 'ロボ太郎'; // エラー
$b = new Robot;
$b->name = 'ロボ次郎'; // エラー

echo $a->name; // エラー
echo $b->name; // エラー
```

正常な代入も弾いちゃったら意味が無いじゃん！こんなの機械じゃない！…はい、機械には操作パネルが必要ですね。

## **メソッド**

それではこのロボットの<ins>内部</ins>に、外部から入力したい名前を受け取って文字列であれば設定する **メソッド** を設けてみましょう。メソッド自体は外部からアクセス可能でなければ意味が無いので **`public`** に設定します。メソッドに対するアクセスは、プロパティ同様に **`->`** を使って行います。

```php:Robotクラス
class Robot {
    private $name = '';
    public function setName($name) {
        $this->name = (string)filter_var($name);
    }
}
```

### **メソッドってもうちょっと分かりやすく言うとつまり何？**

<ins>クラスに所属する</ins>関数のようなものです。

### **`$this` って何？**

インスタンス自身を指す特別な変数です。例えば、 

```php
$a->setName('ロボ太郎');
```

のようにコールされたとき、setNameメソッド内で `$this` は `$a` を表していることになります。

### **代入するとき何してんのこれ？**

全てを文字列にエラーなく変換する方法です。以下のリンクを参照してください。

**[Qiita - $_GET, $_POSTなどを受け取る際の処理](http://qiita.com/mpyw/items/2f9955db1c02eeef43ea)**

**[Qiita - PHPで各種バリデーション]
(http://qiita.com/mpyw/items/346f1789ad0e1b969ebc)**

さて、これで実行してみましょう。

```php:実行コード
$a = new Robot;
$a->setName('ロボ太郎');
$b = new Robot;
$b->setName('ロボ次郎');

echo $a->name; // エラー
echo $b->name; // エラー
```

まだ表示するときにエラーが出ますね。当然です、 **`private`** に設定したからには **書き込み** だけでなく **読み取り** 用のメソッドも作成する必要があります。

## **Getter/Setterパターン**

```php:Robotクラス
class Robot {
    private $name = '';
    public function setName($name) {
        $this->name = (string)filter_var($name);
    }
    public function getName() {
        return $this->name;
    }
}
```

```php:実行コード
$a = new Robot;
$a->setName('ロボ太郎');
$b = new Robot;
$b->setName('ロボ次郎');

echo $a->getName(); // ロボ太郎
echo $b->getName(); // ロボ次郎
```

### **やったぜ。**

オブジェクト指向の基本中の基本を習得することが出来ました。おめでとう。ちなみにこれは **Getter/Setterパターン** と呼ばれ、オブジェクト指向の根幹を為す技法です。

## **オブジェクト指向の特長**

- 外部には機能的にまとめられた最低限必要な情報しか公開しない。
- ライブラリ開発や複数人での開発に向いている。
- 大規模になってきてもメンテナンスがしやすい。

# **クラスとオブジェクト（中級）**

## **`__construct` メソッド (コンストラクタ) の利用**

**`__construct`** という名前で **コンストラクタ** メソッドを作ると、インスタンス生成時に自動的にコールされます。このような特別なメソッドを総称して **マジックメソッド** と呼びます。ここでは、わざわざ後からsetNameメソッドをコールしなくても良いようにしてみましょう。

```php:Robotクラス
class Robot {
    private $name = '';
    public function __construct($name) {
        $this->setName($name);
    }
    public function setName($name) {
        $this->name = (string)filter_var($name);
    }
    public function getName() {
        return $this->name;
    }
}
```

```php:実行コード
$a = new Robot('ロボ太郎');
$b = new Robot('ロボ次郎');

echo $a->getName(); // ロボ太郎
echo $b->getName(); // ロボ次郎
```

### **さっきまで `new Robot` って書いてたけど、 `new Robot()` じゃなくて良かったの？**

PHPでは問題ないようです。Javaではダメです。

### **マジックメソッドって他に何かあるの？**

**[PHP Manual - マジックメソッド](http://www.php.net/manual/ja/language.oop5.magic.php)** 

上記に全部記載されているので興味があればどうぞ。クラスを扱う上でほぼ必須となってくるのはコンストラクタぐらいで、他のメソッドを実装するかどうかはプログラマに委ねられます。

## **基本クラス `stdClass`**

`stdClass` は以下のようにデフォルトで定義されています。

```php
class stdClass { }
```

PHPでは未定義のインスタンスプロパティを新たに作成することが出来ます。連想配列と似た使い方ですね。言うまでも無く、この操作で自動的に作成されるプロパティは **`public`** です。

```php
$a = new stdClass;
$a->name = 'ロボ太郎';
echo $a->name; // ロボ太郎;
```

また、配列と `stdClass` は相互にキャストが可能です。

```php:stdClassから配列へ
$array = (array)$stdClass;
```

```php:配列からstdClassへ
$stdClass = (object)$array;
```

但し、 **数字添え字配列** に対して `(object)` キャストは使用しないでください。アクセス不能なプロパティが発生してしまいます。あくまで **連想配列** だけを対象としてください。この事象に関しては **[暇人向けの考察](http://qiita.com/mpyw/items/1d0593ac0de25225ab06#1-5)** で考察します。

## **オブジェクトと参照**

**[PHP Manual - リファレンスの説明](http://www.php.net/manual/ja/language.references.php)**
**[PHP Manual - オブジェクトと参照](http://www.php.net/manual/ja/language.oop5.references.php)**

詳しいことは上記にまとめられているので、ここでは更に要点を絞ります。

### <ins>通常の値渡し</ins>

`$b` の値に `$a` の値がコピーされます。

```php
$a = 'value';
$b = $a;
```

![通常の値渡し](https://qiita-image-store.s3.amazonaws.com/0/25060/0476a0d1-b9e8-fbe8-a68e-91b6baa14e07.png)

### <ins>通常のリファレンス渡し</ins>

`$a` と `$b` が常に同じ値を参照するようになります。 

```php
$a = 'value';
$b = &$a;
```

![通常のリファレンス渡し](https://qiita-image-store.s3.amazonaws.com/0/25060/9e3ecab8-930d-6955-9fd8-a38c945d14ad.png)

### <ins>オブジェクトIDの値渡し</ins>

`$b` の値に `$a` の値がコピーされます。

オブジェクトは実際にはIDという **値** によって管理されています。これは、 **[var_dump](http://www.php.net/manual/ja/function.var-dump.php)** 関数で表示したときに `#1` のような数字で得られます。オブジェクトIDが一致するとき、それらは全く同一のオブジェクトであることを意味します。

```php
$a = new stdClass;
$b = $a;
```

![オブジェクトIDの値渡し](https://qiita-image-store.s3.amazonaws.com/0/25060/81c82b51-b97a-d047-275f-45cb3e500097.png)

### <ins>オブジェクトIDのリファレンス渡し</ins>

`$a` と `$b` が常に同じ値を参照するようになります。 

オブジェクトIDのリファレンス渡しをする必要性が生まれることは稀です。

![オブジェクトIDのリファレンス渡し](https://qiita-image-store.s3.amazonaws.com/0/25060/adecf9b2-ad66-0b92-d3dd-3073cd9c5561.png)

```php
$a = new stdClass;
$b = &$a;
```

## **静的プロパティ / 静的メソッド / クラス定数** 

ここまでは全て **インスタンスプロパティ** と **インスタンスメソッド** を取り扱ってきました。ロボットの個体それぞれが持つプロパティとメソッドですね。ところが、設計図そのものが持つ **静的プロパティ** / **静的メソッド** / **オブジェクト定数** も存在します。オブジェクト定数は静的プロパティと同様に静的に定義される値なので本来は **クラス定数** と呼ぶべきですが、何故かこの名前がついています。

```php
class Sample {
    public static $property; // 静的プロパティ
    public static function method() { } // 静的メソッド
    const OBJECT_CONSTANT = null; // オブジェクト定数
}
```

- **`::`** のことを **スコープ定義演算子** と呼びます。
- オブジェクト定数は全て **`public`** 相当です。
- オブジェクト定数には必ず初期値の設定が必要です。
- オブジェクト定数に対して配列・オブジェクト・リソースを代入することは出来ません。
- オブジェクト定数に対して再代入を行うことは出来ません。
- クラス内にて自らのインスタンスを生成する場合、`new クラス名` の代わりに **`new self`** が使えます。

### <ins>厳密な対応表</ins>

- オブジェクト定数については、静的プロパティとほとんど扱いが同じなので省略します。
- 複数可能性があるものについては、以下の表中で最も一般的なものを太字で表しました。

…しかし、こんな<del>設計ミスを含んでいるような</del>ごちゃごちゃしたものは覚えなくていいです。

||インスタンス<br />プロパティ|インスタンス<br />メソッド|静的プロパティ |静的メソッド|
|:--:|:-----------------:|:-------------:|:-----------:|:---------:|
| 外部から<br />`->` 演算子で | **`$v->name`** | **`$v->name()`** | × | `$v->name()` |
| 外部から<br />`::` 演算子で | × | △<br />(非推奨警告) | **`クラス名::$name`**<br />`$v::$name` | **`クラス名::name()`**<br />`$v::name()` |
| インスタンス<br />メソッド内から<br />`->` 演算子で | **`$this->name`** | **`$this->name()`** | ×<br />(不可能なのに<br />バグで非推奨警告) | `$this->name()` |
| インスタンス<br />メソッド内から<br />`::` 演算子で | × | `$this::name()` | **`self::$name`**<br />`クラス名::$name`<br />`$this::$name` | **`self::name()`**<br />`クラス名::name()`<br />`$this::name()` |
| 静的<br />メソッド内から<br />`->` 演算子で | × | × | × | × |
| 静的<br />メソッド内から<br />`::` 演算子で | × | × | **`self::$name`**<br />`クラス名::$name` | **`self::name()`**<br />`クラス名::name()` |

### <ins>一般的な書き方に限定した対応表</ins>

覚えるならこちらで！

||インスタンス<br />プロパティ|インスタンス<br />メソッド|静的プロパティ|静的メソッド|
|:--:|:-----------------:|:-------------:|:-----------:|:---------:|
| 外部から | **`$v->name`** | **`$v->name()`** | **`クラス名::$name`** | **`クラス名::name()`** |
| インスタンス<br />メソッド内から | **`$this->name`** | **`$this->name()`** | **`self::$name`** | **`self::name()`** |
| 静的<br />メソッド内から | × | × | **`self::$name`** | **`self::name()`** |

### <ins>実践例(1) - [htmlspecialchars](http://www.php.net/manual/ja/function.htmlspecialchars.php), [html_entity_decode](http://www.php.net/manual/ja/function.htmls-entity-decode.php) のラッパークラス</ins>

単なる静的メソッドの集合体としてクラスを定義することも可能です。この場合、インスタンスを作成できないように <ins>`private` なコンストラクタ</ins> を定義しておくべきでしょう。

```php:クラス定義
class Html {
    public static function encode($str) {
        return htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
    }
    public static function decode($str) {
        return html_entity_decode($str, ENT_QUOTES, 'UTF-8');
    }
    private function __construct() { }
}
```

```php:使用例
$html = '<strong>Test</strong>';
$html = Html::encode($html);
echo $html; // &lt;strong&gt;Test&lt;/strong&gt;
$html = Html::decode($html);
echo $html; // <strong>Test</strong>
```

### <ins>実践例(2) - **[Factory Method パターン](http://ja.wikipedia.org/wiki/Factory_Method_%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3)** の実装</ins>

ロボットに「色」という情報を追加してみましょう。但し、以下の条件を満たすものとします。

- （ロボットの外装は製造工程で決まるので）一度色を決めたら二度と変更できないようにする。
- （工場の生産ラインは限られているので）色を `red` と `blue` に限定する。色の指定が間違っていた場合は `red` を適用する。

```php:Robotクラス
class Robot {
    private $name = '';
    private $color;
    public function __construct($name, $color) {
        $this->setName($name);
        $this->color = $color === 'blue' ? 'blue' : 'red';
    }
    public function setName($name) {
        $this->name = (string)filter_var($name);
    }
    public function getName() {
        return $this->name;
    }    
    public function getColor() {
        return $this->color;
    }    
}
```

```php:実行コード
$a = new Robot('ロボ太郎');
$b = new Robot('ロボ次郎', 'blue');
echo $a->getColor(); // red
echo $b->getColor(); // blue
```

一見、これで条件を満たせているような気がします。…しかし、PHPのコンストラクタはこんな呼び出し方も出来てしまうのです。

```php:実行コード
$a = new Robot('ロボ太郎', 'red');
echo $a->getColor(); // red
$a->__construct('ロボ太郎', 'blue');
echo $a->getColor(); // blue
```

おっと、色が変わってしまいました！何か手を打つ必要がありそうです。ここで、 **[Factory Method パターン](http://ja.wikipedia.org/wiki/Factory_Method_%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3)** を導入します。

- コンストラクタの第2引数に `red` を渡して生成したインスタンスを返す **createRedRobot** メソッドを静的に作成します。
- コンストラクタの第2引数に `blue` を渡して生成したインスタンスを返す **createBlueRobot** メソッドを静的に作成します。
- コンストラクタを **`private`** にし、<ins>外部から直接インスタンスを生成出来ない</ins>ようにします。

こうすればコンストラクタの第2引数には `red` か `blue` しか渡されないことが保証されたので、

```php
$this->color = $color === 'blue' ? 'blue' : 'red';
```

なんて面倒なことを書かなくても

```php
$this->color = $color;
```

で十分ですね！一石二鳥です。

```php:Robotクラス
class Robot {
    private $name = '';
    private $color;
    public static function createRedRobot($name) {
        return new self($name, 'red');
    }
    public static function createBlueRobot($name) {
        return new self($name, 'blue');
    }
    private function __construct($name, $color) {
        $this->setName($name);
        $this->color = $color;
    }
    public function setName($name) {
        $this->name = (string)filter_var($name);
    }
    public function getName() {
        return $this->name;
    }  
    public function getColor() {
        return $this->color;
    }    
}
```

```php:実行コード
$a = Robot::createRedRobot('ロボ太郎');
echo $a->getColor(); // red
$a->__construct('ロボ太郎', 'blue'); // エラー
echo $a->getColor(); // red
```

これで色が不変であるということも保証できました。

## **エラー**

PHPは古くから **エラー** を出力して異常時の対応を行ってきました。例えば、 **[htmlspecialchars](http://www.php.net/manual/ja/function.htmlspecialchars.php)** 関数は第1引数に **配列** を受け取った時、以下のようなエラーを発します。返り値はマニュアルに記載されている通り `false` となります。

```php:ソースコード
var_dump(htmlspecialchars(array()));
```

```text:実行結果
Warning:  htmlspecialchars() expects parameter 1 to be string, array given in ... on line ...
bool(false)
```

自分で定義する関数やメソッド内でも **[trigger_error](http://www.php.net/manual/ja/function.trigger-error.php)** 関数によりエラーを発生させることが出来ます。試しに、除算を行う関数 `div` を作成してみましょう。ただ、ゼロ除算に普通に着目するだけでは面白くないので…

- $\frac{n}{0}(n \gt 0)$ は $\infty$ とする
- $\frac{n}{0}(n \lt 0)$ は $-\infty$ とする
- $\frac{0}{0}$ は `false` としてエラーも発生させる
- エラーが1回でも発生したら強制終了する（戒め）

という実装にしてみましょう。 $\infty$ は定数 `INF` によって定義されているのでこれを利用します。

![野獣](https://qiita-image-store.s3.amazonaws.com/0/25060/90c1bb24-7499-1f3e-bc38-c79eed28a8d6.jpeg)


```php:関数定義
function div($a, $b) {
    if ($a > 0 && $b == 0) {
        return INF;
    }
    if ($a < 0 && $b == 0) {
        return -INF;
    }
    if ($a == 0 && $b == 0) {
        trigger_error('ゼロ除算とか無理だってはっきりわかんだね', E_USER_WARNING);
        return false;
    }
    return $a / $b;
}
```

```php:実行コード
echo "計算を始めます\n";
printf("div(1, 0) = %s\n", div(1, 0));
printf("div(-1, 0) = %s\n", div(-1, 0));
printf("div(0, 0) = %s\n", div(0, 0));
echo "計算は正常に終了しました\n";
```

```text:実行結果
計算を始めます
div(1, 0) = INF
div(-1, 0) = -INF
Warning:  ゼロ除算とか無理だってはっきりわかんだね in ... on line ...
div(0, 0) = 
計算は正常に終了しました
```

全然正常に終了してないですね。ちゃんと条件分岐を実装しましょうか。

```php:実行コード
echo "計算を始めます\n";
$answer = div(1, 0);
if ($answer === false) {
    die("そんなことはしてはいけない（戒め）\n");
}
printf("div(1, 0) = %s\n", $answer);
$answer = div(-1, 0);
if ($answer === false) {
    die("そんなことはしてはいけない（戒め）\n");
}
printf("div(-1, 0) = %s\n", $answer);
$answer = div(0, 0);
if ($answer === false) {
    die("そんなことはしてはいけない（戒め）\n");
}
printf("div(0, 0) = %s\n", $answer);
echo "計算は正常に終了しました\n";
```

```text:実行結果
計算を始めます
div(1, 0) = INF
div(-1, 0) = -INF
Warning:  ゼロ除算とか無理だってはっきりわかんだね in ... on line ...
そんなことはしてはいけない（戒め）
```

一応期待通りに動作するようになりましたが、なんだかとっても記述が冗長になってしまいました。それに、PHPのエラーメッセージもそのまま表示されちゃっててとても不恰好です。これに対して…

- 毎回エラーをチェックするように書かなくていい
- エラーメッセージを変数にセットして好きなように扱える

こんな便利な解決策を提供してくれるモデルが、次に紹介する「例外」なのです。

## **例外処理**

説明ばかりでは面白くないので、具体例から入りましょう。例外を用いて先ほどのコードを再構成してみます。

```php:関数定義
function div($a, $b) {
    if ($a > 0 && $b == 0) {
        return INF;
    }
    if ($a < 0 && $b == 0) {
        return -INF;
    }
    if ($a == 0 && $b == 0) {
        throw new Exception('ゼロ除算とか無理だってはっきりわかんだね');
    }
    return $a / $b;
}
```

```php:実行コード
try {
    echo "計算を始めます\n";
    printf("div(1, 0) = %s\n", div(1, 0));
    printf("div(-1, 0) = %s\n", div(-1, 0));
    printf("div(0, 0) = %s\n", div(0, 0));
    echo "計算は正常に終了しました\n";
} catch (Exception $e) {
    echo $e->getMessage() . "\n";
    echo "そんなことはしてはいけない（戒め）\n";
}
```

```text:実行結果
計算を始めます
div(1, 0) = INF
div(-1, 0) = -INF
ゼロ除算とか無理だってはっきりわかんだね
そんなことはしてはいけない（戒め）
```

メチャクチャすっきり書けましたね。では、例外について詳しく見ていきましょう。

### <ins>[Exception](http://www.php.net/manual/ja/class.exception.php) クラス</ins>

PHPでいうところの例外は全て **[Exception](http://www.php.net/manual/ja/class.exception.php)** クラス（もしくはその派生クラス）のインスタンスです。このクラスをメッセージに直結するものに絞って簡略化すると、以下のような構成になっています。デフォルトのコードは `0` です。また、Getter/Setterパターンがここにも現れていますね。

```php:Exceptionクラスの概略
class Exception {
    private $message;
    private $code;
    public function __construct($message = '', $code = 0) {
        $this->message = $message;
        $this->code    = $code;
    }
    public function getMessage() {
        return $this->message;
    }
    public function getCode() {
        return $this->code;
    }
}
```

このクラスの最大の特徴、それは

```php
throw new Exception('ゼロ除算とか無理だってはっきりわかんだね');
```

**投げる(throw)** ことが出来るということです。 **「投げるって何ぞや？」** と思われた方でも簡単に理解できるようにこれを表現するなら…そうですね、<ins>脱出するための指令を送る</ins>という喩えではどうでしょう。ポケモンの  **「あなぬけのヒモ」** あたりが分かりやすいんじゃないでしょうか。

![あなぬけのヒモ](https://qiita-image-store.s3.amazonaws.com/0/25060/c662f99e-8326-1e40-0a34-775e27696892.gif)

例外を投げるだけではそこで強制終了してしまうのと同じです。今度はこれを **捕まえる(catch)** 必要があります。「あなぬけのヒモ」であればちょうどそのダンジョンの出口で捕まりますね。

```php:例外処理の流れ
try {
    
    /* 1. この中で投げられた例外は */

} catch (Exception $e) { /* 2. ここで $e に代入されて */
     
    /* 3. ここの実行に強制的に移動する */

}
```

**「ちょっと待った！さっき確か[printf](http://www.php.net/manual/ja/function.printf.php)関数呼び出し中に終わっちゃったけどその処理ってどうなったのさ？」**

```php
printf("div(0, 0) = %s\n", div(0, 0));
```

こういう疑問が沸いてくる人は鋭いですね。例外処理においては、それまで実行途中であった<ins>完結していない処理は無かったことにされます</ins>。非常に重要な概念ですので頭に入れておいてください。

**[Exception](http://www.php.net/manual/ja/class.exception.php)** クラスは全ての例外の基底となるクラスですが、これを **継承** したクラスがいくつか存在します。継承については後ほど触れますので、ここでは **亜種のようなもの** として把握しておいてください。 **[Exception](http://www.php.net/manual/ja/class.exception.php)** クラスを直接扱うことはせず、例外の種類を詳しく表現している継承クラスを用いることが多いです。

### <ins>[LogicException](http://www.php.net/manual/ja/class.logicexception.php) クラス</ins>

プログラムの論理的な(Logic)誤りを指摘する例外です。いわば、コードを書いた自分のための警告です。この例外を捕まえる必要は基本的に無く、逆に<ins>発生しないようにプログラムを書かなければなりません</ins>。

```php
throw new LogicException('あのさぁ…（棒読み）');
```

### <ins>[RuntimeException](http://www.php.net/manual/ja/class.runtimeexception.php) クラス</ins>

プログラムの実行時における(Runtime)例外です。ユーザー入力・確率といった不確定要素の決定次第で発生してしまう、いわば発生しても仕方ない、<ins>発生することを想定して捕まえなければならない</ins>例外を表します。

```php
throw new RuntimeException('ねー、今日練習きつかったねー。大会近いからね。しょうがないね（迫真）');
```

こ↑こ↓から更に例外が細分化されていきますが、とりあえずこの2種類を覚えておけば問題はないでしょう。興味のある人は以下のまとめを参照してください。

**[Qiita - PHP標準例外まとめ](http://qiita.com/mikakane/items/dafd3d28c27311e5f429)**

また別の例として、最初のロボットの例で使っていた **setName** メソッドの挙動を変更してみます。以前は **「文字列にキャストさせてみて `false` として失敗していたらそれも強引に `""` に変換する」** という処理を書いていました。

```php
public function setName($name) {
    $this->name = (string)filter_var($name);
}
```

では今回はここを **「文字列にキャスト不可能な型が渡されたら例外をスローする」** という形に変更してみましょう。 **[LogicException](http://www.php.net/manual/ja/class.logicexception.php)** を更に継承した **[InvalidArgumentException](http://www.php.net/manual/ja/class.invalidargumentexception.php)** を使用してみます。

```php
public function setName($name) {
    $name = filter_var($name);
    if ($name === false) {
        throw new InvalidArgumentException('ホモ特有の使い方はNG');
    }
    $this->name = $name;
}
```

これを用いて以下のようなコードを実行すると例外が発生し、スクリプトの実行が停止されます。

```php:停止←setName←例外発生
$robot = Robot::createRedRobot('ロボ太郎');
$rotot->setName(array('そうだよ（便乗）'));
```

```php:停止←createRedRobot←__construct←setName←例外発生
$robot = Robot::createRedRobot(array('そうだよ（便乗）'));
```

## **組み込みクラスの例外**

ここまでは、あらかじめ自分で作成しておいた関数やメソッドで例外をスローするようにコーディングすることを説明しました。しかし、PHP側で<ins>自動的にスローされる</ins>例外もあります。ここではその一例を紹介します。

### <ins>データベース関連</ins>

内容的には **[「PHPでデータベースに接続するときのまとめ」](http://qiita.com/mpyw/items/b00b72c5c95aac573b71)** で紹介しているものを含んでいます。

| | **[PDOException](http://www.php.net/manual/ja/class.pdoexception.php)** | **[mysqli_sql_exception](http://www.php.net/manual/ja/class.mysqli-sql-exception.php)** |
|:---:|:---:|:---:|
|継承元|**[RuntimeException](http://www.php.net/manual/ja/class.runtimeexception.php)**|**[RuntimeException](http://www.php.net/manual/ja/class.runtimeexception.php)**|
|デフォルト設定のまま<br />スローするメソッド| **[PDO::__construct](http://www.php.net/manual/ja/pdo.construct.php)** のみ | 無し |
| 例外スロ―に関しての<br />設定を行う手段 | **[PDO::__construct](http://www.php.net/manual/ja/pdo.construct.php)**<br />**[PDO::setAttribute](http://www.php.net/manual/ja/pdo.setattribute.php)**| **[mysqli_report](http://www.php.net/manual/ja/function.mysqli-report.php)**|

#### **[PDO](http://www.php.net/manual/ja/book.pdo.php)** において全てのメソッドで例外をスローするように設定する

```php
$options = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION);
$pdo = new PDO($dsn, $username, $password, $options);
```

```php
$pdo = new PDO($dsn, $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
```

#### **[mysqli](http://www.php.net/manual/ja/book.mysqli.php)** において全ての関数/メソッドで例外をスローするように設定する

```php
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
```

```php:実行可能だがパフォーマンスを考慮していない糞SQLも防ぎたい場合はこうする
mysqli_report(MYSQLI_REPORT_ALL);
```

### <ins>[SplFileObject](http://www.php.net/manual/ja/class.splfileobject.php) クラス</ins>

PHPには古典的な **[fopen](http://www.php.net/manual/ja/function.fopen.php)** を初めとするファイル操作関数がありますが、これらをオブジェクト指向的に扱えるようにラップした **[SplFileObject](http://www.php.net/manual/ja/class.splfileobject.php)** というクラスも存在します。このクラスのメソッドの一部は `false` を返す代わりに **[RuntimeException](http://www.php.net/manual/ja/class.runtimeexception.php)** をスローします。

## **クロージャ**

### <ins>クロージャの基本</ins>

以下のような関数があるとします。

![MUR](https://qiita-image-store.s3.amazonaws.com/0/25060/6f22faf7-700c-b9bf-5981-c930769d22cb.png)

```php
function soudayo($option) {
    return "そうだよ（{$option}）";
}
echo soudayo('便乗'); // そうだよ（便乗）
```

PHPでは関数をオブジェクトとして生成することが出来ます。これは一般的に **クロージャ** / **無名関数** / **ラムダ** などと呼ばれます。最初の例をクロージャを利用するように書き換えてみましょう。

```php:実行コード
$closure = function ($option) {
    return "そうだよ（{$option}）";
};
var_dump($closure);
echo $closure('便乗');
```

```text:実行結果
object(Closure)#1 (1) {
  ["parameter"]=>
  array(1) {
    ["$option"]=>
    string(10) "<required>"
  }
}
そうだよ（便乗）
```

`"parameter"` や `"$option"` といった項目はPHPが内部的に保持しているだけの情報なので、プログラマ側が気にする必要はありません。以下に注目すべきポイントを挙げます。

1. **`$closure = オブジェクト;` という代入式の一部なので末尾に `;` が必要である。**
2. **`function` の後にすぐ引数の列挙が来る。関数名が存在しない。**
3. **クラス名は [Closure](http://www.php.net/manual/ja/class.closure.php) となっているが、 `new Closure` ではインスタンスを生成することが出来ない。あくまでこの構文を使用する必要がある。** 

### <ins>use キーワードの利用</ins>

クロージャ特有の機能として、 **use** キーワードを使用してそのスコープに存在する変数をインポート出来るというものがあります。通常の関数の場合は **global** キーワードを使用してグローバル変数にアクセスする方法しかありませんでした。

```php:通常の関数
$var = 'GLOBAL';
function a() {
    $var = 'A';
    return b();
}
function b() {
    global $var;
    return $var;
}
echo a(); // GLOBAL
```

```php:クロージャ
$var = 'GLOBAL';
$a = function a() {
    $var = 'A';
    $b = function () use ($var) {
        return $var;
    };
    return $b();
};
echo $a(); // A
```

クロージャ内で再帰的に自分自身をコールしたい場合、<ins>リファレンスでuseする</ins>必要があります。クロージャが生成される瞬間にはまだ代入が済んでいないためです。以下にフィボナッチ数列の第$n$項を求めるクロージャの例を示します。

```php
$fib = function ($n) use (&$fib) {
    switch ($n) {
        case 1:  return 0;
        case 2:  return 1;
        default: return $fib($n - 2) + $fib($n - 1);
    }
};
echo $fib(20); // 4181
```


## **コールバック型（callable）**

PHPには **[コールバック](http://php.net/manual/ja/language.types.callable.php)** という特殊な型が存在します。とはいっても、 **[var_dump](http://www.php.net/manual/ja/function.var-dump.php)** したときなどに型情報として表示されるわけではありません。変数に格納した値を元に<ins>関数やメソッドの名前を動的に指定して実行</ins>するための表現形式であり、実体は以下の何れかに該当します。

### **`クロージャ`**

実は先ほど紹介したクロージャの基本的な使い方は、単なるコールバックの一種に過ぎません。

```php
$closure = function soudayo($option) {
    return "そうだよ（{$option}）";
};
echo $closure('便乗'); // そうだよ（便乗）
```

### **`"関数名"`**

```php
function soudayo($option) {
    return "そうだよ（{$option}）";
}
$name = 'soudayo';
echo $name('便乗'); // そうだよ（便乗）
```

### **`"クラス指定::メソッド名"`**

主に静的メソッドのコールに用いられます。

```php:この記述は誤りを含んでいます。
class MUR {
    public static function soudayo($option) {
        return "そうだよ（{$option}）";
    }
}
$name = 'MUR::soudayo';
echo $name('便乗'); // そうだよ（便乗）
```

```php:この記述は誤りを含んでいます。
class MUR {
    private static function soudayo($option) {
        return "そうだよ（{$option}）";
    }
    public static function test() {
        $name = 'self::soudayo';
        echo $name('便乗'); // そうだよ（便乗）
    }
}
MUR::test();
```

<ins>重要な訂正</ins>
この記法は後に紹介する `call_user_func` 関数を利用したものでしか動作しないようです、皆さんは間違わないように注意してください。更に、PHP5.3以降でしか有効でないという制約もあります。

### **`array("クラス指定", "メソッド名")`**

主に静的メソッドのコールに用いられます。

```php
class MUR {
    public static function soudayo($option) {
        return "そうだよ（{$option}）";
    }
}
$name = array('MUR', 'soudayo');
echo $name('便乗'); // そうだよ（便乗）
```

```php:__CLASS__はそれが記述されたクラス名を表すマジック定数
class MUR {
    private static function soudayo($option) {
        return "そうだよ（{$option}）";
    }
    public static function test() {
        $name = array(__CLASS__, 'soudayo');
        echo $name('便乗'); // そうだよ（便乗）
    }
}
MUR::test();
```

### **`array(インスタンス, "メソッド名")`**

主にインスタンスメソッドのコールに用いられます。

```php
class MUR {
    public function soudayo($option) {
        return "そうだよ（{$option}）";
    }
}
$mur = new MUR;
$name = array($mur, 'soudayo');
echo $name('便乗'); // そうだよ（便乗）
```

```php
class MUR {
    private function soudayo($option) {
        return "そうだよ（{$option}）";
    }
    public function test() {
        $name = array($this, 'soudayo');
        echo $name('便乗'); // そうだよ（便乗）
    }
}
$mur = new MUR;
$mur->test();
```

## **[call_user_func](http://www.php.net/manual/ja/function.call-user-func.php) 関数の利用**

コールバック型は変数に入れた状態でないと有効ではありません。JavaScriptではよく用いられる以下のような記法も残念ながらPHPでは動作しません。

```php:BAD
echo function ($option) {
    return "そうだよ（{$option}）";
}('便乗'); // 構文エラー
```

変数に代入せずに即座にコールバックとして使いたい場合には **[call_user_func](http://www.php.net/manual/ja/function.call-user-func.php)** 関数を利用します。第1引数にコールバックを渡し、第2引数以降に本来の第1引数以降を並べていきます。

```php:GOOD
echo call_user_func(
    function ($option) {
        return "そうだよ（{$option}）";
    },
    '便乗'
); // そうだよ（便乗）
```

またこの関数の特徴として、<ins>本来リファレンス渡しである引数に対してエラーを出さずに値渡し出来る</ins>というものがあります。逆に言えば、リファレンス渡しをこの関数越しに行うことは出来ません。

```php:BAD
// Fatal error:  Only variables can be passed by reference
echo array_shift(array('YJSNPI', 'MUR', 'KMR'));
```

```php:BAD
// Strict Standards:  Only variables should be passed by reference
echo array_shift($members = array('YJSNPI', 'MUR', 'KMR')); // YJSNPI
```

```php:GOOD
echo call_user_func('array_shift', array('YJSNPI', 'MUR', 'KMR')); // YJSNPI
```

## **[call_user_func_array](http://www.php.net/manual/ja/function.call-user-func-array.php) 関数の利用**

これまでに関数やメソッドをコールする方法は3つ紹介しました。

- ごく普通にコールする
- 変数にコールバック型を代入しておいてコールする
- **[call_user_func](http://www.php.net/manual/ja/function.call-user-func.php)** 関数を用いてコールする

しかしこれらはどれも配列形式で与えられた可変長引数を渡すことは出来ませんでした。例えば **[array_merge](http://www.php.net/manual/ja/function.array-merge.php)** 関数は

```php
$x = array('YJSNPI');
$y = array('MUR');
$z = array('KMR');
$a = array_merge($x, $y, $z);
```

のように引数を受け取りますが、もしこの `$x` `$y` `$z` が以下のような可変長の配列で与えられていたらどうしましょう？

```php:引数が3個の場合
$members= array(
    array('YJSNPI'),
    array('MUR'),
    array('KMR'),
);
```

```php:引数が2個の場合
$members = array(
    array('YJSNPI'),
    array('MUR'),
);
```

個数を数えて1個1個場合分けして書きますか？

```php:BAD
if (count($members) === 2) {
    $a = array_merge($members[0], $members[1]);
} elseif (count($members) === 3) {
    $a = array_merge($members[0], $members[1], $members[2]);
}
```

いいえ、そんなことをする必要は全くありません。 **[call_user_func_array](http://www.php.net/manual/ja/function.call-user-func-array.php)** 関数を使えば配列を引数として展開してコールすることが出来ます。但し今回に限っては **[array_merge](http://www.php.net/manual/ja/function.array-merge.php)** 関数が引数を最低1つ必要とするため、1つ以上あるかどうかのチェックが必要です。

```php:GOOD
if ($members) { // (count($members) > 0) とほぼ同じ意味
    $a = call_user_func_array('array_merge', $members);
} else {
    $a = array();
}
```

実はこの関数にも1つ弱点があります。<ins>コンストラクタがコールできない</ins>ことです。以下のような **[func_get_args](http://www.php.net/manual/ja/function.func-get-args.php)** 関数を用いた可変長引数を受け取るコンストラクタがあったときに対応できません。

```php
class KarateTeam {
    private $members;
    public function __construct() {
        $this->members = func_get_args();
    }
    public function display() {
        echo implode(', ', $this->members);
    }
}
```

```php:BAD
$members = array('YJSNPI', 'MUR', 'KMR');
/* Warning:  call_user_func_array() expects parameter 1 to be a valid callback      *
 *           non-static method KarateTeam::__construct() cannot be called staticall */
$team = call_user_func_array('KarateTeam::__construct', $members);
$team->display();
```

これに対応するためには、 **[ReflectionClass::newInstanceArgs](http://www.php.net/manual/ja/reflectionclass.newinstanceargs.php)** メソッドを用います。 リフレクションの意味に関してはWikipediaを参照してください。

**[Wikipedia - リフレクション (情報工学)](http://ja.wikipedia.org/wiki/%E3%83%AA%E3%83%95%E3%83%AC%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3_(%E6%83%85%E5%A0%B1%E5%B7%A5%E5%AD%A6))**

```php:GOOD
$members = array('YJSNPI', 'MUR', 'KMR');
$reflection = new ReflectionClass('KarateTeam');
$team = $reflection->newInstanceArgs($members);
$team->display(); // YJSNPI, MUR, KMR
```

リフレクションは他にもたくさん用途がありますが、ここでの紹介はこの程度にしておきます。

## **継承**

### <ins>継承の基本</ins>

さて、オブジェクト指向の理解に関わる最大の山場が **継承** です。継承は、同じようなコードを二度三度と定義し直すことを回避するためにある、<ins>コード再利用の仕組み</ins>です。この定義でBから見てAのことを **親** と呼ぶことがあります。

```php:BはAの継承クラスであるという定義
class B extends A { } 
```

継承したクラスでは…

- 親クラスのプロパティやメソッドが<ins>全て</ins>引き継がれます。
- 引き継いだもののうち **`public`** または **`protected`** なものに限定して内部からアクセスすることが出来ます。
- 外部からのアクセスは **`public`** に限定されます。

以下の例をご覧ください。

```php:団員クラス
class KarateTeamMember {
    public function comment($sentence, $option = '') {
        if ($option === '') {
            return $sentence;
        } else {
            return "{$sentence}（{$option}）";
        }
    }
}
```

```php:個別のクラス
class YJSNPI extends KarateTeamMember {
    public function say($sentence, $option = '') {
        echo 'YJSNPI「' . $this->comment($sentence, $option) . '」' . PHP_EOL;
    }
}
class MUR extends KarateTeamMember {
    public function say($sentence, $option = '') {
        echo 'MUR「' . $this->comment($sentence, $option) . '」' . PHP_EOL;
    }
}
class KMR extends KarateTeamMember {
    public function say($sentence, $option = '') {
        echo 'KMR「' . $this->comment($sentence, $option) . '」' . PHP_EOL;
    }
}
```

```php:実行コード
$yjs = new YJSNPI;
$mur = new MUR;
$kmr = new KMR;
$yjs->say('じゃけん夜行きましょうね');
$mur->say('おっそうだな');
$mur->say('あ、そうだ', '唐突');
$mur->say('おいKMRァ、さっき俺等が着替えてるときチラチラ見てただろ');
$kmr->say('いや見てないです');
$mur->say('ウソつけぜったいみてたゾ', 'クレしん');
$kmr->say('何で見る必要なんかあるんですか', '正論');
$yjs->say('KMRさお前さ、さっきヌッ、脱ぎ終わった時にさ、なかなか出て来なかったよな？');
$mur->say('そうだよ', '便乗');
```

```text:実行結果
YJSNPI「じゃけん夜行きましょうね」
MUR「おっそうだな」
MUR「あ、そうだ（唐突）」
MUR「おいKMRァ、さっき俺等が着替えてるときチラチラ見てただろ」
KMR「いや見てないです」
MUR「ウソつけぜったいみてたゾ（クレしん）」
KMR「何で見る必要なんかあるんですか（正論）」
YJSNPI「KMRさお前さ、さっきヌッ、脱ぎ終わった時にさ、なかなか出て来なかったよな？」
MUR「そうだよ（便乗）」
```

`YJSNPI` `MUR` `KMR` クラスではcommentという名前のメソッドは実装されていないのに利用することが出来ています。親クラスに `public` で存在しているからです。

### <ins>継承とアクセス権の関係</ins>

|  | `private` | `protected` | `public` |
|:--:|:----:|:---:|:----:|
|継承されるか | ○ | ○ | ○ |
|継承したクラス内からのアクセスが可能か | × | ○ | ○ |
|クラス外からのアクセスが可能か | × | × | ○ |

## **オーバーライド**

## **図解で見る継承関係**

分かりやすく図にまとめてみました。

![図解](https://qiita-image-store.s3.amazonaws.com/0/25060/791fd69d-8dec-bf85-3843-c348aa055983.png)


さて、ここで1つ疑問が沸いてくると思います。

> **なんでわざわざ `(Aの)$publicP` って書いてるの？**
> **普通に `parent::$publicP` じゃダメなの？**

一見 `parent::$publicP` でアクセス出来そうなのですが…

```php:実行コード
class A {
    public $publicP = 'Aのやつ';	
}
class B extends A {
    public $publicP = 'Bのやつ';
    public function test() {
        echo parent::$publicP;
    }
}
$b = new B;
echo $b->test();
```

```text:期待される結果
Aのやつ
```

```text:実際の結果
Fatal error:  Access to undeclared static property: A::$publicP
```

つまりこういうことなんです。

| | `->` (アロー演算子) | `::` (スコープ定義演算子) |
|:---:|:---:|:---:|
| メソッド | オーバーライドに基づいたアクセス | クラスを明示したアクセス |
| プロパティ | オーバーライドに基づいたアクセス<br />**（※インスタンスプロパティに限る）**| クラスを明示したアクセス<br />**(※静的プロパティに限る)** |

更なる疑問が沸いてくるとすれば

> **何でプロパティだけそんな面倒な区別するの？…じゃあもしかして**
>
> ```php:実行コード
> class A {
>    public $p;
>    public static $p; 	
> }
> ```
>
> **のように名前が被ってて形式が違う2種類のプロパティを作ったりできるの？**

このようなものだと思いますが…

```text:実際の結果
Fatal error:  Cannot redeclare A::$publicP
```

はい、<ins>出来ません</ins>（断言）
PHPがそういう仕様だからとして納得してください（涙目）

また、 **[厳密な対応表](#3-15)** にも記載はしていますが…

```php:実行コード
$yj = new YJSNPI;
$yj::say('†悔い改めて†');
```

```text:実行結果
Strict Standards:  Non-static method YJSNPI::say() should not be called statically
YJSNPI「†悔い改めて†」
```

このように<ins>外部から`::`を使ってインスタンスメソッドをコール</ins>すると、動作に支障は無いのですが **非推奨警告** が出ます。特に使用する意味もないので素直に `->` を使いましょう。

# **[クラスとオブジェクト（上級）](http://qiita.com/mpyw/items/1d0593ac0de25225ab06#1-4)**

# **[暇人向けの考察](http://qiita.com/mpyw/items/1d0593ac0de25225ab06#1-5)**