【PHP】オブジェクト指向の近道 - staticと転送コール

# staticプロパティとstaticメソッド
前回までは、インスタンスを生成してプロパティとメソッドを使いました。インスタンスのプロパティとメソッドとは別に、クラスのプロパティとメソッドにアクセスすることもできます。これらを`static`プロパティ（静的プロパティ）と`static`メソッド（静的メソッド、クラスメソッド）とよびます。`static`プロパティと`static`メソッドはクラスごとにあり、プロパティやメソッドのようにインスタンスごとにはありません。

例えば、生成したインスタンス数`$number`をもちたい時に`static`プロパティを使います。生成したインスタンス数はクラスごとの値ですので、`static`プロパティに値をセットするのがよいです。また、`static`プロパティにアクセスするだけのメソッド`getNumber()`は、インスタンスにある必要がないので`static`メソッドを使うのがよいです。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2962814/e2924876-4bfe-8bcd-c1d4-b0528df0ca5a.png)

`Person3`のクラス定義です。`static`をつけるだけで、`static`プロパティ`$number`と`static`メソッド`getNumber()`を定義できます。

```php
<?php

class Person
{
    private $name;

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

    public function getName()
    {
        return $this->name;
    }
}

class Person3 extends Person
{
    private static $number = 0;

    public function __construct($name)
    {
        parent::__construct($name);
        ++self::$number;
    }

    public static function getNumber()
    {
        return self::$number;
    }
}

$person_a = new Person3('suzuki');
$person_b = new Person3('tanaka');

$person_number = Person3::getNumber();

var_dump($person_number);
```

:::note info
staticプロパティとstaticメソッドはクラスごとにある
:::

# 転送コール
子クラスから親クラスのメソッドをコールしたい時は`parent::`を使います。`self::`や`parent::`を転送コールとよび、クラス定義でのみ使えます。`parent::`を使用して親クラスのメソッドを呼び出し、その後に処理を追加することで、子クラスのメソッドに追加の処理を挿入することができます。親クラスのメソッドを利用できるため、子クラスのメソッドでは変更分だけをコーディングするだけですみます。

```php:親クラスを転送コール
        parent::__construct($name);
```

クラス内では`self::`で自クラスの`static`プロパティと`static`メソッドにアクセスします。

```php:staticプロパティにアクセス
        ++self::$number;
```

クラス外からは`Person3::getNumber()`のように、クラス名を指定して`static`メソッドにアクセスします。

```php:クラス外からstaticメソッドをコール
$person_number = Person3::getNumber();
```

```sh:実行結果
int(2)
```

:::note info
インスタンス内は`$this`、クラス内は`self::`、親クラスは`parent::`でアクセス
:::

:::note alert
`static`メソッドからインスタンスのプロパティにはアクセスできません。
:::
クラスから複数個のインスタンスが生成されるため、どのプロパティにアクセスするかを特定できないからです。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2962814/b440f76e-9917-0934-f46e-b060305fb22b.png)

# 遅延静的束縛
PHPの中でも最強クラスの攻撃力がありそうな、遅延静的束縛でこの記事をしめたいと思います。転送コール`parent::` `self::`で対応できないケースに、`static::`で転送コールする時に遅延静的束縛がおこります。

親クラス`Person`では親クラスのプロパティ`$age`を、子クラス`Person2`では子クラスのプロパティ`$age`にアクセスしたい時に、転送コール`static::`を使います。転送コール`self::$age`は常に`Person`の`$age`にアクセスしますし、`Person`に親クラスがないため、転送コール`parent::$age`は使えません。

![](https://storage.googleapis.com/zenn-user-upload/40f6a4b68873-20221115.png)

```php:sample7-1.php
<?php

class Person
{
    protected static $age = 26;

    public static function getAge()
    {
        return static::$age;
    }
}

class Person2 extends Person
{
    protected static $age = 28;
}

$person_age = Person::getAge();
$person2_age = Person2::getAge();

var_dump($person_age);
var_dump($person2_age);
```

`static`は直近の非転送コール`Person::` `Person2::`を保存して、そのクラスに動的に転送（Late Binding）します。

```php:実行結果
int(26)
int(28)
```

:::note info
`static::`は、いい感じの転送コール
:::

# オブジェクト指向の近道（全５記事）
1. [なぜオブジェクト指向が必要か？](https://qiita.com/hyada/items/a50586ff3579c078d2b6)
2. [クラスとインスタンス](https://qiita.com/hyada/items/e86af8baf136ac27d9ae)
3. [継承とトレイト](https://qiita.com/hyada/items/ad9ecc8ddc75404b504e)
4. [アクセス権とカプセル化](https://qiita.com/hyada/items/866ecd191bb25ef5c368)
5. [staticと転送コール](https://qiita.com/hyada/items/238fdda17a6704e4c613)