第5章 クラスメンバとインスタンスメンバ
5.1 インスタンスメンバとクラスメンバについて
これまでクラス内にはフィールド変数、メソッド、コンストラクタといったメンバを記述できることを学習してきました。その中のフィールドとメソッドのメンバについて2種類に分類することができます。それはこれまでの章で目にしてきたインスタンスメンバ、そしてもう1つ本節の後半で学習するクラスメンバとなります。
PHPフレームワーク基礎テキストの第2章では、「static」キーワードがついたメソッドのことを「クラスメソッド」、つかないメソッドを「インスタンスメソッド」と呼ぶことを説明しましたが、それはフィールド変数にも当てはまり、「static」キーワードがついた変数のことを「クラス変数」、つかない変数を「インスタンス変数」と呼びます。また、「static」キーワードがついたメソッドや変数を総称して「クラスメンバ」、つかないメソッドや変数を「インスタンスメンバ」と呼びます。
2つのメンバの違いを簡単に説明すると以下のようになります。
・インスタンスメンバはオブジェクトに対して関連付けられるメンバ
・クラスメンバはクラスに対して関連付けられるメンバ
この関連付けされる場所によって大きく仕組みが変わってきますので、これからその仕組みについて学習します。
まずはこれまでに目にしてきた、インスタンスメンバで構成されたクラスの再確認をしていきましょう。
5.1.1 インスタンスメンバとは
これまでの学習でクラスに定義してきたメンバ(フィールド変数、メソッド)をインスタンスメンバと呼びます。
インスタンスメンバの特徴
クラス内のインスタンスメンバにはオブジェクトが作成されてはじめて、フィールド変数に値を格納できたり、メソッドを呼び出したりすることができます。逆に言えば、オブジェクトを生成しない限りメンバにアクセスができないという性質をもつものがインスタンスメンバになります。
オブジェクト生成時にインスタンスメンバは、オブジェクト毎にメンバが生成されます。(2.3.3サンプル参照)
書式:インスタンスメンバの定義
これまでの各章で定義してきたクラスと同じになります。
凡例:インスタンスメンバのクラス定義
次の項にてインスタンスメンバで構成されたサンプルを再度簡単に説明していきます。
5.1.2 インスタンスメンバを使用したプログラム
インスタンスメンバで構成されたクラスを複数オブジェクト化し、インスタンスメンバにアクセスして内容を確認します。
ソースコード
ソース・フォルダー :myproj_framework_basic/ch05
ファイル名 :instanceMember.php
アクセスURL :http://localhost/myproj_framework_basic/ch05/instanceMember.php
➢ instanceMember.php
<?php // クラスの定義作成 class Computer1{ private $os;// インスタンス変数 private $memory;// インスタンス変数 public function __construct(){// コンストラクタ $this->os = null; $this->memory = 0; echo "パソコンを作成しました。<br>"; } public function setOsMemory($os, $memory){//インスタンスメソッド $this->os = $os; $this->memory = $memory; echo "OSを「" . $os . "」に、メモリサイズを「" . $memory . "MByte」に変更しました。<br>"; } public function show(){//インスタンスメソッド echo "パソコンのOSは「" . $this->os . "」です。<br>"; echo "メモリサイズは「" . $this->memory . "MByte」です。<br>"; } } ?> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>インスタンスメンバ</title> </head> <body> <?php $com1 = new Computer1(); // $com1オブジェクト作成(インスタンス作成) $com1->setOsMemory("WindowsXP", 2048); // $com1オブジェクトのsetOsMemoryメソッド呼び出し $com1->show(); // $com1オブジェクトのshowメソッド呼び出し echo "---------------------------------------------------------<br>"; $com2 = new Computer1(); // $com2オブジェクト作成(インスタンス作成) $com2->setOsMemory("Windows2000", 512); // $com2オブジェクトのsetOsMemoryメソッド呼び出し $com2->show(); // $com2オブジェクトのshowメソッド呼び出し ?> </body> </html>
実行結果
解説
3~22行目で定義されているComputer1クラスはインスタンスメンバのみで構成されています。
4、5行目の2つのフィールド変数「$os、$memory」がインスタンス変数に該当し、13行~21行目の2つのメソッド「setOsMemory()、show()」がインスタンスメソッドに該当します。
31行~37行で「Computer1」クラスを2つ生成しています。31、35行目でオブジェクトを2つ生成することにより、個々のオブジェクト($com1、$com2)のインスタンスメソッドを呼び出すことができます。
実行結果を見て分かるようにオブジェクト毎($com1、$com2)にフィールドの値があることが確認できます。
ポイント・インスタンスメンバはオブジェクト自身に関連付けられる為、オブジェクトを生成してアクセスする必要がある。
さらにインスタンスメンバはオブジェクト毎に個々として独立する。
インスタンスメンバの関連付けの仕組み
図 5.1.1: インスタンスメンバの関連付け
上記の図のようにオブジェクトを生成することで、インスタンスメンバも同時に生成されます。これによりメソッドを利用してそれぞれのオブジェクトの「$os」や「$memory」に値を代入したり、出力したりすることができました。OSやメモリといった値がそれぞれのパソコンに設定されているように、各Computer1オブジェクトのフィールドへ値を格納することができたのです。
オブジェクトを生成すると実体化しアクセス可能になるメンバはオブジェクトに関連付けられていると言えます。このような、各オブジェクトに関連づけられているフィールドをインスタンス変数、メソッドをインスタンスメソッド、この2つを総称してインスタンスメンバと呼びます。
図を見るとコンストラクタが消されているのが確認できます。なぜならコンストラクタはオブジェクトを生成する際に呼び出される特別なメソッドのため、オブジェクトに関連付けられません。このことも合わせて覚えておいて下さい。
前項でインスタンスメンバについて学習しました。次の項ではもう1つのクラスメンバについて説明を行っていきます。
5.1.3 クラスメンバとは
インスタンスメンバはオブジェクトに関連づけられたように、クラスメンバはクラス自身に関連づけられるメンバのことをいいます。ではどのようにすればクラスメンバとして定義できるか、構文を説明していきます。
クラスメンバの特徴
static修飾子がついたクラスメンバはオブジェクトを生成しないでメンバにアクセスができるという性質をもちます。オブジェクトがいくつ生成されてもクラスメンバは、各オブジェクト共通のメンバになりますので、クラス全体で扱うべきデータや操作をクラスメンバとしておくのが一般的な使い方になります。
書式:クラスメンバの定義
これまでインスタンスメンバの定義方法に加えてstaticというキーワードがついている所がポイントです。
このstaticキーワードがつくことでクラスメンバを「スタティックメンバ」とも呼びます。
凡例:クラスメンバの定義
書式:クラスメンバへのアクセス方法
クラスメンバへのアクセス方法は「クラス名」の後に「::」をつけてアクセスしたいクラスメンバを記述します。この時、オブジェクトの生成が必要ない点がポイントになります。
凡例:クラスメンバへのアクセス方法
クラスメンバの定義凡例で紹介した「Computer2」クラスを例にしています。
クラスメンバとインスタンスメンバへのアクセス方法の違い
① クラス変数へはオブジェクトを生成せずに「クラス名::フィールド変数名」で直接アクセスします。
② クラスメソッドへはオブジェクトを生成せずに「クラス名::メソッド名」で直接アクセスします。
③ Computer2クラス型のオブジェクトを生成します。($com1)
④ インスタンスメソッドへはオブジェクトから「オブジェクト変数名.メソッド名」でアクセスします。
⑤ Computer2クラス型のオブジェクトを生成します。($com2)
⑥ インスタンスメソッドへはオブジェクトから「オブジェクト変数名.メソッド名」でアクセスします。
上記を見て分かるように、クラスメンバへはオブジェクトを生成しなくてもアクセスすることが可能になっています。なぜならクラスメンバはクラス自身に関連付けされており、既に実体として定義されているからです。インスタンスメンバもクラスに定義しますが実体ではありません。オブジェクトを生成することでオブジェクト自身に関連付けられた実体を持つことになり、そこで初めてアクセスが可能になります。この違いがインスタンスメンバとクラスメンバの大きな違いになります。
では次の項でクラスメンバを利用したサンプルを紹介します。
5.1.4 クラスメンバを使用したプログラム
インスタンスメンバとクラスメンバ両方で構成されたクラスを複数オブジェクト化して、クラスメンバにアクセスして内容を確認します。
ソースコード
ソース・フォルダー :myproj_framework_basic/ch05
ファイル名 :classMember.php
アクセスURL :http://localhost/myproj_framework_basic/ch05/classMember.php
➢ classMember.php
<?php // クラスの定義作成 class Computer2{ private $os;// インスタンス変数 private $memory;// インスタンス変数 public static $sum;// クラス変数 // コンストラクタ public function __construct(){ $this->os = null; $this->memory = 0; Computer2::$sum++; echo "パソコンを作成しました。<br>"; } public function setOsMemory($os, $memory){// インスタンスメソッド $this->os = $os; $this->memory = $memory; echo "OSを「" . $os . "」に、メモリサイズを「" . $memory . "MByte」に変更しました。<br>"; } public function show(){// インスタンスメソッド echo "パソコンのOSは「" . $this->os . "」です。<br>"; echo "メモリサイズは「" . $this->memory . "MByte」です。<br>"; } public static function showSum(){// クラスメソッド echo "■パソコンは合計" . Computer2::$sum . "台作成されています。<br>"; } } ?> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>クラスメンバ</title> </head> <body> <?php Computer2::$sum = 0; // クラス変数sumにアクセスし0で初期化 Computer2::showSum(); // クラスメソッドshowSumにアクセス1回目(オブジェクト作成前) $com1 = new Computer2(); $com1->setOsMemory("WindowsXP", 2048); $com1->show(); Computer2::showSum(); // クラスメソッドshowSumにアクセス2回目(com1オブジェクト作成後) $com2 = new Computer2(); $com2->setOsMemory("Windows2000", 512); $com2->show(); Computer2::showSum(); // クラスメソッドshowSumにアクセス3回目(com1,com2オブジェクト作成後) ?> </body> </html>
実行結果
解説
3~27行目で定義されているComputer2クラスはインスタンスメンバとクラスメンバで構成されています。6行目のフィールド変数「$sum」がクラス変数に該当し、24行~26行目のメソッド「showSum()」がクラスメソッドに該当します。その他のフィールド変数やメソッドはインスタンスメンバになります。
Computer2クラスのコンストラクタ処理内12行目で、クラス変数「$sum」をインクリメントしています。
これによりオブジェクト生成する毎に数値が1増え、クラスを何回生成しているか分かるようになります。
呼び出し元では、初めに36行目の処理でクラス変数である「$sum」にアクセスして「0」を設定しています。※ここではまだオブジェクトは生成していない。
続いて37行目の処理でクラスメソッドである「showSum()メソッド」にアクセス(1回目)し、クラス変数の「$sum」の値を画面に出力しています。実行結果からも分かるように36行目で設定した値0で正しくメッセージが出力されているのが確認できます。
上記処理の実行結果
39行目で1つ目のComputer2型のオブジェクトを生成し、「setOsMemory()メソッド」を利用して値を設定しています。値が正しく設定されているかを「show()メソッド」を利用して確認しています。
上記処理の実行結果
39行でComputer2型のオブジェクト生成が行われクラス変数「$sum」の値が1増えているはずなので、42行目でクラスメソッドである「showSum()メソッド」にアクセス(2回目)し、クラス変数の「$sum」の値を画面に出力しています。オブジェクト生成後クラス変数「$sum」の値は正しく1増えていることが確認できます。
上記処理の実行結果
44行目で2つ目のComputer2型のオブジェクトを生成し、「setOsMemory()メソッド」を利用して値を設定しています。値が正しく設定されているかを「show()メソッド」を利用して確認しています。
上記処理の実行結果
44行でComputer2型のオブジェクト生成が行われクラス変数「$sum」の値がさらに1増えているはずなので、47行目でクラスメソッドである「showSum()メソッド」にアクセス(3回目)し、クラス変数の「$sum」の値を画面に出力しています。オブジェクト生成後クラス変数「$sum」の値が、1増えていることが確認できます。
上記処理の実行結果
ポイント・クラスメンバはクラス自身に関連付けられる為、オブジェクトを生成せずに直接アクセスできる。
但しクラスメンバは各オブジェクト共通メンバになる。
クラスメンバの関連付けの仕組み
図 5.1.2: クラスメンバの関連付け
クラス自身に関連づけられているフィールドをクラス変数、メソッドをクラスメソッドといいこの2つを総称してクラスメンバと呼びます。
5.1.5 インスタンスメソッドからクラスメンバを利用したプログラム
インスタンスメソッド内からクラスメンバにアクセスして動作するプログラムです。
ソースコード
ソース・フォルダー :myproj_framework_basic/ch05
ファイル名 :classMemberFromInstanceMethod.php
アクセスURL :http://localhost/myproj_framework_basic/ch05/classMemberFromInstanceMethod.php
➢ classMemberFromInstanceMethod.php
<?php // クラスの定義作成 class Computer3{ private $os;// インスタンス変数 private $memory;// インスタンス変数 public static $sum;// クラス変数 // コンストラクタ public function __construct(){ $this->os = null; $this->memory = 0; Computer3::$sum++; echo "パソコンを作成しました。<br>"; } public function setOsMemory($os, $memory){ $this->os = $os; $this->memory = $memory; echo "OSを「" . $os . "」に、メモリサイズを「" . $memory . "MByte」に変更しました。<br>"; } public function checkSum(){ if(Computer3::$sum > 2){ echo "■" . Computer3::$sum . "台コンピュータが作成されたので、メンテナンスを実施して下さい。<br>"; }else{ echo "■" . Computer3::$sum . "台目なので、まだメンテナンスは必要ありません。<br>"; } } } ?> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>インスタンスメソッドからクラスメンバ参照</title> </head> <body> <?php $com1 = new Computer3(); // Computer3オブジェクト作成1回目 $com1->setOsMemory("WindowsXP", 2048); $com1->checkSum(); $com2 = new Computer3(); // Computer3オブジェクト作成2回目 $com2->setOsMemory("Windows2000", 512); $com2->checkSum(); $com3 = new Computer3(); // Computer3オブジェクト作成3回目 $com3->setOsMemory("WindowsVista", 3072); $com3->checkSum(); ?> </body> </html>
実行結果
解説
このComputer3クラスは5.1.4で紹介したComputer2クラスを元に、show()メソッド、showSum()メソッドの代わりとして20行~26行目で定義しているcheckSum()メソッドが追加されています。このcheckSum()メソッドはクラス変数である$sumの値を調べ、3以上であるならメンテナンスを促すメッセージを出力します。
呼び出し元の36行目で1回目のオブジェクト生成を行います。
37行目でインスタンスメソッドを利用して各値を設定したのち、38行目の「checkSum()メソッド」を呼び出してクラス変数の値チェックを行っています。画面の出力結果を見て分かるように、インスタンスメソッドからクラス変数にアクセスできていることが確認できます。
上記処理の実行結果
続いて40行目で2回目のオブジェクト作成を行います。41行目でインスタンスメソッドを利用して各値を設定したのち、42行目の「checkSum()メソッド」を呼び出してクラス変数の値チェックを行っています。画面の出力結果を見てまだ2回目のオブジェクト生成なので、「■2台目なので、まだメンテナンスは必要ありません。」と表示されていることが確認できます。
上記処理の実行結果
最後となる3回目のオブジェクト作成を44行目で行います。45行目でメソッドを利用して各値を設定したのち、46行目の「checkSumメソッド」を呼び出してクラス変数の値チェックを行っています。今回のオブジェクト生成処理で$sumの値が3となり、画面に「■3台コンピュータが作成されましたので、メンテナンスを実施して下さい。」と正しく出力されているのが確認できます。
上記処理の実行結果
今回のサンプルではインスタンスメソッドからクラス変数にアクセスしていますが、クラスメソッドにもアクセス可能となっていますので合わせて覚えておいて下さい。
ポイント・インスタンスメソッド内からクラスメンバへアクセスは可能。