PHPでは、JavaやC#のようなブログラミング言語同様にstaticを使用して静的メンバを指定することができます。
この記事では、
・PHPのクラスの構造
・静的なメンバとstatic
という基本的な内容から、
・staticを使う際の注意点
で、気をつけなくてはならない点について言及します。
今回はそんなstaticを使用する方法について、わかりやすく解説します!
PHPのクラスの構造
staticについて説明する前に、オブジェクト指向言語としてのPHPについて軽く復習しておきましょう。
class宣言
まず、クラスと呼ばれる型の宣言を行います。
class (クラス名){ … }
クラスは動作を表すメソッドと、データを表すプロパティからなります。
このクラスをもとに、インスタンスを生成します。書式は以下の通りです。
(インスタンス名) = new (クラス名)
インスタンスを生成したら
(インスタンス名)->(プロパティ名) (インスタンス名)->(メソッド名)
といった形でプロパティ、ならびにメソッドにアクセスします。
では実際にサンプルを見てみましょう。
<?php // Studentというクラス(型)を宣言。クラスの1文字目は大文字 class Student { // プロパティ public $name; public $age; // メソッド function showData(){ echo $this->name." is ".$this->age." years old.<br/>"; } } //クラスStudentのインスタンスを作成 $tanaka = new Student; //(インスタンス名)->(プロパティ名) ※プロパティの"$"はつけない //tanakaというインスタンスのプロパティ$nameに、tanakaを挿入。 $tanaka->name = "tanaka"; $tanaka->age = 12; echo $tanaka->name."<br/>"; echo $tanaka->age."<br/>"; $tanaka->showData();
tanaka 12 tanaka is 12 years old.
静的メンバと動的メンバ
通常クラスへアクセスするには、new演算子を使用してクラスのインスタンスを生成する必要があります。
しかし、クラスのインスタンスを生成しなくても、クラスのメンバにアクセス可能なメンバのことを静的(static)メンバと呼びます。
言語によってはクラスメンバと言う場合もあります。その際、メソッドの場合はクラスメソッド、プロパティをクラス変数などと呼びます。
静的(static)メンバを使用するためには、変数や関数、メソッドの先頭にstaticを記述する必要があります。
staticな変数を定義する場合、以下のように記述します。
クラス名{ static $変数名 = 値; //処理 }
また、staticの前にはpublic、privateなどのアクセス権を指定することができます。
アクセス権を指定すれば、staticのメンバがどこからでもアクセスできるようになったり、逆にアクセスを限定するようなことが可能となります。
public static $変数名 = 値;
なおPHPのclassのさまざまな処理については、以下の記事にまとめていますので、ぜひ参考にしてください。
静的なメンバとstatic
ここでは静的(static)なメンバの使用方法について紹介します。
static変数の使い方
通常クラスの変数は外部から参照するためには、クラスのインスタンスを生成してクラスの関数や変数などにアクセスします。
しかし、前述したようにstaticを使用すれば、クラスのインスタンスを生成しないで直接クラスのメンバにアクセスすることができます。
これは、staticを指定した変数や関数・メソッドはクラスそのものに属することなり、インスタンスとの関わりがなくなるからです。
以下にstaticな変数を定義して、クラス外からインスタンスを生成しないで参照する方法を記述します。
<?php class Foo { //静的変数を作成する public static $val = 10; } //静的変数を参照する $value = Foo::$val; echo $value; ?>
実行結果
10
実行結果のとおり、クラスFooのインスタンスを生成しないで、クラス内の静的メンバにアクセスできることがわかりますね!
staticな変数の活用法として、ローカルな変数では関数内でセットした値は関数の外に出たら値はリセットされてしまいますが、staticな変数を関数内で定義した場合、セットした値は処理が関数外に移っても保持されます。
以下の例では、関数を呼び出すごとにstaticな変数の値をインクリメントしています。
<?php function Foo(){ static $val = 0; echo $val.'<br>'; $val++; } Foo(); Foo(); Foo(); ?>
実行結果
0 1 2
実行結果のとおり、関数を呼び出すごとに値がインクリメントされていることがわかりますね!
これがstaticを指定しないローカルな変数だったら、毎回0が出力されてしまいます。
なお、クラス内で生成したstaticでない通常の変数を静的にアクセスしようとすると、エラーが発生しますので注意しましょう。
逆に静的なメンバは、クラスのインスタンスから参照するときに使用する矢印演算子->によるアクセスはできません。
staticな配列の指定方法
配列をstaticなメンバとして定義することも可能です。
以下に配列をstaticとして定義して、クラス外から参照する方法を記述します。
<?php class fruitsClass{ //静的な配列を定義する public static $fruits_array = ['apple', 'orange', 'melon', 'banana', 'pineapple']; } //静的な配列を参照する $array = fruitsClass::$fruits_array; foreach($array as $value){ echo $value; echo '<br>'; } ?>
実行結果
apple orange melon banana pineapple
実行結果のとおり、配列もインスタンス化しないでstaticなメンバとしてアクセスできることがわかりましたね。
配列もstatic修飾子を使用することにより、ローカルから外に処理が移行しても、値はそのまま保持されますので、処理によって使い分けるとよいでしょう。
なお、変数や配列などをクラス内で定数化したい場合はconstを使用します。
constの使い方については、以下の記事で詳しく解説しています!
staticなメソッド
staticを使用してメソッドを静的にアクセスすることもできます。
以下にstaticなメソッドを定義して、クラス外からアクセスする方法を記述します。
<?php class SamuraiClass { //静的なメソッドを使用する public static function SamuraiMethod($val) { $val = 'Samurai '.$val; return $val; } } //静的なメソッドを参照する $name = SamuraiClass::SamuraiMethod('Engineer'); echo $name; ?>
実行結果
Samurai Engineer
このようにstaticを使用すれば、気軽に関数やメソッドにアクセスすることが可能となります。
staticを使う際の注意点
このように便利なstaticですが、使うときには注意しなくてはならない点がいくつかあります。
以下、それらについて説明していきましょう。
動的メンバと静的メンバの関係性
静的なメソッドおよび静的なプロパティは、動的なメソッド・プロパティにアクセスできます。
しかし、動的なメソッド・プロパティから静的メソッド、プロパティにアクセスすることは出来ません。
例えば、以下のようなクラスはエラーになります。
<?php class Foo{ public static $n = "static"; public $m = "instance"; // 静的メソッドから動的プロパティを呼び出す public static function show(){ echo Foo::$n; // 静的プロパティ echo $this->m; // 動的プロパティ } } Foo::show();
Fatal static Fatal error: Using $this when not in object context in /home/ubuntu/workspace/Err.php on line 9
動的プロパティはインスタンスを作らなければ使えません。
継承と静的メソッド
また、継承の際にも気をつけなくてはならない点があります。
インスタンスメソッドにはオーバーライドと言う概念があります。
これは、サブクラスの中でスーパークラスのメソッドを上書きできるというものですが、静的メソッドの場合はこれが当てはまりません。
<?php // スーパークラス class MyParent { static function foo() { return "Super"; } static function bar() { echo self::foo() ."<br/>"; } } // サブクラス class MyChild extends MyParent { // スーパーのメソッドをオーバーライド static function foo() { return "Sub"; } } MyParent::bar(); # <= "Super"と出力してほしい MyChild::bar(); # <= "Sub"と出力してほしい
Super Super
サブクラスでオーバーライドしたfoo()が呼ばれず、スーパークラスのfoo()が呼ばれています。
selfは、self::が記載されたクラス内のプロパティやメソッドを呼び出すのに使われます。
したがって、スーパークラス内では、”Parent”が、サブクラス内では”Sub”が取得されるはずです。
ところが実際は、サブクラスからスーパークラスの静的メソッドを呼び出した場合、そのメソッドは親クラスのコンテキストで実行されてしまいます。
そのため、サブクラスから呼び出したスーパークラスのstaticなメソッド内でサブクラスでオーバーライドされたメソッドを呼び出そうとしても、親クラスで定義されたものが呼ばれる結果になります。
このように、staticを使う際には意外な落とし穴がありますので、気をつけてください。
なお、PHPの継承については、以下の記事で詳しく説明しています。興味のある方はこちらもあわせてみてください。
まとめ
ここでは静的メンバの意味やstaticを使用した変数やクラス、メソッド、配列などの使い方について解説しました。
静的メンバはクラスをインスタンス化しなくても、簡単にクラスのメンバにアクセスして、値を参照できたりすることが可能ですので、この機会にぜひ覚えておきましょう。
もしstaticの使い方忘れてしまったら、この記事を思い出してくださいね。