鬼滅で例えるクラス設計と書き方

鬼滅の映画をみたのでせっかくなので学習中のプログラミングにも活用したいと思いました。
クラス設計に関してもっと色々理解したら拡張していく予定です。

# 前提
- getterメソッドで長くなるので便宜上プロパティは全てpublicです
- クラス、インスタンス、プロパティ、メソッド、コンストラクト、staticの記法がメイン(抽象クラスも少し)
- フレームワークを使ってないので一部MVCの内容を同一ファイルに記述してます

abstract/interfaceの使い方を勉強した上でその上でもっと改良していきたいです。


> こうした方が良いと言う箇所があればコメントいただけますと幸いです。
もし鬼滅をご存知の方であれば、できれば鬼滅で例えてもらえるとこの記事の品質向上にも繋げやすいので可能であればよろしくお願いしますm(_ _)m
鬼舞辻無惨をどこかに入れたかったです。

# classとは
classとはプロパティ(変数)とメソッド（関数)をグルーピングしたもの。
> 変数や関数は、小規模開発の際は名前のつけたで管理できるが、人間なので、沢山できてくると関数や変数名を重複してうわがいてしまったり、やたら関数や変数名が長くなってしまったり、まったく関係ない処理を作りたいのに他の処理と競合してしまわないかと気を使ったりなど非効率なので、「商品情報を処理する変数と関数」「ユーザー情報を処理する変数と関数」「購入情報を処理する変数と関数」という処理に必要なプログラムをグルーピングして管理しやすくしよう！という先人の偉大な産物。
 ”設計書”と例えられることが多いが、”設計書”であるclass内のプロパティやメソッドを使うこともある。

# 設計
今回は以下クラス継承です。

Character (抽象クラス)
┗ → Oni (鬼) → Kizuki (十二鬼月)
┗ → Taishi (隊士) → Hashira (柱) 
![class_sekei.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/825124/3188999c-3ade-badd-4e47-efbd0a391918.png)
画像を新しいタブで開いていただくとと見やすいかもしれません。

# 抽象クラス(Character)
```Character.php
<?php

//抽象class
abstract class Character
{
  abstract protected function attack();
}

?>
```
- 先頭に`abstract`を付ける
- 継承先で`オーバーライドして欲しいメソッドにabstract`と付ける
- 抽象クラスはインスタンスを作れない

# Oni,Kizukiクラス
※ この見出し以下のコードは全てOni.phpです。長いので分割してます。

### Oniクラス
- 別ファイルに記述した継承元の抽象クラスファイルを、冒頭で`require_once`します。`extends`で継承しましょう。
- `全てのOniインスタンスに共通するプロパティはstatic`をつけてクラスから取得できるようにしておきます。
- 抽象クラスにある`attack()`は`オーバーライド`必須です。
- `__construct()`メソッドに記述された処理は`インスタンス作成と同時に処理が実行される`(プロパティが勝手にセットされるので便利)

```Oni.php
<?php

require_once "Character.php";

//Oniクラス
class Oni extends Character 
{
  //Property
  public static $count = 0;
  public static $blood = "鬼";
  public static $weak = "太陽光";
  public $name;
  public $sex;
  public $age;
  public $lifePoint;
  public $hitPoint;
  public $ateSum;

  //Function
  public function __construct($name,$sex,$age,$lifePoint,$hitPoint,$ateSum)
  {
    self::$count++;
    $this->name = $name;
    $this->sex = $sex;
    $this->age = $age;
    $this->lifePoint = $lifePoint;
    $this->hitPoint = $hitPoint;
    $this->ateSum = $ateSum;
  }

  public function attack()  //オーバーライドするため必ず書かないとエラーになるメソッド
  {
    return "継承元の抽象クラスCharacterのattack()をオーバーライド";
  }

  public function eat()
  {
    return "捕食数を増やすメソッド";
  }

  public function recover()
  {
    return "lifePointを増やすメソッド";
  }

}
```
### Kizukiクラス
- Oniクラスを`extends`で継承しましょう。
- Oniクラスのプロパティとメソッドは引き継いでいるので、`十二鬼月にのみ追加で必要なプロパティとメソッドを追加`。

