【PHP】インターフェイスとクラスの抽象化の使い分けついて

この記事は[エイチーム引越し侍 / エイチームコネクト Advent Calendar 2019](https://qiita.com/advent-calendar/2019/hikkoshi) 2日目の記事です。

# きっかけ
業界未経験からエンジニアなり、およそ半年が経ちました。最近ゼロからちょっとしたツールを作る機会をいただき、なんとか形にはなったのですが、拡張性や保守性を担保するには、コード側で制約するような設計が必要なのではないかと思い、これらについて調べてみました。

# インターフェイスとクラスの抽象化は似ている

## インターフェイス
複数のクラスに共通の機能を実装するために、その実体を定義することなく指定する仕組みで、インターフェイスを用いると、特定のオブジェクトが特定の機能（メソッド）を有することが保証されます。インターフェイスに定義されているメソッドを実装しないと致命的なエラーとなります。

## クラスの抽象化
共通の機能を抽象的な親クラスで定義し、特有の機能は個々の子クラスでそれぞれ実装させたい場合に定義します。抽象化を使うには、抽象化したクラスを子クラスに継承し、すべてのabstractメソッドを実装する必要があります。

# どう使うか
色々調べた結果、私が感じたイメージがこちらです。PHPは、クラスやインターフェイスの多重継承ができるが、クラスの場合は子が親のメソッドを呼ぶ際、どちらの親のメソッドが呼ばれるのかわかりにくいため、クラスの多重継承はあまり使用しないほうが良いと思いました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329017/34d101dd-2f38-9cdd-9d2f-c61b2b6b948b.png)

クラスの抽象化については、通常の継承のように複数のクラスで共通する処理があるが、親のみで使用することがない或いはしたくない場合に使用するで良いと思いました（自分はこう思う、こう使っているなどあればコメントしていただけると幸いです:bow:）。インターフェイスについては、指示書的な使い方をし、どういったメソッドを持ったクラスを作成するかを決めておき、他の開発メンバーが依存する部分を作業するときに使えるのでは無いかと思いました。（自分はこう(ry）。また、メソッドの型宣言も用いることで、クラスかインターフェイスかを切り分けることができるのもメリットかなと思いました。

# 使ってみた

## インターフェイス

```php
interface Player
{
    public function play();
    public function stop();
}

class musicPlayer implements Player
{
    public function play()
    {
      echo '音楽再生中' . PHP_EOL;
    }

    public function stop()
    {
      echo '音楽停止中' . PHP_EOL;
    }
}

class moviePlayer implements Player
{
    public function play()
    {
      echo '動画再生中' . PHP_EOL;
    }

    public function stop()
    {
      echo '動画停止中' . PHP_EOL;
    }
}


$obj1 = new musicPlayer();
$obj2 = new moviePlayer();

$obj1->play(); // 音楽再生中
$obj1->stop(); // 音楽停止中

$obj2->play(); // 動画再生中
$obj2->stop(); // 動画停止中
```

## クラスの抽象化

```php
abstract class Polygon
{
  public function showHeight()
  {
    return $this->height;
  }

  public function showWidth()
  {
    return $this->width;
  }

  abstract public function clucArea();
}

class Square extends Polygon
{
  public $height = 1;
  public $width = 1;

  public function clucArea()
  {
    return $this->height * $this->width;
  }
}

class Triangle extends Polygon
{
  public $height = 2;
  public $width = 2;

  public function clucArea()
  {
    return $this->height * $this->width / 2;
  }
}

$obj1 = new Square;
$obj2 = new Triangle;

echo $obj1->showHeight() . PHP_EOL; // 1
echo $obj2->showWidth() . PHP_EOL;  // 2

echo $obj1->clucArea() . PHP_EOL; // 1
echo $obj2->clucArea() . PHP_EOL; // 2
```

# 参考
- [オブジェクト インターフェイス](https://www.php.net/manual/ja/language.oop5.interfaces.php)
- [クラスの抽象化](https://www.php.net/manual/ja/language.oop5.abstract.php)
- [型宣言](https://www.php.net/manual/ja/functions.arguments.php#functions.arguments.type-declaration
)
- [[PHP]abstractとinterfaceの使い分けを整理してみる](https://suin.io/522)
- [PHPのinterfaceとabstractを正しく理解して使い分けたいぞー](https://havelog.ayumusato.com/develop/php/e166-php-interface-abstract.html)
- [PHPにおけるインターフェースと抽象クラス、多重継承、トレイトの使い方](https://www.atmarkit.co.jp/ait/articles/1511/02/news016_2.html)
- [パーフェクトPHP](https://www.amazon.co.jp/%E3%83%91%E3%83%BC%E3%83%95%E3%82%A7%E3%82%AF%E3%83%88PHP-PERFECT-3-%E5%B0%8F%E5%B7%9D-%E9%9B%84%E5%A4%A7/dp/4774144371/ref=sr_1_1?adgrpid=56985217887&gclid=CjwKCAiA5o3vBRBUEiwA9PVzar8v-ehFk0l2Pa2LMiJgtQ8ivSjnjsm6NRPp_mypGU0yvckp3chOQxoC4RwQAvD_BwE&hvadid=338533712109&hvdev=c&hvlocphy=1009461&hvnetw=g&hvpos=1t1&hvqmt=e&hvrand=9438966585656371783&hvtargid=aud-759242200006%3Akwd-333806024309&hydadcr=4072_10899412&jp-ad-ap=0&keywords=%E3%83%91%E3%83%BC%E3%83%95%E3%82%A7%E3%82%AF%E3%83%88php&qid=1575205557&sr=8-1)

# お知らせ
エイチームグループでは一緒に活躍してくれる優秀な人材を募集中です。
興味のある方はぜひとも[エイチームグループ採用ページ](https://www.a-tm.co.jp/recruit/requirements/career/lifestylesupport-webengineer/)よりご応募ください！

Qiita Jobsの[エイチーム引越し侍社内システム企画 / 開発チーム](https://jobs.qiita.com/employers/a-hikkoshi/development_teams/176)、[社内システム開発エンジニアを募集！](https://jobs.qiita.com/postings/309)からチャットでご質問いただくことも可能です！

# 明日
明日は、@ikuma_hayashiさんの「php+mecab環境をdockerで構築する（仮）」です。