Laravel・PHP入門

PHPer初心者

【PHP】静的と動的メソッドとは

先輩が初心者むけにあまりに分かり易すぎる解説をしてくださったので
忘れないうちに。と自分の解釈もメモ。

PHPでよくみるstaticですが、ずっと個人的にも謎でした。

サンプル

まずは例から。かなり簡易化して先輩がかいてくださいました。

今回は計算機を例にします。
計算機クラスは、誰が実行するか、実行者というプロパティを持っています。
そしてこの計算機を使おうとするたびに、実行者を教えてあげる必要があります。

早速使ってみます。

class 計算機
{
   private 実行者;

   private function __construnct(実行者)
   {
        $this->実行者 = 実行者;
   }

   public static function 足す($a, $b) 
   {
        return $a + $b;
   }

   public function 掛ける(a,b)
   {
         if ($this->実行者 == 田中さん) {
             return $a + $b; // 田中さんは掛け算が苦手なので、足した数字を返してしまいます
         }
         return $a * $b;
    }
 }
静的メソッド足し算

足し算は簡単で全員計算することができます。
実際にこのクラスを使ってみると、、

田中さんの答え = (new 計算機(田中))->足す(1,3) // 4
佐藤さんの答え = (new 計算機(佐藤))->足す(1,3) // 4
山田さんの答え = (new 計算機(山田))->足す(1,3) // 4

実行者、つまりはインスタンスにより変わらないですね。
なので、この「足す」というメソッドは静的メソッドとして定義することができます。

計算機::足す(1,3) //4

実行者にも依存しない、インスタンスにも依存しないので、
実態のないインスタンス化していない状態で、このメソッドを呼び出すことができるのですね。
今回結果を変えることができるのは、引数だけですね。

動的メソッド掛け算

さて、次に掛け算をしてみます。
上に書いている通り、田中さんは掛け算が苦手で、ついつい足してしまいます。

田中さんの答え = (new 計算機(田中))->掛ける(1,3) // 4
佐藤さんの答え = (new 計算機(佐藤))->掛ける(1,3) // 3
山田さんの答え = (new 計算機(山田))->掛ける(1,3) // 3
)

佐藤さんは掛け算が苦手で、ついつい足してしまいました。
インスタンス、実行者により結果が変わってしまいました。
このため、この「掛ける」メソッドは動的にしか定義できません。

計算機::掛ける(1,3) // エラー(誰が実行するかで結果が変わるのに実行者がわからないから、結果が出せませんよ!

静的メソッドの書き方をしても、エラーが出ます。



イメージ補足

個人的なイメージだと、
そのクラスが保持するプロパティがそのメソッドの結果に

ざっくり比較するとこんな感じです。

静的メソッド:インスタンスに影響を受けない
動的メソッド:インスタンスに依存する

静的メソッド:PostModel::join('comments', 'posts.id', '=', 'comments.post_id');
動的メソッド:(new PostModel(1))->comments();

例えば、joinはpostsテーブルに全てのcommentsテーブルを結合しているだけなので
idが1のPostでも、2のPostでも、結果は変わらないですね。

ですが、PostModelがidが1のPostModelをインスタンス化した時に、
リレーションで定義しているcommentsメソッドを呼び出すと
idが1のPostに紐づくcommentsが全て取得できます。
しかし、これはidが2のPostに紐づくcommentsと一緒ではないですよね。

これが、インスタンスに依存するかしないか、という話です。


わかりやすくいうと、そのメソッドのなかで、メソッドを定義しているクラスのプロパティが
影響しているかどうかで判断できますね。
クエリビルだとかだと、発行したクエリの中に、クラスのプロパティが含まれていれば動的とわかりますし、
引数からしか影響を受けていなければ静的です。

それでは、Laravel、Modelのwhereメソッドは静的・動的どちらでしょうか?




正解は静的です。where句の中身にプロパティを含めていない限り、
発行するクエリにプロパティは影響しないためです。

なぜ静的・動的メソッドを使うのか

クラスは、いろんな箇所で実体化して使うことが多いですよね。
保守の時も、いろんな箇所で改修が入ります。

仮に、staticと定義せず皆があの「足し算」を使っていたらどうでしょう?
皆、足して返してくれると思っています。
ですが、ある開発者が「あ、田中さん足し算じゃなくて引き算してしまうことにしよう」と
足し算でもif文で実行者による分岐をいれたとします。

staticにしていると、この段階でエラーが出ますが、むやみに動的にしている場合、エラーが出ません。
いろんな箇所で足してくれるものと思っているのに、
結果が変わってしまうと皆困ってしまいますし、バグの元になります。

そのため、結果がプロパティに依存しない場合はstaticを使うのも一つの良い手なんだと思います。


以上