```Oni.php
//Kizukiクラス
class Kizuki extends Oni
{
  //Property
  public static $count = 0;
  public static $category = "十二鬼月";
  public $number;
  
  //Function
  public function __construct($name,$sex,$age,$lifePoint,$hitPoint,$ateSum,$number)
  {
    self::$count++;
    $this->name = $name;
    $this->sex = $sex;
    $this->age = $age;
    $this->lifePoint = $lifePoint;
    $this->hitPoint = $hitPoint;
    $this->ateSum = $ateSum;
    $this->number = $number;
  }

  public function order()
  {
      return "鬼に命令するメソッド";
  }
}
```

### ２つのクラスのインスタンスを作成
- インスタンスのプロパティの値は配列で渡すため`ReflectionClass`と`(インスタンス名)->newInstanceArgs`を活用。
- 値がインスタンスの配列をreturn
 
```Oni.php
function createOni()
{
    //Oniデータ
    $oni_list = [
    "yasamaru" => ["朱紗丸","f",16,25,20,23],
    "yahaba" => ["矢琶羽","m",18,20,35,9],
    ];
    //Oni配列を作成
    $data=[];
    foreach($oni_list as $key => $value)
    {
        $oni = new ReflectionClass("Oni"); //instance作成
        $instance = $oni->newInstanceArgs($value); //引数にプロパティ値の配列を渡す
        $data[] = $instance; //Oniインスタンスの配列を作成
    }
    return $data;
}

function createKizuki()
{
    //Kizukiデータ
    $kizuki_list = [
    "kokushibou" => ["黒死牟","m",27,250,150,450,"壱"],
    "douma" => ["童磨","m",24,220,135,420,"弐"],
    "akaza" => ["猗窩座","m",18,180,100,380,"参"],
    ];
    //Kizuki配列を作成
    $data=[];
    foreach($kizuki_list as $key => $value)
    {
        $kizuki = new ReflectionClass("Kizuki"); //instance作成
        $instance = $kizuki->newInstanceArgs($value); //引数にプロパティ値の配列を渡す
        $data[] = $instance; //Oniインスタンスの配列を作成
    }
    return $data;
}

//実行
$data_Oni = createOni();
$data_Kizuki = createKizuki();
```

# Taishi,Hashiraクラス
※ この見出し以下のコードは全てOni.phpです。長いので分割してます。
※ Oni,Kizukiクラスと流れが同じなのでコードだけ貼ります。

### Taishiクラス

```Taishi.php
<?php

require_once "Character.php";

//Taishiクラス
class Taishi extends Character 
{
  //Property
  public static $count = 0;
  public static $blood = "人間";
  public static $weak = "鬼の血";
  public $name;
  public $sex;
  public $age;
  public $lifePoint;
  public $hitPoint;

  //Function
  public function __construct($name,$sex,$age,$lifePoint,$hitPoint)
  {
    self::$count++;
    $this->name = $name;
    $this->sex = $sex;
    $this->age = $age;
    $this->lifePoint = $lifePoint;
    $this->hitPoint = $hitPoint;
  }

  public function attack()  //オーバーライドするため必ず書かないとエラーになるメソッド
  {
    return "継承元の抽象クラスCharacterのattack()をオーバーライド";
  }
}
```

# Hashiraクラス

```Taishi.php
/Hashiraクラス
class Hashira extends Taishi
{
  //Property
  public static $count = 0;
  public static $category = "鬼殺隊";
  public $type;
  public $tsuguko;
  
  //Function
  public function __construct($name,$sex,$age,$lifePoint,$hitPoint,$type,$tsuguko)
  {
    self::$count++;
    $this->name = $name;
    $this->sex = $sex;
    $this->age = $age;
    $this->lifePoint = $lifePoint;
    $this->hitPoint = $hitPoint;
    $this->type = $type;
    $this->tsuguko = $tsuguko;
  }

  public function tsuguko()
  {
      return "継子を交換するメソッド";
  }
}
```

