オープンソースのWeb開発向けスクリプト言語「PHP」の文法を一から学ぶための入門連載。今回はクラスの機能として、staticと定数を扱います。
オープンソースのWeb開発向けスクリプト言語「PHP」の文法を一から学ぶための入門連載「Web業界で働くためのPHP入門」。今回も、前回の続きで、PHPのオブジェクト指向言語としての書き方を紹介します。
staticは、「静的」と和訳されます。連載第10回で紹介した静的変数は、英語の「static variable」を和訳したものです。つまり、staticという言葉はこの連載では、初出ではありません。ただし、ここで扱うstaticはクラスのメンバ、つまり、プロパティやメソッドについての話なので、静的変数とは区別するためにあえて和訳せずにstaticと表記しています。和名を使うならば、単に「静的」といわずに、「静的プロパティ」「静的メソッド」とした方が正確です。
さて、そのstaticは、簡単に言うと、クラスのインスタンスを生成することなしに、つまり、newせずに利用できるプロパティやメソッドのことです。newせずに利用すると、いったいどういう挙動となるのか、これから見ていくことにしましょう。
まずは、staticの性質が分かりやすい「プロパティ」からです。
staticプロパティが実際にどういったものか、サンプルで見ていきましょう。まず、以下のStaticMembersクラスを作成してください。
<?php class StaticMembers { //staticプロパティ。 public static $stNum = 0; //(1) //通常のプロパティ。 public $num = 0; //(2) //それぞれのプロパティに引数の数値を加算するメソッド。 public function countUp(int $plus):void { //staticプロパティに加算。 self::$stNum += $plus; //(3) //通常プロパティに加算。 $this->num += $plus; //(4) } }
(1)がstaticなプロパティを初期値「0」で宣言しているところです。staticなメンバを作成するには、プロパティでもメソッドでも、staticを付けるだけです。
staticと非staticの違いがはっきりするように、ここでは通常のプロパティも宣言しています(2)。
メソッドcountUp()は、引数でもらった数値をその両プロパティに加算するメソッドです。(3)でstaticなプロパティ$stNumに、(4)で非staticなプロパティ$numに加算処理を行っています。
ここで注目するのは(3)です。同一インスタンス内のプロパティにアクセスするには下記のような記述をしますが、staticは違います。
$this->プロパティ名
「->」ではなく「::」を使います。さらに、自分自身も「$this」ではなく、「self」を使います。まとめると、以下のようになります。
self::プロパティ
クラスが記述できたので、このクラスを利用する以下のuseStaticMembersProperty.phpを作成し、実行してください。
<?php require_once("StaticMembers.php"); //StaticMembersインスタンスを2コ作成。 $staticA = new StaticMembers(); //(1) $staticB = new StaticMembers(); //(1) //AのcountUp()を引数10で実行。 $staticA->countUp(10); //(2) //Aのプロパティをそれぞれ出力。 print("staticAのstNum: ".$staticA::$stNum." num: ".$staticA->num); //(3) //BのcountUp()を引数5で実行。 $staticB->countUp(5); //(4) //Bのプロパティをそれぞれ出力。 print("<br>staticBのstNum: ".$staticB::$stNum." num: ".$staticB->num); //(5) //StaticMembersのstaticプロパティのみ出力。 print("<br>stNum: ".StaticMembers::$stNum); //(6)
実行結果は以下の通りです。
staticAのstNum: 10 num: 10 staticBのstNum: 15 num: 5 stNum: 15
(1)でStaticMembersのインスタンスを2個作成し「A」「B」とします。まず、(2)でAのcountUp()を引数10で実行します。ということは、A内部のプロパティ$stNumと$numそれぞれに10加算されるはずです。それを確認するために、(3)で出力します。実行結果の1行目を見ると、その通りになっています。
次に、(4)でBのcountUp()を引数「5」で実行します。同じように、B内部のプロパティ$stNumと$numそれぞれに5加算されるはずです。それを確認するために、(5)で出力します。Aと同じく、下記のように出力されるはずです。
staticBのstNum: 5 num: 5
ところが、実行結果はそうなっていません。$stNumは、明らかにAで加算された10にさらにBの5が加算された値になっています。これは、どういう現象でしょうか。
連載第13回でクッキーの型とクッキーの喩えを使ってクラスとインスタンスの関係を説明しました。その際、プロパティの値は各インスタンスに属していることを理解してもらえたと思います。ところが、staticが付くと、そのプロパティはインスタンスに属さずクラスに属します(図1)。
この図から分かるように、インスタンスを何個生成しても、staticプロパティは1個しか存在しません。従って、リスト2の(2)でAのcountUp()メソッドを使って$stNumに10加算した後に(4)でBのcountUp()メソッドを使って$stNumに5加算していますが、この両処理で加算対象となっている変数は実は同じものなのです。そのため、(4)で加算する際は、既に$stNumは10になっているのです。この流れを図1に追記したのが図2です。
図2を見ると、staticプロパティと非staticプロパティの挙動が全く違うことが理解できるでしょう。
ところで、リスト2の(6)に注目してください。リスト2の(3)や(5)ではstaticプロパティへのアクセスとして「$staticA::$stNum」や「$staticB::$stNum」と記述しています。
先に説明したように、staticプロパティへのアクセスは「::」を使います。従って、「::$stNum」という記述は正しいものです。ところが、そもそもクラスに属し、全インスタンス中で1個しか存在しないプロパティに対して、インスタンスを表す$staticAや$staticBからアクセスするのは変です。
この記述方法は、リスト2を動作させてもエラーになっていないところから、可能は可能なのです。しかし、正しくはクラス経由でアクセスします。それが下記のような(6)の記述方法です。
StaticMembers::$stNum
まとめると以下のようになります。
クラス名::プロパティ
Copyright © ITmedia, Inc. All Rights Reserved.