---
# vim: set tabstop=4 softtabstop=4 shiftwidth=4 expandtab:
layout: "@/layouts/MarkdownLayout.astro"
---

import Toc from "../../components/Toc.astro";
import ExampleWrapper from "@/components/ExampleWrapper.astro";
import RenderFile from "@/components/RenderFile";
import RenderHtml from "@/components/RenderHtml";
import Details from "@/components/Details.astro";

export const title = "オブジェクト指向とクラス";

# {title}

スマホのボリュームの上げ下げをするために、わざわざ蓋を明けてこの端子を触ってね・・・ということはないですよね。  
大抵は音量を操作するためのボタンが用意されて、そこを操作してもらううことになると思います。

今のは極端な例ではありましたが、プログラミングの世界でも同様のことが起こっています。

オブジェクト指向とはこのような危険な操作を隠して、ユーザーが安全に操作できるようにするための設計思想です。

## TOC

## 大事な用語

- Class (クラス)
- インスタンス
- 継承

## データのまとまり

プログラムを組むとき、データのまとまりを扱うことがよくあります。

- 設定ファイル
- データベースから取得したデータ
- 入力フォームから送られてきたデータ
- ...etc

この中でも入力フォームは、開発者自身であってもどのような値が入ってくるかわからなくなることが多いです。

このようなフォームがあったとしても、

<RenderFile path="public/sample/tips/object-oriented/form.html" />

データを受け取る側は、どのような値が入ってきているのかわかりません。  
これを知るために、とりあえず変数の中身を表示する処理を書いてみたり、

```php file=public/sample/tips/object-oriented/confirm.php
```

<br />

もととなるHTMLの`name`属性を直接確認してみたりすることもあるでしょう。

<Details summary="HTMLを見る">

```php file=public/sample/tips/object-oriented/form.html collapse={1-153, 184-188} /name="[a-zA-Z0-9]+"/
```

</Details>

<br />

これらの確認を経て、送られてくるデータには以下のものがあるとはじめてわかります。

- name
- email
- gender
- message

しかし、予めどのようなデータが入ってくるのかを把握したいものです。

今回の例のような入力フォームであれば、HTMLの変更によって意図しないデータが入ってくる可能性もありますし、そもそもHTMLを見ないとどのようなデータが入ってくるのかわからないのは、あまり良い状態とは言えません。

これを解決するために、あるデータの集まりに対して、具体的になにがあるのかを説明するようなアプローチが存在します。  
その最も原始的な方法が、 `構造体(struct)` や `クラス(class)` を使うことです。

これはHTMLから送られてくるデータ全体をひとつのまとまりとして扱う考え方です。  
この構造の中に、具体的に何が入ってくるのかを定義することができます。

```php
<?php
/**
 * HTMLから送られてくるデータの構造を定義するクラス
 */
class FormField {
    public $name;
    public $email;
    public $gender;
    public $message;
}
```

この`FormField`クラスでは、この構造の中に、`name`、`email`、`gender`、`message`というデータが入ってくることを定義しています。  

なお、これらクラスの中にあるデータは、以下のような様々な呼び方があります。

- プロパティ
- メンバー変数
- フィールド
- 属性

このページの中では、クラスの中で定義される変数を、**プロパティ**と呼ぶことにします。

次の章では、クラスの使い方について説明していきます。

## クラスの使い方

### 構造を定義する (メンバー変数)