# ２つのクラスのインスタンスを作成

```Taishi.php
function createTaishi()
{
    //Taishiデータ
    $taishi_list = [
    "tanjiro" => ["竈門 炭治郎","m",15,12,32],
    "zenitsu" => ["我妻 善逸","m",16,10,28],
    "inosuke" => ["嘴平 伊之助","m",15,15,30],
    ];
    //Taishi配列を作成
    $data=[];
    foreach($taishi_list as $key => $value)
    {
        $taishi = new ReflectionClass("Taishi"); //instance作成
        $instance = $taishi->newInstanceArgs($value); //引数にプロパティ値の配列を渡す
        $data[] = $instance; //Taishiインスタンスの配列を作成
    }
    return $data;
}

function createHashira()
{
    //Hashiraデータ
    $hashira_list = [
    "giyuu" => ["冨岡 義勇","m",21,18,34,"水柱","なし"],
    "shinobu" => ["胡蝶 しのぶ","f",18,10,21,"蟲柱","栗花落 カナヲ"],
    "kyoujyurou" => ["煉獄 杏寿郎","m",20,22,35,"炎柱","なし"],
    "tengen" => ["宇髄 天元","m",23,20,40,"音柱","なし"],
    "muichirou" => ["時透 無一郎","m",14,22,12,"霞柱","なし"],
    ];
    //Hashira配列を作成
    $data=[];
    foreach($hashira_list as $key => $value)
    {
        $hashira = new ReflectionClass("Hashira"); //instance作成
        $instance = $hashira->newInstanceArgs($value); //引数にプロパティ値の配列を渡す
        $data[] = $instance; //Hashiraインスタンスの配列を作成
    }
    return $data;
}

//実行
$data_Taishi = createTaishi();
$data_Hashira = createHashira();
```

