PHP classについて（基本）コンストラクタ使い方 / staticを使用したメソッド呼び出し / selfの使用 / 例外処理について

#PHPのclassを例文を読み解きながら理解していく
参考文書：初めてのPHP（オライリー）

###例１）

```php

<?php

class Entree
{
    public static $hoge = 'hoge';
    public $name;
    public $ingredients = [];
    const fugo = 'fugo';

    public function hasIngredient($ingredient)
    {
        return in_array($ingredient, $this->ingredients);
    }

    public function echoHoge()
    {
        echo self::$hoge;
    }
    public static function getSizes()
    {
        return ['small', 'medium', 'large'];
    }
}
//スープインスタンス
$soup = new Entree;
$soup->name = ' 鳥スープ';
$soup->ingredients = ['chicken', 'water'];


//サンドイッチインスタンス
$sandwich = new Entree;
$sandwich->name = '鳥サンド';
$sandwich->ingredients = ['chicken', 'bread'];

foreach (['chicken', 'lemon', 'bread', 'water'] as $ing) {
    if ($soup->hasIngredient($ing)) {
        print "Soup contains $ing.\n";
    }
    if ($sandwich->hasIngredient($ing)) {
        print "sandwich contains $ing.\n";
    }
}

$sandwich->echoHoge();
var_dump(Entree::getSizes());// staticの定義によりインスタンス化せず「::」を使用しクラスを呼び出せる

結果
/*
Soup contains chicken.
sandwich contains chicken.
sandwich contains bread.
Soup contains water.
hogearray(3) {
  [0]=>
  string(5) "small"
  [1]=>
  string(6) "medium"
  [2]=>
  string(5) "large"
*/
```

まず上記ではスープとサンドイッチ双方同じEntreeクラスからインスタンスを生成。
それぞれで名前と材料を設定。
foreachで条件分岐により該当の食材を使用しているものをエコーしている。

```php
$sandwich->echoHoge();
var_dump(Entree::getSizes());// staticの定義によりインスタンス化せず「::」を使用しクラスを呼び出せる
```
上記ではclass内で```self```を使用した例と
staticで指定したメソッドの呼び出し```::メソッド名```
の検証をしている。

###例２）コンストラクタを使用すると名前や食材の指定を省略出来る

```php

<?php

class Entree
{
    public static $hoge = 'hoge';
    public $name;
    public $ingredients = [];
    const fugo = 'fugo';

public function __construct($name,$ingredients){
$this->name = $name;
$this->ingredients = $ingredients;
}


    public function hasIngredient($ingredient)
    {
        return in_array($ingredient, $this->ingredients);
    }

}

//スープインスタンス
$soup = new Entree('鳥スープ２',['chicken', 'water']);
// $soup->name = ' 鳥スープ';
// $soup->ingredients = ['chicken', 'water'];


//サンドイッチインスタンス
$sandwich = new Entree('鳥サンド',['chicken', 'bread']);
// $sandwich->name = '鳥サンド';
// $sandwich->ingredients = ['chicken', 'bread'];

foreach (['chicken', 'lemon', 'bread', 'water'] as $ing) {
    if ($soup->hasIngredient($ing)) {
        print "Soup contains $ing.\n";
    }
    if ($sandwich->hasIngredient($ing)) {
        print "sandwich contains $ing.\n";
    }
}

結果
//結果は例）１と同じ
```

class内で

```php
public function __construct($name,$ingredients){
$this->name = $name;
$this->ingredients = $ingredients;
}
```
を設定し

各インスタンス化時に

```php
$soup = new Entree('鳥スープ２',['chicken', 'water']);
```
上記のように引数を設定することで例１で設定した内容と同様の処理をコンストラクタで実装している。



##例外処理
上記の記述でインスタンス化した際

```php

$sandwich = new Entree('鳥サンド',['chicken', 'bread']);
```
第二引数を配列に指定しない場合

```php
    public function hasIngredient($ingredient)
    {
        return in_array($ingredient, $this->ingredients);
    }
```
上記でin_array()を使用していることから以下のようなエラーになる。

```terminal
Warning: in_array() expects parameter 2 to be array, string given in /Applications/MAMP/htdocs/test/class1.php on line 24
sandwich contains chicken.

Warning: in_array() expects parameter 2 to be array, string given in /Applications/MAMP/htdocs/test/class1.php on line 24

Warning: in_array() expects parameter 2 to be array, string given in /Applications/MAMP/htdocs/test/class1.php on line 24
sandwich contains bread.

Warning: in_array() expects parameter 2 to be array, string given in /Applications/MAMP/htdocs/test/class1.php on line 24
```

そこでコンストラクタに例外処理を追加
※変更箇所はスープインスタンスの第二引数部分

```php

//スープインスタンス
// $soup = new Entree('鳥スープ２', ['chicken', 'water']);
$soup = new Entree('鳥スープ２', 'water');
```

###例３）

```php

<?php

class Entree
{
    public static $hoge = 'hoge';
    public $name;
    public $ingredients = [];
    const fugo = 'fugo';

    public function __construct($name, $ingredients)
    {
        if (!is_array($ingredients)) {
            throw new Exception('$ingredientsは配列を指定してください');
        }


        $this->name = $name;
        $this->ingredients = $ingredients;
    }


    public function hasIngredient($ingredient)
    {
        return in_array($ingredient, $this->ingredients);
    }
}

//スープインスタンス
// $soup = new Entree('鳥スープ２', ['chicken', 'water']);
$soup = new Entree('鳥スープ２', 'water');



//サンドイッチインスタンス
$sandwich = new Entree('鳥サンド', ['chicken', 'bread']);


foreach (['chicken', 'lemon', 'bread', 'water'] as $ing) {
    if ($soup->hasIngredient($ing)) {
        print "Soup contains $ing.\n";
    }
    if ($sandwich->hasIngredient($ing)) {
        print "sandwich contains $ing.\n";
    }
}
```

上記では

```php

        if (!is_array($ingredients)) {
            throw new Exception('$ingredientsは配列を指定してください');
        }
```
をコンストラクタに追加した。
結果は

```
Fatal error: Uncaught Exception: $ingredientsは配列を指定してください in /Applications/MAMP/htdocs/test/class1.php:13
Stack trace:
#0 /Applications/MAMP/htdocs/test/class1.php(30): Entree->__construct('\xE9\xB3\xA5\xE3\x82\xB9\xE3\x83\xBC\xE3\x83\x97\xEF\xBC\x92', 'water')
#1 {main}
  thrown in /Applications/MAMP/htdocs/test/class1.php on line 13
```
上記のように例外に指定した内容が表示されるようになった。