[データのまとまり](#データのまとまり) で示したように、そのまとまりに対して具体的にどのようなデータが入ってくるのかを定義することができます。  
これはデータ構造を表すための設計図のようなものです。  
このクラスは通常の型と同じように、変数の型として使うことができます。

ところで通常の型は代入した時点で、その型の値が入ってきます。

```php
<?php
// numberという型で、値は123
$data = 123;

// stringという型で、値は"hello"
$data = "hello";
```

<br />

一方でクラスは、データ構造を定義するための型で、設計図のようなものだと説明しました。  
これを具体的なデータとして使うためには、`new` というキーワードを使って変数に代入する必要があります。

```php collapse={2-8}
<?php

class FormField {
    public $name;
    public $email;
    public $gender;
    public $message;
}

// $変数 = new クラス名();
$formField = new FormField();
```

<br />

この `new クラス名()` で作られたものを、クラスの **インスタンス (instance)** と呼びます。

ところでこの時点では、作られたインスタンスには、特に初期値を設定していません。  
なにかしらの手段で、値を入れてあげる必要があります。

```php collapse={2-8}
<?php

class FormField {
    public $name;
    public $email;
    public $gender;
    public $message;
}

// $変数 = new クラス名();
$formField = new FormField();

var_dump($formField);
// この時点では、空の値であることを示すNULLが入っている (言語によって違う)
// object(FormField)#1 (4) {
//   ["name"]=>
//   NULL
//   ["email"]=>
//   NULL
//  ["gender"]=>
//   NULL
//   ["message"]=>
//   NULL
// }

$formField->name = $_POST["name"];
$formField->email = $_POST["email"];
$formField->gender = $_POST["gender"];
$formField->message = $_POST["message"];

var_dump($formField);
// object(FormField)#1 (4) {
//   ["name"]=>
//   string(5) "Alice"
//   ["email"]=>
//   string(17) "alice@example.com"
//   ["gender"]=>
//   string(3) "woman"
//   ["message"]=>
//   string(11) "Hello world"
// }
```

<br />

これで、クラスを使うための最低限の準備ができました。

### 振る舞いを定義する (メソッド / 関数)

クラスでは、インスタンスが持っているデータを活用して、なにかしらの振る舞いを定義することができます。
これを **メソッド (method)** と呼びます。

例として、`gender` に値を設定するメソッドを定義してみましょう。

```php {8-11}
<?php
class FormField {
    public $name;
    public $email;
    public $gender;
    public $message;

    public function setGender($gender) {
        // 自身のgenderプロパティに、引数の値を代入する
        $this->gender = $gender;
    }
}

$formField = new FormField();
$formField->setGender("man");
echo $formField->gender . PHP_EOL;
// => man

$formField->setGender("woman");
echo $formField->gender . PHP_EOL;
// => woman
```

<br />

`$this` という変数が出てきました。

通常クラスのインスタンスは、`$formField = new FormField();` のように、変数に代入されます。  
しかしこの `$formField` という変数はクラスの外で定義されている変数で、クラスの中からはどのような変数名で代入されるのかわかりません。

とはいえクラスの中から、自分自身が持っているデータにアクセスしたいことはよくあります。  
このときに、クラスのメソッド内でのみ使える特別な変数 `$this` を使うことで、クラスの中から自分自身のインスタンスを指すことができます。

この`$this`を経由して、自身が持っている `gender` というプロパティにアクセス、値を代入するということができます。

<br />
<br />

値を設定するメソッドを定義したので、次は値を活用するメソッドも定義してみましょう。

```php {12-38}
<?php
class FormField {
    public $name;
    public $email;
    public $gender;
    public $message;

    public function setGender($gender) {
        $this->gender = $gender;
    }

    public function reply_template() {
        $gender_display = null;
        if ($this->gender === "man") {
            $gender_display = "男性";
        } else if ($this->gender === "woman") {
            $gender_display = "女性";
        } else {
            $gender_display = "不明";
        }

        $body = "この度はお問い合わせいただきまして、誠にありがとうございます。
        いただいた内容を確認の上、改めてご連絡いたします。

        ご入力内容

        お名前: {$this->name}
        性別: {$gender_display}
        メールアドレス: {$this->email}

        お問い合わせ内容
        ---
        {$this->message}
        ---
        ";

        return $body;
    }
}

$formField = new FormField();
$formField->name = "Alice";
$formField->email = "alice@example.com";
$formField->gender = "woman";
$formField->message = "Hello world";

$template = $formField->reply_template();
// この度はお問い合わせいただきまして、誠にありがとうございます。
// いただいた内容を確認の上、改めてご連絡いたします。
//
// ご入力内容
//
// お名前: Alice
// 性別: 女性
// メールアドレス: alice@example.com
//
// お問い合わせ内容
// ---
// Hello world
// ---

$formField->name = "Bob";

$template = $formField->reply_template();
// 名前がBobに変わっていることがわかる
```

### 特別なメソッド

クラスの中で、特別な意味を持つメソッドが存在します。  
この中では、**constructor (コンストラクタ)** と呼ばれるメソッドが特に重要です。

[クラスの使い方](#クラスの使い方) の章で、クラスをインスタンス化するためには、`new クラス名()` という構文を使う必要があると説明しました。  
その書き方は、クラス名の後ろに、括弧 `()` をつける形になっています。

まるで関数を呼び出すような書き方になっていますが、これがコンストラクタと呼ばれる特別なメソッドの呼び出しになっています。

具体的に見てみましょう。

```php
<?php

class User {
    public $name;

    public function __construct() {
        echo "newされました";
    }
}

$user = new User(); // __construct() が呼び出される
// => newされました
```

このコンストラクタには、引数を定義することもできます。  
その多くの場合、インスタンスを作るときにプロパティの初期値を設定するために使われます。

```php
<?php

class User {
    public $name;

    public function __construct($name) {
        echo "newされました";
        $this->name = $name;
    }
}

// 引数が指定されていないので、エラーになる
// $user = new User();

$user = new User("Alice");  // nameプロパティに"Alice"が入ったインスタンスが代入される
echo $user->name . PHP_EOL;
// => Alice
```

<br />

なお、このコンストラクタは言語によって書き方が異なります。

<Details summary="他の言語のコンストラクタを見てみる">

```java title=Java
class User {
    public String name;

    // クラス名がそのままコンストラクタの名前になる
    public User() {
        System.out.println("newされました");
    }
}
```

<br />

```python title=Python
class User:
    # コンストラクタは __init__ という名前になる
    def __init__(self):
        print("newされました")
```

<br />

</Details>

### 派生を作る (継承)

クラスには、**継承 (inheritance)** という機能があります。  
これはあるクラスをもとにして、さらに新しいクラスを作ることができる機能です。

継承をすることにより、もとのクラスの一部分だけを変更したり、もとのクラスの機能を拡張したりすることができます。

この、継承をするためのクラスを、**派生クラス (derived class)** と呼びます。  
逆に、もとになるクラスを、**基底クラス (base class)** と呼びます。

また、基底クラスに存在するメソッドを派生クラスで、同じ名前で再定義することができます。  
これを **オーバーライド (override)** と呼びます。

```php
<?php

class User {
    public $name;

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

    public function greet(User $target) {
        echo "こんにちは、{$target->name}さん！";
    }
}

$owner = new User("オーナー");

$user1 = new User("Bob");
$user1->greet($owner);
// => こんにちは、オーナーさん！


class CheerfulUser extends User {
    // greet() メソッドをオーバーライド
    public function greet(User $target) {
        echo "やあ、{$target->name}さん！";
    }
}

$user2 = new CheerfulUser("Charlie");
$user2->greet($owner);
// => やあ、オーナーさん！


class PoliteUser extends User {
    public function greet(User $target) {
        super::greet($target);  // Userクラスのgreetメソッドを呼び出す
        echo "今日もいい天気ですね！";
    }
}

$user3 = new PoliteUser("Dave");
$user3->greet($owner);
// => こんにちは、オーナーさん！今日もいい天気ですね！


class RudeUser extends User {
    public function greet(User $target) {
        echo "おい、{$target->name}！";
    }

    // 基底クラスにはない、shout() というメソッドを独自に定義した
    public function shout(User $target) {
        echo "うるせぇ、{$target->name}！";
    }
}

$user4 = new RudeUser("Eve");
$user4->greet($owner);
// => おい、オーナー！
$user4->shout($owner);
// => うるせぇ、オーナー！
```

### 敢えてアクセス制限をかける (アクセス修飾子)

ここまで読み進めてきた人に取っては、ソースコードに含まれる `public` というキーワードが気になっているかもしれません。  
これは、どこからでもアクセスすることを許可するという意味の **アクセス修飾子 (access modifier)** と呼ばれるものです。

アクセス修飾子には、いくつかの種類がありますが、主に以下の3つが使われます。

| 種類 | 説明 |
| :-- | :-- |
| `public` | どこからでもアクセスできる |
| `protected` | クラスの中と、継承したクラスの中からアクセスできる |
| `private` | クラスの中からのみアクセスできる |

具体的に見てみましょう。

あるユーザーに対応するクラスがあったとして、そのメソッドに成人かどうかを判定する `isAdult()` というメソッドがあったとします。  
また、`birthday()` を呼び出すことが、誕生日を迎えることを表すとします。

```php
<?php

class User {
    public $name;
    public $age;

    public function __construct(array $values) {
        $this->name = $values["name"];
        $this->age = $values["age"];
    }

    public function birthday() {
        $this->age += 1;
    }

    public function isAdult() {
        if ($this->age >= 20) {
            echo "{$this->age}歳なので、成人です";
        } else {
            echo "{$this->age}歳なので、未成年です";
        }
    }
}

$user = new User([ "name" => "Alice", "age" => 18 ]);

$user->isAdult();
// => 18歳なので、未成年です

// 2回誕生日を迎える
$user->birthday();
$user->birthday();

$user->isAdult();
// => 20歳なので、成人です
```

<br />

今、すべてのアクセス修飾子が `public` になっています。  
このとき、どのような不都合があるでしょうか？

```php collapse={6-22} add={"ageはpublicなので、外部から代入できる": 37-38}
<?php

class User {
    public $name;
    public $age;

    public function __construct(array $values) {
        $this->name = $values["name"];
        $this->age = $values["age"];
    }

    public function birthday() {
        $this->age += 1;
    }

    public function isAdult() {
        if ($this->age >= 20) {
            echo "{$this->age}歳なので、成人です";
        } else {
            echo "{$this->age}歳なので、未成年です";
        }
    }
}

$user = new User([ "name" => "Alice", "age" => 18 ]);

$user->isAdult();
// => 18歳なので、未成年です

// 2回誕生日を迎える
$user->birthday();
$user->birthday();

$user->isAdult();
// => 20歳なので、成人です


$user->age = 10;    // 年齢詐称

$user->isAdult();
// => 10歳なので、未成年です
```

<br />

なんと年齢を詐称することができてしまいました。  
これができるということは、未成年にも関わらずにお酒を飲んだり、タバコを吸ったりすることを許してしまうことになります。

これをさせないために、`age` プロパティを `private` にしてみましょう。

```php collapse={6-22} "private" {"ageはprivateなので、外部から操作できない": 37-38}
<?php

class User {
    private $name;
    private $age;

    public function __construct(array $values) {
        $this->name = $values["name"];
        $this->age = $values["age"];
    }

    public function birthday() {
        $this->age += 1;
    }

    public function isAdult() {
        if ($this->age >= 20) {
            echo "{$this->age}歳なので、成人です";
        } else {
            echo "{$this->age}歳なので、未成年です";
        }
    }
}

$user = new User([ "name" => "Alice", "age" => 18 ]);

$user->isAdult();
// => 18歳なので、未成年です

// 2回誕生日を迎える
$user->birthday();
$user->birthday();

$user->isAdult();
// => 20歳なので、成人です


$user->age = 10;    // Error: Cannot access private property User::$age
```

<br />

これで、誕生日を迎える以外の方法で、年齢を変更することができなくなりました。

ところで、`User`というクラスから、派生したクラスが作られたとします。  
そこに、`greet()` というメソッドを定義して、ユーザーに挨拶させたいとします。

```php add={25-29} "private"
<?php

class User {
    private $name;
    private $age;

    public function __construct(array $values) {
        $this->name = $values["name"];
        $this->age = $values["age"];
    }

    public function birthday() {
        $this->age += 1;
    }

    public function isAdult() {
        if ($this->age >= 20) {
            echo "{$this->age}歳なので、成人です";
        } else {
            echo "{$this->age}歳なので、未成年です";
        }
    }
}

class ExtendedUser extends User {
    public function greet() {
        echo "こんにちは、{$this->name}さん！"; // Undefined property: User::$name
    }
}
```

<br />

これはエラーになります。  
なぜなら、基底クラスである `User` クラスの `name` プロパティは、アクセス修飾子が `private` になってなっています。  
そのため、継承先のクラスではこのプロパティにアクセスすることができないからです。

これを解決するために、アクセス修飾子を `protected` にしてみましょう。

```php "protected" {31-33} {"protectedなので、関係のない場所からは操作できない": 45-46}
<?php

class User {
    protected $name;
    protected $age;

    public function __construct(array $values) {
        $this->name = $values["name"];
        $this->age = $values["age"];
    }

    public function birthday() {
        $this->age += 1;
    }

    public function isAdult() {
        if ($this->age >= 20) {
            echo "{$this->age}歳なので、成人です";
        } else {
            echo "{$this->age}歳なので、未成年です";
        }
    }
}

class ExtendedUser extends User {
    public function greet() {
        echo "こんにちは、{$this->name}さん！";
    }
}

$user = new ExtendedUser([ "name" => "Alice", "age" => 18 ]);
$uset->greet();
// => こんにちは、Aliceさん！

$user->isAdult();
// => 18歳なので、未成年です

// 2回誕生日を迎える
$user->birthday();
$user->birthday();

$user->isAdult();
// => 20歳なので、成人です


$user->age = 10;    // Error: Cannot access protected property User::$age
```

<br />

これで、継承先のクラスからは `name` プロパティにアクセスすることができるようになりました。  
`age`も同様に `protected` にしているので、継承先のクラスからはアクセスできますが、関係のない場所からはアクセスできないようになっています。

### staticな変数

クラスは、基本的にはインスタンスごとにデータを持ちます。  
一方で、クラス全体で共有されるデータを定義することもできます。

これを **staticな変数** 、日本語では **静的変数** と呼びます。

staticな変数は、クラス名を使ってアクセスすることができます。  
またクラス全体で共有しているため、インスタンスを通してアクセスしても同じ値が見えるようになっています。

```php
<?php

class MyClass {
    public static $static_variable = "初期値";
}

$instance = new MyClass();

echo MyClass::$static_variable . " (MyClass)" . PHP_EOL;
echo $instance::$static_variable . " (instance)" . PHP_EOL;
// => 初期値 (MyClass)
// => 初期値 (instance)

MyClass::$static_variable = "MyClassから値を変更";

echo MyClass::$static_variable . " (MyClass)" . PHP_EOL;
echo $instance::$static_variable . " (instance)" . PHP_EOL;
// => MyClassから値を変更 (MyClass)
// => MyClassから値を変更 (instance)

$instance::$static_variable = "instanceから値を変更";

echo MyClass::$static_variable . " (MyClass)" . PHP_EOL;
echo $instance::$static_variable . " (instance)" . PHP_EOL;
// => instanceから値を変更 (MyClass)
// => instanceから値を変更 (instance)
```

<br />

このstaticな変数は、継承したクラスからもアクセスすることができます。  
ただし継承先で同じ名前のstaticな変数を定義している場合、それ以降は別の変数として扱われるようになります。

```php
<?php

class MyClass1 {
    public static $static_variable = "初期値";
}

class MyClass2 extends MyClass1 {
    // なにも定義しない
}

class MyClass3 extends MyClass2 {
    public static $static_variable = "MyClass3の初期値";
}

class MyClass4 extends MyClass3 {
    // なにも定義しない
}

echo MyClass1::$static_variable . " (MyClass1)" . PHP_EOL;
echo MyClass2::$static_variable . " (MyClass2)" . PHP_EOL;
echo MyClass3::$static_variable . " (MyClass3)" . PHP_EOL;
echo MyClass4::$static_variable . " (MyClass4)" . PHP_EOL;
// => 初期値 (MyClass1)
// => 初期値 (MyClass2)
// => MyClass3の初期値 (MyClass3)
// => MyClass3の初期値 (MyClass4)

MyClass1::$static_variable = "MyClass1から値を変更";
echo MyClass1::$static_variable . " (MyClass1)" . PHP_EOL;
echo MyClass2::$static_variable . " (MyClass2)" . PHP_EOL;
echo MyClass3::$static_variable . " (MyClass3)" . PHP_EOL;
echo MyClass4::$static_variable . " (MyClass4)" . PHP_EOL;
// => MyClass1から値を変更 (MyClass1)
// => MyClass1から値を変更 (MyClass2)
// => MyClass3の初期値 (MyClass3)
// => MyClass3の初期値 (MyClass4)

MyClass3::$static_variable = "MyClass3から値を変更";
echo MyClass1::$static_variable . " (MyClass1)" . PHP_EOL;
echo MyClass2::$static_variable . " (MyClass2)" . PHP_EOL;
echo MyClass3::$static_variable . " (MyClass3)" . PHP_EOL;
echo MyClass4::$static_variable . " (MyClass4)" . PHP_EOL;
// => MyClass1から値を変更 (MyClass1)
// => MyClass1から値を変更 (MyClass2)
// => MyClass3から値を変更 (MyClass3)
// => MyClass3から値を変更 (MyClass4)
```

### staticなメソッド

通常のメソッドは、インスタンスを通して呼び出す必要があります。  
これに対してstaticなメソッドはインスタンスを通さずに、クラス名を使って呼び出すことができます。

```php
<?php

class MyClass {
    public static function introduce() {
        echo "私はMyClassです！";
    }
}

MyClass::introduce();
// => 私はMyClassです！
```

<br />

staticなメソッドは一見通常の関数と同じ用に見えます。  
しかしクラスの中に定義されているため、そのクラスの [アクセス修飾子](#敢えてアクセス制限をかける-アクセス修飾子) を気にせず、自由にアクセスすることができます。

```php
<?php

class MyClass {
    protected $data = null;

    public static function fromData($data) {
        $instance = new self();

        // fromData() はMyClassの中に定義されているため、protectedなプロパティであるdataにアクセスできる
        $instance->data = $data;

        return $instance;
    }

    public function display() {
        var_dump($this->data);
    }
}

$instance = MyClass::fromData('Hello, World!');
$instance->display();
// => string(13) "Hello, World!"


function makeMyClass($data) {
    $instance = new MyClass();

    // public なプロパティではないため、外部からアクセスできない
    $instance->data = $data;    // Uncaught Error: Cannot access protected property MyClass::$data

    return $instance;
}

$instance2 = makeMyClass('Hello, World!');  // エラー
```

<br />

通常のメソッドと同様に、staticなメソッドもオーバーライドすることができます。

```php
<?php

class BaseClass {
    public statuc function introduce() {
        echo "私はBaseClassです！";
    }
}

class DerivedClass extends BaseClass {
    public static function introduce() {
        echo "私はDerivedClassです！";
    }
}

BaseClass::introduce();
// => 私はBaseClassです！

DerivedClass::introduce();
// => 私はDerivedClassです！
```

### どのメソッドを呼び出すかを指定する (self, static, parent)

当然ではありますが、staticなメソッドから別のstaticなメソッドを呼び出すこともできます。

```php
<?php

class BaseClass {
    public static function introduce() {
        echo "私はBaseClassです！" . PHP_EOL;
    }

    public static function introduceTwice() {
        BaseClass::introduce();
        BaseClass::introduce();
    }
}

BaseClass::introduceTwice();
// => 私はBaseClassです！
//    私はBaseClassです！
```

<br />

今のコードでは、`introduceTwice()` メソッドは、`BaseClass::introduce()` を呼び出しています。

ところで、この`BaseClass`が継承されて、`DerivedClass`が作られたとします。  
そのときには自己紹介をする`introduce()` メソッドは、きっとオーバーライドされるでしょう。

```php collapse={4-11} add={14-18} add={"意図した動作ではない？":25-30}
<?php

class BaseClass {
    public static function introduce() {
        echo "私はBaseClassです！" . PHP_EOL;
    }

    public static function introduceTwice() {
        BaseClass::introduce();
        BaseClass::introduce();
    }
}

class DerivedClass extends BaseClass {
    public static function introduce() {
        echo "私はDerivedClassです！" . PHP_EOL;
    }
}

BaseClass::introduce();
// => 私はBaseClassです！
BaseClass::introduceTwice();
// => 私はBaseClassです！
//    私はBaseClassです！

DerivedClass::introduce();
// => 私はDerivedClassです！
DerivedClass::introduceTwice();
// => 私はBaseClassです！
//    私はBaseClassです！
```

<br />

この状態では、まだ問題が残っています。

`introduceTwice()` メソッドは`BaseClass::introduce()` を呼び出しているため、`DerivedClass` から呼び出したときも`BaseClass::introduce()` が呼び出されてしまいます。

これを、`DerivedClass::introduce()` を呼び出すようにするにはどうしたらいいでしょうか？  
愚直に、`introduceTwice()` メソッドをオーバーライドして、`DerivedClass::introduce()` を呼び出すようにするしかないのでしょうか？

```php collapse={3-13,25-29} add={19-22} {"これも1つの解決策":30-35}
<?php

class BaseClass {
    public static function introduce() {
        echo "私はBaseClassです！" . PHP_EOL;
    }

    public static function introduceTwice() {
        BaseClass::introduce();
        BaseClass::introduce();
    }
}

class DerivedClass extends BaseClass {
    public static function introduce() {
        echo "私はDerivedClassです！" . PHP_EOL;
    }

    public static function introduceTwice() {
        DerivedClass::introduce();
        DerivedClass::introduce();
    }
}

BaseClass::introduce();
// => 私はBaseClassです！
BaseClass::introduceTwice();
// => 私はBaseClassです！
//    私はBaseClassです！

DerivedClass::introduce();
// => 私はDerivedClassです！
DerivedClass::introduceTwice();
// => 私はDerivedClassです！
//    私はDerivedClassです！
```

<br />

今回の問題の根本は、継承されたクラスからメソッドを呼ぶときに、どの時点のメソッドを呼び出すかを指定する手段を知らない状態だったことにあります。  
これを解決するためのキーワードが、`self`、`static`、`parent` です。

```php "parent" "self" /static(?=::)/ add={8-12,14-17,30-33}
<?php

class BaseClass {
    public static function introduce() {
        echo "私はBaseClassです！" . PHP_EOL;
    }

    public static function introduceSelf() {
        // selfは自分自身であるBaseClassを指す
        // introduceSelf() がオーバーライドされない限り、BaseClass::introduce() が呼び出される
        self::introduce();
    }

    public static function introduceStatic() {
        // 継承先でintroduce() がオーバーライドされている場合、そちらが呼び出される
        static::introduce();
    }

    public static function introduceTwice() {
        BaseClass::introduce();
        BaseClass::introduce();
    }
}

class DerivedClass extends BaseClass {
    public static function introduce() {
        echo "私はDerivedClassです！" . PHP_EOL;
    }

    public static function introduceParent() {
        // 親クラスであるBaseClassのintroduce() を呼び出す
        parent::introduce();
    }
}

BaseClass::introduce();
// => 私はBaseClassです！
BaseClass::introduceSelf();
// => 私はBaseClassです！
BaseClass::introduceStatic();
// => 私はBaseClassです！

DerivedClass::introduce();
// => 私はDerivedClassです！
DerivedClass::introduceSelf();  // オーバーライドされていないため、BaseClass::introduce() が呼び出される
// => 私はBaseClassです！
DerivedClass::introduceStatic();
// => 私はDerivedClassです！

DerivedClass::introduceParent();
// => 私はBaseClassです！
```

<br />

つまり意図した`introduceTwicw()` メソッドを定義するためには、`self` ではなく `static` を使う必要があったということになります。

```php del={9-10} add={11-12}
<?php

class BaseClass {
    public static function introduce() {
        echo "私はBaseClassです！" . PHP_EOL;
    }

    public static function introduceTwice() {
        BaseClass::introduce();
        BaseClass::introduce();
        static::introduce();
        static::introduce();
    }
}

class DerivedClass extends BaseClass {
    public static function introduce() {
        echo "私はDerivedClassです！" . PHP_EOL;
    }
}

BaseClass::introduce();
// => 私はBaseClassです！
BaseClass::introduceTwice();
// => 私はBaseClassです！
//    私はBaseClassです！

DerivedClass::introduce();
// => 私はDerivedClassです！
DerivedClass::introduceTwice();
// => 私はDerivedClassです！
//    私はDerivedClassです！
```

オーバーライドが想定されるクラスのメソッドから別のstaticなメソッドを呼び出すときには、  
`static` を使って継承先を明示的に呼び出すようにすることが、意図した動作を実現するためのポイントになります。

## よく見るコード例

### 初期化のための静的メソッド

初期値となるデータを渡すと、クラスのインスタンスを作るような静的メソッド

```php {9-22}
<?php

class FormField {
    protected $name;
    protected $email;
    protected $gender;
    protected $message;

    public static function fromValues($values) {
        if (!is_array($values)) {
            throw new Exception("values must be an array");
        }

        $instance = new FormField();
        $instance->name = $values["name"];
        $instance->email = $values["email"];
        $instance->gender = $values["gender"];
        $instance->message = $values["message"];

        return $instance;
    }
}

// $_POSTの中身をもとに、FormFieldクラスのインスタンスを作る
$formField = FormField::fromValues($_POST);
```

### 別の型に変換するためのメソッド

入力フォームの情報を、そのままユーザー情報に変換する処理

```php {3-24, 46-57}
<?php

class User {
    protected $id = null;
    protected $name;
    protected $email;
    protected $gender;

    public static function fromValues($values) {
        if (!is_array($values)) {
            throw new Exception("values must be an array");
        }

        $instance = new User();

        // 代入の処理は省略

        return $instance;
    }

    public function save() {
        // データベースに保存する処理
    }
}

class FormField {
    protected $name;
    protected $email;
    protected $gender;
    protected $message;

    public static function fromValues($values) {
        if (!is_array($values)) {
            throw new Exception("values must be an array");
        }

        $instance = new FormField();
        $instance->name = $values["name"];
        $instance->email = $values["email"];
        $instance->gender = $values["gender"];
        $instance->message = $values["message"];

        return $instance;
    }

    public function toUser() {
        $values = [
            "name" => $this->name,
            "gender" => $this->gender,
            "email" => $this->email,
        ];

        $user = new User();
        $user->fromValues($values);

        return $user;
    }
}

// $_POSTの中身をもとに、FormFieldクラスのインスタンスを作る
$formField = FormField::fromValues($_POST);

// FormFieldクラスが持つ情報で、Userクラスのインスタンスを作る
$user = $formField->toUser();
$user->save();
```
