[PHP]staticメソッドとstatic::に関するメモ

##はじめに
この記事はプログラミング初学者による備忘録用の記事であり、また、少しでも他の初学者のお役に立てればと思い書いています。

今回は、staticメソッドとstatic::は本来別物ですが、staticという共通文字に騙され同じような挙動をすると誤解し、スコープ定義演算子を用いたメソッドの呼び出し方で悩まされたので、再度staticメソッドとstatic::について復習したことをまとめておきたいと思います。

間違いなどがございましたら、ご指摘のほどよろしくお願い致します。


##staticメソッドとは

>
クラスプロパティもしくはメソッドを static として宣言することで、 クラスのインスタンス化の必要なしにアクセスすることができます。 static として宣言されたプロパティやメソッドは、 インスタンス化されたオブジェクトの内部からも静的にコールできます。
static メソッドは、オブジェクトのインスタンスを生成せずに コールすることができるので、疑似変数 $this は、 static として宣言されたメソッドの内部から利用することはできません。
``引用:``[PHP公式ドキュメント staticキーワード](https://www.php.net/manual/ja/language.oop5.static.php)

staticメソッドの例

```php
<?php
class Test {
    public static function sampleMethod() {
        // ...
    }
}

Test::sampleMethod();
$classname = 'Test';
$classname::sampleMethod();
?>
```




##staticでないメソッドを静的にコールしてはいけない
>
staticでないメソッドを静的にコールすると、Error がスローされます。
PHP 8.0.0 より前のバージョンでは、 static でないメソッドを静的にコールすることが非推奨になっており、 E_DEPRECATED レベルの警告が発生していました。
``引用:``[PHP公式ドキュメント staticキーワード](https://www.php.net/manual/ja/language.oop5.static.php)

``例:``

```php
//例　staticメソッドとは
class A
{
    public static function aa()
    {
    }
}

//例 非推奨な呼び出し方
class B
{
    public static function bb() //staticメソッド
    {
    }

    public function cc() //staticではないメソッド
    {
    }
}

//上記のようなクラスBの場合でインスタンス化せずに直接staticではないメソッドを呼ぶことが非推奨となっている

//staticではないメソッド正しい呼び出し方
$b = new B();
$b->cc();

//非推奨
B::cc();

//staticメソッドに対してはok
B::bb();
```

##スコープ定義演算子 (::)とは
>
スコープ定義演算子 (またの名を Paamayim Nekudotayim)、 平たく言うと「ダブルコロン」は、トークンのひとつです。 static, 定数 およびオーバーライドされたクラスのプロパティやメソッドにアクセスすることができます。
これらの要素をクラス定義の外から参照する際には、 クラスの名前を使用してください。
変数を用いてクラスを参照することも可能です。 変数の値に (self や parent、 static といった) キーワードを指定することはできません。
``引用:``[PHP 公式ドキュメント スコープ定義演算子 (::)](https://www.php.net/manual/ja/language.oop5.paamayim-nekudotayim.php)

``例:クラス定義の外からスコープ定義演算子を使う``

```php
<?php
class SampleClass {
    const CONST_VALUE = 'A constant value';
}

$classname = 'SampleClass';
echo $classname::CONST_VALUE;

echo SampleClass::CONST_VALUE;
?>
```

``・クラス定義の内部で使われるスコープ定義演算子``

クラス定義の内部で使われるスコープ定義演算子は3つ存在し、``self`` と ``parent``、 ``static`` がクラス定義の内部からプロパティまたはメソッドにアクセスする際に使用されます。

``例:クラス定義の内部でスコープ定義演算子を使う``

```php
<?php
//親クラス
class BaseClass {
    const CONST_VALUE = 'Base constant value';
}

//継承先クラス
class OtherClass extends BaseClass
{
 public static $my_static = 'static var';

 public static function doubleColon() {
  echo parent::CONST_VALUE . "\n";// parent::で親クラスの定数をコール
  echo self::$my_static . "\n";// 継承先クラス自身のstaticプロパティをコール
   }
}

$classname = 'OtherClass';
$classname::doubleColon();
OtherClass::doubleColon();


//親クラスのメソッドをコールする例
class BaseClass
{
    protected function sample() {
        echo "BaseClass::sample()\n";
    }
}

class OtherClass extends BaseClass
{
    // 親の定義をオーバーライドします
    public function sample()
    {
        // オーバーライド状態でも親の関数をコールできます
        parent::sample();
        echo "OtherClass::sample()\n";
    }
}

$class = new OtherClass();
$class->sample();
?>
```


##::(スコープ定義演算子)を用いてメソッドを呼び出す = 静的にコールする だけではない
まず、静的にコールするとは、「静的にコールする」＝「クラスオブジェクト(インスタンス化)を作らずに直接メソッドを呼ぶ」という認識で良いと思います。

しかし、::(スコープ定義演算子)を用いてメソッドを呼び出す = クラスオブジェクト(インスタンス化)を作らずに直接メソッドを呼び出す、という認識の場合、実は**スコープ定義演算子を用いてメソッドを呼び出す（[クラス名]::、self::、parent::、static::）」のうち、**``「static::」のみ``**特殊な挙動をする**為、混乱が生じる場合があります。

``・static::の特殊な挙動とは``
PHPの公式ドキュメントによると、下記のように記されています。
>
 静的メソッドの場合、これは明示的に指定されたクラス (通常は :: 演算子の左側に書かれたもの) となります。静的メソッド以外の場合は、そのオブジェクトのクラスとなります。
``引用:``[PHP公式ドキュメント 遅延静的束縛](https://www.php.net/manual/ja/language.oop5.late-static-bindings.php)

まとめると下記のようになります。

| スコープ定義演算子を用いたメソッドの呼び出し方 | 特徴 |
|:-:|:-|
|static::|・実行時に最初にコールされたクラスを参照<br>・呼出し先メソッドが静的or動的で使用可能<br>・呼出し先メソッドの定義(静的or動的)によって、静的なコールか動的なコールかが決まる|
|クラス名::|・呼出し先メソッドが静的メソッド及び、定数へのアクセスを実行する|
|self::|・自クラスのプロパティ、及びメソッドへの静的アクセスを実行する|
|parent::|・親クラスのプロパティやメソッドへのアクセスを実行する|

##おわりに
staticメソッドとstatic::は別物であるということを念頭に置いて、スコープ定義演算子やstaticメソッドを使っていきたいと思います。

##参考文献
[PHP 公式ドキュメント staticキーワード](https://www.php.net/manual/ja/language.oop5.static.php)
[PHP 公式ドキュメント 遅延静的束縛](https://www.php.net/manual/ja/language.oop5.late-static-bindings.php)