PHPやLaravelを使っていると、静的(スタティック)メソッドや動的(インスタンス)メソッドといった言葉が出てくる。
この2つは、呼び出し方も使い方も大きく異なる。違いを理解していないと混乱しエラーなどにも繋がってしまうため、しっかりと理解しておく必要がある。
この重要な静的(スタティック)メソッドと動的(インスタンス)メソッドの違いについて実例を用いて解説します。
静的(スタティック)メソッドとは何か?
静的(static)メソッドとは、クラスの中で「static」を記述して作成した関数の中のメソッドのこと。呼び出しはクラスに対して行い、どこで呼び出しても同じ処理を行う。
//クラスの中で定義
[アクセス権限] static function メソッド名(){
//処理
};
呼び名が以下のように色々とあってややこしいがどれも同じになる。
- 静的メソッド
- スタティックメソッド
- クラスメソッド
- staticメソッド
staticは静的という意味で、どのインスタンスでも共通のメソッドやプロパティを呼び出せる処理を表す。
インスタンスではなく、クラスに対して使うので「クラスメソッド」という名称もよく使う。
動的(インスタンス)メソッドとは何か?
動的(インスタンス)メソッドとは、静的メソッドとは異なり、インスタンスに対して呼び出し、インスタンス毎に固有の結果を返す。
関数を定義する時は「static」を付けない。
//クラスの中で定義
[アクセス権限] function メソッド名(){
//処理
};
こちらも以下のように呼び名が色々とあるが、どれも同じ。
- 動的メソッド
- インスタンスメソッド
- instanceメソッド
- ダイナミックメソッド
- dynamicメソッド
インスタンスの中で使うメソッドなので、インスタンスメソッドというのが一般的。
静的(スタティック)メソッドと動的(インスタンス)メソッドの違い
静的(スタティック)メソッドと動的(インスタンス)メソッドを定義する時の違いは、(1)定義方法の違いと、(2)実際に使う時の違いがある。
(1)定義する時の違いは「static」をつけるか付けないか、と「アクセス権限」の必要性。
メソッド | static | アクセス権限 |
---|---|---|
静的(スタティック) | 必須 | 必須 |
動的(インスタンス) | 不要 | なくてもいい(ない場合はpublic扱い) |
アクセス権限は、権限の強い順から、 private > protected > public (=記載なし) となる。
- private :定義したクラス内のみ
- protected :継承クラス(子クラス)からもアクセス可能
- public :クラスの外からアクセス可能
- 記載なし(function) :publicと同じ
- 記載なし(プロパティをvarで定義) :publicと同じ
(2)実際に使う時の違いは違いは大きく2つ。
- 呼び出し方の違い
- アクセスできるプロパティの違い
個別に確認した方がわかりやすいため、まずは呼び出し方の違いから解説します。
メソッドの呼び出し方の違い
呼び出し方の違いで重要なのは2点。
- 呼び出しの対象が何か?
- 呼び出し方法はどうするか?
まとめると以下のようになる。
メソッド | 対象 | 呼び出し方法 |
---|---|---|
静的(スタティック) | クラス | クラス::メソッド名 |
動的(インスタンス) | インスタンス | インスタンス->メソッド名() |
動的(インスタンス)メソッドを「クラス名::」で呼び出そうとするとエラーになる。(静的(スタティック)メソッドは、「->」でも呼び出せる)
実際にそれぞれを定義して呼び出した例は以下になる。
<?php
class TestClass{
public static function testStatic(){
echo "静的(スタティック)メソッド";
}
public function testInstance(){
echo "動的(インスタンス)メソッド";
}
}
//「クラス::」での呼び出し
TestClass::testStatic(); //出力結果: 静的(スタティック)メソッド:
TestClass::testInstance(); //出力結果: エラー:
//「オブジェクト->」での呼び出し
$obj = new TestClass;
$obj->testInstance(); //出力結果: 動的(インスタンス)メソッド:
$obj->testStatic(); //出力結果: 静的(スタティック)メソッド:
$obj::testStatic(); //出力結果: 静的(スタティック)メソッド:
$obj::testInstance(); //出力結果: エラー:
?>
TestClassというクラスを作成し、testStaticメソッドと、testInstanceメソッドを定義している。
動的(インスタンス)メソッドを「クラス名::」で呼び出した時のエラーは以下。
PHP Fatal error: Uncaught Error: Non-static method TestClass::testInstance() cannot be called statically in /workspace/Main.php:17
スタティックじゃないから、スタティックとして呼び出せないという内容。
インスタンス化したオブジェクトからメソッドを呼び出す場合は、「->」でインスタンスメソッドとクラスメソッドの両方を呼び出すことができる。
インスタンスに対して「->」や「::」を使って静的メソッドを呼びだすこともできるが、明示的かつ混乱防止のために、以下のルールに沿うことを推奨。
メソッド | 対象 | 呼び出し方法 |
---|---|---|
静的(スタティック) | クラス | クラス::メソッド名() |
動的(インスタンス) | インスタンス | インスタンス->メソッド名() |
アクセスできるプロパティの違い
続いて、静的(スタティック)メソッドと動的(インスタンス)メソッドのアクセスできるプロパティの違いについて。
プロパティとはクラスの中で定義できる特別な変数のことで、これにも、静的(スタティック)プロパティと、動的(インスタンス/クラス)プロパティの2種類がある。
基本的にはメソッド同じ。クラス内で呼び出す時は、静的(スタティック)プロパティは「self::$」を、動的(インスタンス/クラス)プロパティは「$this->」を使う。
プロパティ | 対象 | 呼び出し方法 | クラス内での呼び出し |
---|---|---|---|
静的(スタティック) | クラス | クラス::プロパティ名 | self::$プロパティ名 |
動的(インスタンス) | インスタンス | インスタンス->プロパティ名 | $this->プロパティ名 |
注意点は、selfでプロパティを呼び出す時は、変数名に$をつけるが、インスタンスプロパティを呼び出す時は、$thisの後に$を付けない。ということ。
スタティックメソッドは、self::メソッド() だが、スタティックプロパティは self::$プロパティ名 というのも紛らわしいポイント。
なお、「self::」は自分自身のクラスを指し、「$this」は自分自身のクラスをインスタンス化したオブジェクトを指す。
静的(スタティック)メソッドと動的(インスタンス)メソッドの違いの重要なポイントは、静的(スタティック)メソッドの中では「$this」が使えない、つまり、インスタンスプロパティにアクセスできないということ。
メソッド | self:: | $this |
---|---|---|
静的(スタティック) | ○ | × |
動的(インスタンス) | ○ | ○ |
インスタンスの中でクラスにアクセスできるが、クラスの中でインスタンスにはアクセスできない(※インスタンスが存在しない)
静的(スタティック)メソッドからプロパティへのアクセス例
例えば、以下のようにクラスの中に、インスタンスプロパティ($instVar)とスタティックプロパティ($staticVar)を定義して、スタティックメソッドの中でそれぞれ呼び出した例が以下になる。
<?php
class TestClass
{
private $instVar;
private static $staticVar;
public static function staticMethod($val)
{
$this->instVar = $val;
echo $this->instVar;
}
}
TestClass::staticMethod("スタティック"); //出力結果:エラー
?>
TestClass::staticMethod(“スタティック”) を実行すると、スタティックメソッドの中では「$this」が使えないので以下のようなエラーが表示される。
PHP Fatal error: Uncaught Error: Using $this when not in object context in /workspace/Main.php:22
オブジェクトじゃない文脈の中で、$thisは使えないとの内容。
もちろん、「self::」でスタティックプロパティにアクセスすることはできる。
<?php
class TestClass
{
private $instVar;
private static $staticVar;
public static function staticMethod($val)
{
self::$staticVar = $val;
echo self::$staticVar;
}
}
TestClass::staticMethod("スタティック"); //出力結果:スタティック
?>
動的(インスタンス)メソッドからプロパティへのアクセス例
先程と同様に、インスタンスプロパティ($instVar)とスタティックプロパティ($staticVar)を定義して、インスタンスメソッドの中でそれぞれ呼び出した例が以下になる。
<?php
class TestClass
{
private $instVar;
private static $staticVar;
public function instMethod($val)
{
$this->instVar = $val;
echo $this->instVar;
echo "\n"; //改行
self::$staticVar = $val;
echo self::$staticVar;
}
}
$obj = new TestClass;
$obj->instMethod("インスタンス"); //出力結果:スタティック スタティック
?>
インスタンスメソッドからは、スタティックプロパティと、インスタンスプロパティのどちらにもアクセスできる。
まとめ
静的(スタティック)メソッドと動的(インスタンス)メソッドは、その呼び名が複数あったり、定義方法や呼び出し方が微妙に違ったりと、紛らわしいことが多い。
ただし、その中身は、クラスに属しているか、インスタンスに属しているかとう点が大きく異なる。
クラスは大元で、そこからインスタンスが生み出される。このため、クラスのみの場合はインスタンスは存在しない。すなわち、インスタンスメソッドやインスタンスプロパティにはアクセスできない。
一方で、インスタンスは、クラスから生成されているので、大元のスタティックメソッドやスタティックプロパティにもアクセスできる。
この概念的なポイントをしっかり押さえて、あとは使い方「オブジェクト->」「クラス::」や「$this->」や「self::」、を覚えておけば、そこまで混乱することはないかと思います。