初心者必見！オブジェクト指向の三大要素をわかりやすく解説（カプセル化・継承・ポリモーフィズム）

# はじめに
前回では、オブジェクト指向についてサクッと紹介しました。今回はオブジェクト指向の三代要素について紹介していきます。

# 1. カプセル化
カプセル化とは、**クラスの機能のうち、使い手に必要のないものを隠してしまうこと**を指します。自動販売機を例に見てみましょう！

#### ユーザーが行うこと(インターフェース)
- お金を入れる
- 商品を選択する
- 商品をとる
- お釣りをとる

#### 内部の仕組み（カプセル化）
- お金の計算
- 在庫の管理
- おつりの処理
- 商品の取り出しメカニズム

#### カプセル化との関係
- 内部の仕組みを隠す（情報隠蔽）
    - ユーザーはお金の計算や在庫管理の詳細を知らなくても利用できる。
- 外部に提供する機能（インターフェース）
    - ボタンを押す、お金を入れる、といった操作のみをユーザーに提供する。

![商品選択.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3935088/85dbcf42-ddfd-4f7a-b0c7-6e0540dd6acd.png)


### ▼実際にプログラムで書いてみよう

```php
<?php
class VendingMachine {
    private $balance = 0; // 入金額
    private $inventory = [ // 在庫管理
        "コーラ" => ["price" => 150, "stock" => 5],
        "お茶" => ["price" => 130, "stock" => 3],
        "水" => ["price" => 100, "stock" => 10]
    ];

    public function insertMoney($amount) {
        if ($amount <= 0) {
            return "正しい金額を入れてください。\n";
        }
        $this->balance += $amount;
        return "現在の残高: {$this->balance}円\n";
    }

    public function selectProduct($product) {
        if (!isset($this->inventory[$product])) {
            return "選択した商品はありません。\n";
        }

        $price = $this->inventory[$product]["price"];
        $stock = $this->inventory[$product]["stock"];

        if ($stock <= 0) {
            return "{$product} は売り切れです。\n";
        }

        if ($this->balance < $price) {
            return "お金が足りません。あと " . ($price - $this->balance) . "円必要です。\n";
        }

        // 商品の購入処理
        $this->balance -= $price;
        $this->inventory[$product]["stock"] -= 1;
        return "{$product} を購入しました！ 残高: {$this->balance}円\n";
    }

    public function takeChange() {
        $change = $this->balance;
        $this->balance = 0;
        return "お釣り: {$change}円\n";
    }

    public function checkStock() {
        echo "現在の在庫状況:\n";
        foreach ($this->inventory as $product => $data) {
            echo "{$product}: {$data['stock']}個 (価格: {$data['price']}円)\n";
        }
    }
}

// 自動販売機の使用例
$vendingMachine = new VendingMachine();

echo $vendingMachine->insertMoney(200);
echo $vendingMachine->selectProduct("コーラ");
echo $vendingMachine->takeChange();
$vendingMachine->checkStock();


```

:::note info
**実装ポイント**
- `private` 変数を使って `balance`（入金額）と `inventory（在庫）`を カプセル化。
- `insertMoney($amount)` でお金を投入し、残高を管理。
- `selectProduct($product)` で商品を選択し、購入できるか判定。
- `takeChange()` でお釣りを取得し、残高をリセット。
- `checkStock()`で在庫状況を確認。
:::


# 2. 継承
継承とは、**基になるクラス機能(メソッド)を引き継ぎながら、新たな機能を追加したり、元の機能の一部だけを修正したりできる仕組み**のことを指します。乗り物を例に見てみましょう！


### ▼構文
```php
class サブクラス名 extends スーパークラス{
//メソッド・プロパティなどの定義
}
```

### ▼例
#### 親クラス(共通の乗り物)
はじめに、乗り物が共通の機能を持つ`Vehicle`クラスを作成します

```php
class Vehicle {
    //「速さ」 という共通のプロパティ
    public $speed;

    public function __construct($speed) {
        $this->speed = $speed;
    }

    //「移動する」という共通の機能を持たせる
    public function move() {
        return "時速 {$this->speed} km で移動します。";
    }
}

```

#### 子クラス（車と自転車）
次に、車と自転車を`Vehicle`クラスから継承させ、それぞれの特徴を追加します

```php
class Car extends Vehicle {
    public function honk() {
        return "クラクションを鳴らします！（プップー！）";
    }
}

class Bicycle extends Vehicle {
    public function ringBell() {
        return "ベルを鳴らします！（チリンチリン！）";
    }
}
```

#### 実際に使用してみる
```php
$car = new Car(80); // 車の速さは80km
echo $car->move(); // "時速 80 km で移動します。"
echo $car->honk(); // "クラクションを鳴らします！（プップー！）"

$bicycle = new Bicycle(20); // 自転車の速さは20km
echo $bicycle->move(); // "時速 20 km で移動します。"
echo $bicycle->ringBell(); // "ベルを鳴らします！（チリンチリン！）"
```

このように、継承を使うことで 「共通の機能を親クラスにまとめ、子クラスで独自の機能を追加する」ことができます。


:::note alert
**注意事項**
phpでは、一つのクラスが同時に複数のクラスを親に持つような継承(**多重継承**)はできません。

```php
class Cat extends Animal, Person{ //複数の親クラスは継承できない
```
:::

### ▼継承を使用すべき場合
親と子クラスに**is-a**の関係が成り立つかを確認し、成り立つ場合は継承を使用するべき！is-a関係とは「SubClass is a Superclass」であるということです。つまり、今回の例では、Car(車)はVehicle(乗り物)になるので、継承関係は妥当であると判断できます。

# 2. ポリモーフィズム
ポリモーフィズムとは、**同じメソッド名を使いながら、異なるクラスで異なる動作を実現すること**です。ポイントは、親クラスの型を使って統一的にオブジェクトを扱えることになります。

### ▼ポリモーフィズムの実装方法
#### 1. 抽象メソッド（Abstract Class）を使う
抽象メソッドとは、それ自体が中身を持たない空のメソッドのことを指します。

```php
abstract class Animal {
    abstract public function makeSound(); // 子クラスで実装を強制

    public function move() {
        return "移動します。"; // すべての動物に共通
    }
}

class Dog extends Animal {
    public function makeSound() {
        return "ワンワン！";
    }
}

class Cat extends Animal {
    public function makeSound() {
        return "ニャーニャー！";
    }
}

```

#### 2. インターフェース（Interface）を使う
interface を使うと、「このクラスは必ずこのメソッドを持つ」 ことを強制できます。
```php
interface AnimalInterface {
    public function makeSound(); // すべてのクラスで実装を強制
}

class Dog implements AnimalInterface {
    public function makeSound() {
        return "ワンワン！";
    }
}

class Cat implements AnimalInterface {
    public function makeSound() {
        return "ニャーニャー！";
    }
}

```


:::note info
**抽象クラスとインターフェースの違い**

✅ **共通点**  
どちらも共通のメソッドを強制する役割を持つ。

✅ **違い**
- **抽象クラス（`abstract class`）**  
  - 共通の処理を実装できる（すべての子クラスで同じ動作）
  - プロパティ（変数）を持てる
  - `extends` を使って1つだけ継承可能
- **インターフェース（`interface`）**  
  - すべてのメソッドは未実装（処理を持たない）
  - プロパティを持てない
  - `implements` で複数のインターフェースを実装可能（多重実装）

:::

# おわりに
今回はオブジェクト指向の三代要素の紹介をしました。少しでもお役に立てば幸いです。最後までご覧いただきありがとうございました！