# View
```index.php
<?php
require_once('Oni.php');
require_once('Taishi.php');
?>

<!DOCTYPE html>
<html>

<head>
    <meta charest="UTF-8">
    <title>鬼滅で例えるclassとinstance</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css"
        integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous">
    <style>
        .red {color: red}
        .blue {color: blue}
        .green {color: green}
        #ONI {padding: 15px;}
        #TAISHI {padding: 15px;}
        th,td {text-align: center}
    </style>
</head>

<body>
    <section id="ONI">
    <h1>Character→Oni→Kizuki</h1>
    <hr>
    <h2>Oniインスタンス</h2>
   <p>数→<?=Oni::$count ?> / 血→<?=Oni::$blood ?> / 弱点→<?=Oni::$weak ?></p> <!-- staticプロパティを取得 -->
    <table class="table table-striped">
        <tr>
            <th>name</th>
            <th>sex</th>
            <th>age</th>
            <th>lifePoint</th>
            <th>hitPoint</th>
            <th>ateSum</th>
            <th class="red">attack()</th>
            <th>eat()</th>
            <th>recover()</th>
        </tr>
    <?php foreach ($data_Oni as $key => $value){ ?> 
        <tr>
            <td><?=$value->name ?></td>
            <td><?=$value->sex ?></td>
            <td><?=$value->age ?></td>
            <td><?=$value->lifePoint ?></td>
            <td><?=$value->hitPoint ?></td>
            <td><?=$value->ateSum ?></td>
            <td><?=$value->attack() ?></td>
            <td><?=$value->eat() ?></td>
            <td><?=$value->recover() ?></td>
        </tr>
    <?php } ?>
    </table>

    <h2>Kizukiインスタンス</h2>
   <p>数→<?=Kizuki::$count ?> / 血→<?=Kizuki::$blood ?> / 弱点→<?=Kizuki::$weak ?> / <span class="blue">カテゴリ→<?=Kizuki::$category ?></span></p>
    <table class="table table-striped">
        <tr>
            <th>name</th>
            <th>sex</th>
            <th>age</th>
            <th>lifePoint</th>
            <th>hitPoint</th>
            <th>ateSum</th>
            <th class="green">number</th>
            <th>attack()</th>
            <th>eat()</th>
            <th>recover()</th>
        </tr>
    <?php foreach ($data_Kizuki as $key => $value){ ?> 
        <tr>
            <td><?=$value->name ?></td>
            <td><?=$value->sex ?></td>
            <td><?=$value->age ?></td>
            <td><?=$value->lifePoint ?></td>
            <td><?=$value->hitPoint ?></td>
            <td><?=$value->ateSum ?></td>
            <td><?=$value->number ?></td>
            <td><?=$value->attack() ?></td>
            <td><?=$value->eat() ?></td>
            <td><?=$value->recover() ?></td>
        </tr>
    <?php } ?>
    </table>
 </section>
 

  <section id="TAISHI">
    <h1>Character→Taishi→Hashira</h1>
    <hr>
    <h2>Taishiインスタンス</h2>
   <p>数→<?=Taishi::$count ?> / 血→<?=Taishi::$blood ?> / 弱点→<?=Taishi::$weak ?></p>
    <table class="table table-striped">
        <tr>
            <th>name</th>
            <th>sex</th>
            <th>age</th>
            <th>lifePoint</th>
            <th>hitPoint</th>
            <th class="red">attack()</th>
        </tr>
    <?php foreach ($data_Taishi as $key => $value){ ?> 
        <tr>
            <td><?=$value->name ?></td>
            <td><?=$value->sex ?></td>
            <td><?=$value->age ?></td>
            <td><?=$value->lifePoint ?></td>
            <td><?=$value->hitPoint ?></td>
            <td><?=$value->attack() ?></td>
        </tr>
    <?php } ?>
    </table>

    <h2>Hashiraインスタンス</h2>
   <p>数→<?=Hashira::$count ?> / 血→<?=Hashira::$blood ?> / 弱点→<?=Hashira::$weak ?> / <span class="blue">カテゴリ→<?=Hashira::$category ?></span></p>
    <table class="table table-striped">
        <tr>
            <th>name</th>
            <th>sex</th>
            <th>age</th>
            <th>lifePoint</th>
            <th>hitPoint</th>
            <th class="green">type</th>
            <th class="green">tsuguko</th>
            <th class="red">attack()</th>
            <th>tsuguko()</th>
        </tr>
    <?php foreach ($data_Hashira as $key => $value){ ?> 
        <tr>
            <td><?=$value->name ?></td>
            <td><?=$value->sex ?></td>
            <td><?=$value->age ?></td>
            <td><?=$value->lifePoint ?></td>
            <td><?=$value->hitPoint ?></td>
            <td><?=$value->type ?></td>
            <td><?=$value->tsuguko ?></td>            
            <td><?=$value->attack() ?></td>
            <td><?=$value->tsuguko() ?></td>
        </tr>
    <?php } ?>
    </table>
 </section>

</body>
</html>
```

# 実行画面
- 赤文字は<font color="red">抽象クラスから継承されているメソッド</font>です。
- 青文字はstaticプロパティを`クラス名::プロパティ名`で<font color="blue">クラスから直接取得</font>しています。
- 緑文字は継承元クラスにはない、<font color="green">追加したプロパティ</font>です。

### 鬼と十二鬼月のインスタンスデータ
![スクリーンショット 2020-11-06 18.09.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/825124/3b656a4d-92ea-b936-07cb-e85cb41125e3.png)

### 隊士と柱のインスタンスデータ

![スクリーンショット 2020-11-06 18.09.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/825124/011d8b0c-215e-9dca-ef80-ba8d871705ac.png)

# 記事
require_onceについて
https://qiita.com/v97ug/items/d058f69b1cf6f606aad2