static修飾子とは?
状態:-
閲覧数:4,403
投稿日:2010-05-10
更新日:2018-01-18
クラス メンバーが、「クラスのインスタンス」ではなく「クラス」に属していることを宣言する修飾子
・「通常のメンバー」は、「インスタンスメンバー」として「インスタンスオブジェクト」に属している
「クラスメンバー」とは?
・「静的メンバー」と同義語
→ クラスそのものに属する「プロパティ」「メソッド」のこと
静的メンバーの対義語
・通常メンバー
static
・スタティック
・静的
定義
・メソッドやプロパティにstatic キーワード をつけるだけ
・プロパティをstaticにする意味はあまりないので普通はstaticにしない
・呼び出しは、クラス外より行なうので、アクセス修飾子は必ず「public」とする
呼出
・インスタンスオブジェクトを生成せず、直接「クラス名::メソッド名()」で呼び出す
・「通常のメンバー」は、「インスタンスメンバー」として「インスタンスオブジェクト」に属している
「クラスメンバー」とは?
・「静的メンバー」と同義語
→ クラスそのものに属する「プロパティ」「メソッド」のこと
静的メンバーの対義語
・通常メンバー
static
・スタティック
・静的
書式
定義
・メソッドやプロパティにstatic キーワード をつけるだけ
・プロパティをstaticにする意味はあまりないので普通はstaticにしない
・呼び出しは、クラス外より行なうので、アクセス修飾子は必ず「public」とする
呼出
・インスタンスオブジェクトを生成せず、直接「クラス名::メソッド名()」で呼び出す
クラス名::メソッド名()
・クラス内よりアクセスする場合self::$プロパティ
self::メソッド()
日本語で例えてみる
「日本人」クラスを設計
class 日本人 {
}
}
氏名
プロパティ
・日本人なら誰もが持っていて、みな異なる(同じ場合もある)
・個々のインスタンス(例、山田太郎、鈴木花子)で異なる
class 日本人 {
氏名;
}
氏名;
}
生年月日
プロパティ
・日本人なら誰もが持っていて、みな異なる(同じ場合もある)
・個々のインスタンス(例、山田太郎1990-01-01、鈴木花子2000-02-02)で異なる
class 日本人 {
氏名;
生年月日;
}
氏名;
生年月日;
}
年齢
メソッドより求める
・日本人なら誰もが持っていて、みな異なる(同じ場合もある)
・個々のインスタンス(例、山田太郎27、鈴木花子17)で異なる
・プロパティを利用して算出可能
class 日本人 {
氏名;
生年月日;
年齢計算 function{生年月日プロパティを使用して求める};
}
氏名;
生年月日;
年齢計算 function{生年月日プロパティを使用して求める};
}
公用言語
staticプロパティ
・全ての日本人で共通
・すべてのインスタンス(例、山田太郎、鈴木花子)で共通なもの(であるがゆえに1つだけあればよい代物)
class 日本人 {
static 公用言語;
氏名;
生年月日;
年齢計算 function{生年月日を使用して求める};
}
static 公用言語;
氏名;
生年月日;
年齢計算 function{生年月日を使用して求める};
}
まとめ1
「氏名」「生年月日」「年齢」
・「日本人」ではなく、個々のインスタンス(例、山田太郎、鈴木花子)に属している
→ staticを付与しない
「公用言語」
・「日本人」に属している
→ staticを付与
まとめ2
インスタンスメソッド内より
・staticプロパティとstaticメソッドは呼出可
山田太郎の公用語を求める
staticメソッド内より
・普通のプロパティと普通のメソッドは呼び出し不可
日本人に共通な氏名を求める
日本人に共通な生年月日を求める
日本人に共通な年齢を求める
「static修飾子」付与 → クラスメソッド
クラスメソッド
クラスで定義されている関数の内、静的(static)なもの
・インスタンス化せずにアクセス可能
=静的メソッド
・インスタンス化せずにアクセス可能
クラスメソッド定義例
class Calculator{
public static function addition($int1, $int2){
}
public static function substraction($int1, $int2){
}
public static function getAverage($intVals){
}
}
public static function addition($int1, $int2){
}
public static function substraction($int1, $int2){
}
public static function getAverage($intVals){
}
}
クラスメソッド呼び出し例
Calculator::addition(10, 1);
Calculator::substraction(10, 1);
Calculator::getAverage($intVals);
クラスメソッドをメンバーとして持つクラス例
計算処理クラス
class Calculator{
// 足し算
public static function addition($int1, $int2){
return $int1 + $int2;
}
// 引き算
public static function substraction($int1, $int2){
return $int1 - $int2;
}
// 平均値を求める
public static function getAverage($intVals){
if (false == is_array($intVals)) {
return false;
}
$cnt = count($intVals);
$total = 0;
foreach ($intVals as $int) {
$total += $int;
}
$average = $total / $cnt;
return $average;
}
}
$answer = Calculator::addition(10, 1);
var_dump($answer);
$answer = Calculator::substraction(10, 1);
var_dump($answer);
$intVals = array(1, 2, 3, 4, 5, 6, 7);
$answer = Calculator::getAverage($intVals);
var_dump($answer);
▼結果
int(11)
int(9)
int(4)
int(9)
int(4)
階層関係 相関イメージ
メンバ(内容別)
メンバ
|
+--- プロパティ
| |
| +--- インスタンスプロパティ
| |
| +--- クラスプロパティ
|
+--- メソッド
|
+--- インスタンスメソッド
|
+--- クラスメソッド
|
+--- プロパティ
| |
| +--- インスタンスプロパティ
| |
| +--- クラスプロパティ
|
+--- メソッド
|
+--- インスタンスメソッド
|
+--- クラスメソッド
メンバへのアクセス方式(書式)
メンバへのアクセス方式
|
+--- 「インスタンスオブジェクト経由アクセス」→「->(アロー演算子)」利用。オブジェクト生成必要
|
+--- 「クラスアクセス」→「:(スコープ演算子)」利用。オブジェクト生成不要
|
+--- 「インスタンスオブジェクト経由アクセス」→「->(アロー演算子)」利用。オブジェクト生成必要
|
+--- 「クラスアクセス」→「:(スコープ演算子)」利用。オブジェクト生成不要
メンバへのアクセス(プロパティ)
class A
{
public $p;
public static $s;
}
$a = new A();
{
public $p;
public static $s;
}
$a = new A();
メンバへのアクセス(プロパティ)
|
+--- $a->p ◯「オブジェクト経由アクセス」インスタンスプロパティ
|
+--- $a->s ×「オブジェクト経由アクセス」クラスプロパティ ※「スタティック」宣言したプロパティは完全に「クラスプロパティ」となるため、「インスタンスプロパティ」としてオブジェクト経由で参照することはできない
|
+--- A::$p ◯「クラスアクセス」インスタンスプロパティ
|
+--- A::$s ◯「クラスアクセス」クラスプロパティ
|
+--- $a->p ◯「オブジェクト経由アクセス」インスタンスプロパティ
|
+--- $a->s ×「オブジェクト経由アクセス」クラスプロパティ ※「スタティック」宣言したプロパティは完全に「クラスプロパティ」となるため、「インスタンスプロパティ」としてオブジェクト経由で参照することはできない
|
+--- A::$p ◯「クラスアクセス」インスタンスプロパティ
|
+--- A::$s ◯「クラスアクセス」クラスプロパティ
メンバへのアクセス(メソッド)
class A
{
public $p();
public static $s();
}
$a = new A();
{
public $p();
public static $s();
}
$a = new A();
メンバへのアクセス(メソッド) ※メソッド内の記述によっては下記と異なる挙動となる
|
+--- $a->p() ◯「オブジェクト(インスタンスメソッド)経由アクセス」
|
+--- $a->s() △「オブジェクト(クラスメソッド)経由アクセス」 ※可読性の観点から、クラス関数へはアロー演算子でアクセスしない方がよい
|
+--- A::p() △「クラスアクセス(インスタンスメソッド経由)」 ※static でないメソッドを静的呼出ししているので、限りなくまちがいに近い
|
+--- A::s() ◯「クラスアクセス(クラスメソッド経由)」
|
+--- $a->p() ◯「オブジェクト(インスタンスメソッド)経由アクセス」
|
+--- $a->s() △「オブジェクト(クラスメソッド)経由アクセス」 ※可読性の観点から、クラス関数へはアロー演算子でアクセスしない方がよい
|
+--- A::p() △「クラスアクセス(インスタンスメソッド経由)」 ※static でないメソッドを静的呼出ししているので、限りなくまちがいに近い
|
+--- A::s() ◯「クラスアクセス(クラスメソッド経由)」
詳細
一覧表
△
・可読性を考慮すると、避けた方が無難
一覧表
メンバの種類 | インスタンス経由アクセス「->」 | クラス経由アクセス「::」 |
---|---|---|
インスタンスプロパティ | ◯ | ◯ |
クラスプロパティ | × | ◯ |
インスタンスメソッド | ◯ | △(staticでないメソッドを静的呼出し) |
クラスメソッド | △ | ◯ |
・staticメソッド内で「$this」使用不可
/*
* 値が異なったら、順位と値を更新するメソッド
* ランキング出力する際に使用
* @param string $value 順位の基準となる値
* @return int $rank 順位
*/
class Samerank
{
public static $rank = 0; //初期値(実際は最初必ず繰り上がるはずなので「1」小さい)
public static $lastValue = null;
public static function rankUpdate($value){
if (Samerank::$lastValue !== $value) {//異なったら
Samerank::$rank++; //順位を更新
Samerank::$lastValue = $value; //前のレコードの値を更新
}
return Samerank::$rank;
}
}
メンバへアクセスする方法
アクセス経路2種類
インスタンスオブジェクト経由アクセス
・インスタンスオブジェクト生成が必要
・「->(アロー演算子)」を用い、生成したオブジェクト経由で「インスタンスメンバ」へアクセス
クラス経由アクセス
・オブジェクト生成は不要
・「::(スコープ演算子)」を利用し、「クラスメンバ」へ直接アクセス
メソッド
クラスで定義されている関数
・メンバ関数
・「インスタンスメソッド」と「クラスメソッド」の2種類存在
メソッド分類2種類
インスタンスメソッド
・インスタンスオブジェクトに所属する関数
・クラス定義されている関数の内、静的(static)でないもの
・インスタンス(オブジェクト)を通してアクセスする
クラスメソッド
・クラスに所属する関数
・静的メソッド
・クラス定義されている関数の内、静的(static)なもの
・インスタンス化せず(クラスのインスタンスオブジェクトを生成せず)にアクセス
「$this」の利用可否
利用可
・インスタンスメソッド
→ インスタンスを生成し、そのメソッド内で「self::」または「parent::」を使用してコールした場合
利用不可
・「クラスメソッド」としてコールされた場合
・「インスタンスオブジェクト」は生成されていないため、メソッド内でオブジェクトへのリファレンスを保持する「$this」は利用不可
「self::」「parent::」
「クラスメソッド」がアクセスできるのは?
・「クラスメンバ」のみ
・具体的には、「self::」を用いて「self::$static_public_property」や「self::static_public_method()」のようにアクセスする
・ちなみに、「クラスメソッド」でない「インスタンスメソッド」もこれでコールできる
・しかし、この場合にコールされるのは「インスタンスメソッド」となる(当然、「クラスメソッド」からのアクセスの場合は「クラスメソッド」としてコールされる)
「static修飾子」と「アクセス制限修飾子」の順番
・定義時に指定する「static修飾子」と「アクセス制限修飾子」の順番は任意。ex) 「static public $v」 でも、「public static $v」でも可。
コンストラクタ
・「スタティック」宣言できない
・そもそもスタティックにコールされることを想定していない
<pre>
<?php
class A{
public $public_v = "public_vメンバ変数";
static public $static_public_v = "static_public_vメンバ変数";
public function public_method(){
return "public_method()";
}
static public function static_public_method(){
return "static_public_method()";
}
public function get_static_public_v(){
#通常メソッド内でクラスメンバ参照
return self::$static_public_v;
}
static public function get_public_v(){
#スタティックメソッド内でインスタンスメンバ参照
return $this->public_v;
}
}
/*
class SKY{
#①コンストラクタをスタティック宣言しようとすると、Fatal error: Constructor SKY::SKY() cannot be staticとなる。コンストラクタは「スタティック」宣言できない(そもそもスタティックにコールされることを想定しないため)
static public function SKY(){
//empty
}
}
*/
#②インスタンスオブジェクト生成
$a = new A;
echo "■③インスタンスオブジェクト経由アクセス\n";
echo "▼インスタンスプロパティ取得\n";
echo '$a->public_v : ', $a->public_v, "\n\n";
echo "▼クラスプロパティ取得\n";
echo '$a->static_public_v : ', $a->static_public_v, "×「スタティック」宣言したプロパティは完全に「クラスプロパティ」となるため、「インスタンスプロパティ」として参照することが出来なくなる。\n\n";
echo "▼インスタンスメソッド取得\n";
echo '$a->public_method() : ', $a->public_method(), "\n\n";
echo "▼クラスメソッド取得 ※可読性の観点から、クラス関数へはアロー演算子でアクセスしない方がよい\n";
echo '$a->static_public_method(): ', $a->static_public_method(), "\n\n
";
echo "■④クラスアクセス\n";
echo "▼インスタンスプロパティ取得\n";
echo 'A::$public_v : '/*, A::$public_v*/, "×「インスタンスプロパティ」を「クラスプロパティ」として参照することはできない。【Fatal error: Access to undeclared static property: A::$public_v】\n\n";
echo "▼クラスプロパティ取得\n";
echo 'A::$static_public_v : ', A::$static_public_v, "\n\n";
echo "▼インスタンスメソッド取得 ※static でないメソッドを静的呼出ししているので、限りなくまちがいに近い\n";
echo 'A::public_method() : ', A::public_method(), "\n\n";
echo "▼クラスメソッド取得\n";
echo 'A::static_public_method() : ', A::static_public_method(), "\n\n
";
echo "■⑤インスタンスオブジェクト経由アクセス\n";
echo "▼インスタンスプロパティ更新\n";
$a->public_v = "public_vメンバ変数更新";
echo "▼インスタンスプロパティ取得\n";
echo '$a->public_v : ', $a->public_v, "\n\n
";
echo "■⑥クラスアクセス\n";
echo "▼クラスプロパティ更新\n";
A::$static_public_v = "static_public_vメンバ変数更新";
echo "▼クラスプロパティ取得\n";
echo 'A::$static_public_v : ', A::$static_public_v, "\n\n
";
echo "■⑦新たなオブジェクトb生成\n\n
";
$b = new A;
echo "■⑧インスタンスオブジェクト経由アクセス\n";
echo "▼インスタンスプロパティ取得\n";
echo '$b->public_v : ', $b->public_v, " …「aオブジェクトに対するインスタンスプロパティ」更新は、「bオベジェクトのインスタンスプロパティ」とは関係がない\n\n
";
echo "■⑨インスタンスオブジェクト(インスタンスメソッド)経由アクセス\n";
echo "▼クラスプロパティ取得\n";
echo '$a->get_static_public_v() : ', $a->get_static_public_v(), " …「クラスに対するプロパティ」更新は、そのクラスから生成される全てのオブジェクトが影響を受ける(クラスプロパティとインスタンスオブジェクトは無関係)\n";
echo '$b->get_static_public_v() : ', $b->get_static_public_v(), " …「クラスに対するプロパティ」更新は、そのクラスから生成される全てのオブジェクトが影響を受ける(クラスプロパティとインスタンスオブジェクトは無関係)\n\n
";
echo "■⑩クラスアクセス(クラスメソッド)経由\n";
echo "▼インスタンスプロパティ取得\n";
echo 'A::get_public_v() : '/*, A::get_public_v()*/, "×【Fatal error: Using $this when not in object context】「オブジェクトではないから「\$this」は使えない」 \n\n
";
echo "■⑪インスタンスオブジェクト(クラスメソッド)経由アクセス\n";
echo "▼インスタンスプロパティ取得\n";
echo '$a->get_public_v() : '/*, $a->get_public_v()*/,"×【Fatal error: Using $this when not in object context】「オブジェクトではないから「\$this」は使えない」 \n";
?>
▼クラス継承時の注意事項
子クラスで親クラスと同名のプロパティを再定義する場合も、メソッドをオーバーライドする場合も、「クラスメンバ」だったものを「インスタンスメンバ」にしたり、「インスタンスメンバ」だったものを「クラスメンバ」に変更することは出来ない。
また、“「パブリック」な「スタティックプロパティ」”に関して、何れの場合も(子クラスで「スタティック」宣言したとしても)子クラスで再定義することができない。