クラス
クラスとは、一般に関数の集合体として定義されていますが、関数と比べデータの扱いという点で見比べてみるとその違いがよりわかりやすくなります。関数は与えられた入力値(引数)を元にして処理結果を戻り値として出力するだけのしくみですが、クラスまたはオブジェクトは、自分自身のなかにデータを格納する変数としての役割もはたしています。その結果、関数でのデータの扱いは、データが処理を「通過」していくだけなのにたいして、クラス、オブジェクトではさらに処理前、処理後のデータを内部で保持しておくことが可能になります。プログラマは必要に応じこの値を取り出して再度利用することができるようになるわけです。
データを保持 | データを処理 | |
変数 | ○ | × |
関数 | × | ○ |
クラス、オブジェクト | ○ | ○ |
オブジェクト
クラスを理解するうえで重要になってくるのがオブジェクトです。クラスとオブジェクトは似て非なるものです。オブジェクトとはクラスを元にしてつくられたコピーを指します。クラスでは「データを保持できる」という性質をもっているため、複数の処理でひとつのクラスにアクセスした場合、データの上書き(不整合)を引き起こす危険があります。そのため、処理に応じクラスのコピーを作成し、そのコピーに対してアクセスすることが考えだされました。実際に使う場合には、まずクラス本体には手を加えず、オブジェクトと呼ばれるクラスのコピーを作成しそれを処理の対象としてプログラムを組んでいきます。
TOPインスタンス化
クラスのコピー(オブジェクト)を生成することを「インスタンス化」といいます。インスタンス化とは、クラスを扱うための「自分専用の領域」を確保する行為ともいえます。PHPでは、クラスのインスタンス化を次のようにnew演算子を使って行ないます。また、インスタンス化の際に、必要に応じて初期化のためのデータを引き渡すことも可能です。
$変数名 = new クラス名([引数,...]);
引数が必要ない場合でもカッコは省略できない点に注意してください。インスタンス化したオブジェクトは「$変数名」に格納され、以降はこの変数をオブジェクトとして扱うことになります。また、インスタンス化した変数を「オブジェクト変数」と呼称します。この場合、オブジェクト変数のなかのクラスに属する関数と変数のことを「メンバ関数」と「メンバ変数」、または「メソッド」と「プロパティ」と呼びます。
・処理の適応、戻り値の取得 [戻り値] = $変数名 -> メソッド名([引数,...]); ・値の参照、代入 $変数名 -> プロパティ名 [ = 値];TOP
コンストラクタ、デストラクタ
インスタンス化の際に実行される特別なメソッド(メンバ関数)のことを、コンストラクタと呼びます。PHP4では、クラス名と同名のメソッドをコンストラクタと見なしていましたが、PHP5からは、「__construct」という統一名を採用しています。もし、クラスと同じ名前のメソッドがクラス(オブジェクト)内に存在する場合には「__construct」が優先して処理されます。コンストラクタは、インスタンス化のタイミングで実行されるという性質上、プロパティ(メンバ変数)の初期化や、クラスで使用する各種リソースの初期化といった呼び出されて最初の一回だけ処理を必要とするものを記述するのが一般的です。特に初期化処理が必要ない場合は、コンストラクタは省略可能です。
コンストラクタとは反対に、オブジェクト(インスタンス)が破棄されるタイミングで実行されるのがデストラクタです。デストラクタはPHP5以降でのみ利用可能で、統一名として「__destruct」を採用しています。デストラクタには、クラス内で使用したリソースを破棄するなど主に終了処理を記述するのが一般的です。PHPでは、Javaと同じくメモリの解放などは自動である程度おこなってくれるので使用頻度としてはコンストラクタより多くはみかけません。
アクセス修飾子
クラスを理解するうえでもう一つ重要な概念となるのが「アクセス修飾子」です。アクセス修飾子とは、クラス内のメンバ変数(プロパティ)やメンバ関数(メソッド)に対するアクセスの可否を決めるための命令になります。
・PHP5で利用可能なアクセス修飾子
アクセス修飾子 | 概要 |
public | どこからでもアクセス可能(デフォルト) |
protected | 現在のクラスとサブクラスでのみアクセス可能 |
private | 現在のクラス内部でのみアクセス可能 |
アクセス修飾子を省略した場合、そのメソッドとプロパティはpublic扱いと見なされ、デフォルトでどこからでもアクセス可能になります。また、PHP4ではプロパティを定義するためのvar命令がありましたが、こちらもpublic修飾子と同様の意味であると見なされます。これら、修飾子としての役割は、クラス内部の機能をクラス外部から隠蔽することが目的で使われます。こうした機能をオブジェクト指向では「カプセル化」と言います。 TOP
ゲッタメソッド、セッタメソッド
クラス内のprivate変数にアクセスするためのメソッドのことを「アクセサメソッド(Accesor Method)」と総称します。また、「get_」メソッドと「set_」メソッドをそれぞれ「ゲッタメソッド(Getter Method)」、「セッタメソッド(Setter Method)」と呼ぶこともあります。
public function get_プロパティ名(){ return $this -> プロパティ名; } public function set_プロパティ名(){ $this -> プロパティ名 = 引数; }「$this」は、現在のクラスを示すための命令で、クラス内のメンバにアクセスするためには、この$thisを介して行う必要があります。アクセサメソッドの名前は、一般的に「get_プロパティ名」、「set_プロパティ名」とするのが慣例ですが構文規則ではないので必ずしもこの規則に従う必要はありません。get_メソッドが定義された場合にはプロパティは読み取り専用にset_メソッドが定義された場合にはプロパティは書き込み専用になります。プロパティを隠蔽して、アクセサメソッドを介して参照、設定することで、
- 読み書きの制御が可能となる
- プロパティ値を設定する際に値の検証を行える
- プロパティ値を参照する際に値の加工を行える
静的メソッド
クラスを利用するにあたっては、必ず「インスタンス化」を行い、クラスのコピーを生成する必要があると紹介しましたが、例外的に「インスタンス化」を行わなくても利用できるメソッドがあります。このようなメソッドのことを「静的メソッド」と言います。静的メソッドを定義するには、メソッド定義の先頭にstatic修飾子を付加するだけです。
・MyClass.class.php <?php class MyClass{ public static function triangle ($width, $height){ return $width * $height / 2; } } ?>クラス外部から静的メソッドを呼び出すには、一般的なメソッド、プロパティを呼び出す「->」演算子ではなく、「::」演算子を使用します。
・static.php <?php require_once('MyClass.class.php'); print('三角形の面積は' . MyClass::triangle(10,5) . 'です<br>'); ?>「::」演算子を利用することでオブジェクト変数名でなくクラス名から直接的にメソッドを呼び出すことが可能となります。ではなぜこのように、インスタンス化を必要とするメソッドとそうでないメソッドが存在するのかというと、それは、外部から与えられた値を処理し出力するだけということだけをしているからです。クラス内でプロパティとしてデータを留めることなくメソッドとしてだけ処理し呼び出し元に返すだけのいわゆる関数的な処理を求められているのでわざわざオブジェクトをつくらなくとも、データの上書き(不整合)が発生しないためです。そもそも、静的メソッドでは、クラス内にプロパティ(データ)を設定もとい参照しようにもプロパティ自体が存在しないのでできません。$this命令も当然ながら使えません。 TOP
クラス内定数
クラス内定数とは、その名の通りclassブロックの中で定義された定数のことです。PHP5からはconst命令を利用することでクラス内部で定数を定義することができます。
<?php class MyClass { const AUTHOR = '名無し'; } print('著者名:' . MyClass::AUTHOR); ?>クラス内定数を参照するには静的メソッド同様、「::」演算子を使います。クラス内定数を利用すると、特定のクラスでしか利用しない定数をクラス内部で管理でき、クラス外部に出さなくて済むのでより分かりやすいコードを記述することができます。 TOP
継承
継承とは、クラスに含まれるプロパティやメソッドを引き続きながら新たな機能を追加したり、元の機能を一部だけ修正することができる機能のことです。必要に応じ元になるクラスの機能を引き継ぎつつ機能追加、変更などの新しいクラスをつくる場合に使われます。継承の際、基になるクラスのことを「スーパークラス(親クラス、基底クラス)」と呼び、継承の結果できたクラスのことを「サブクラス(子クラス、派生クラス)」と呼びます。
<?php class サブクラス名 extends スーパークラス名 { サブクラスの処理定義 } ?>継承によりスーパークラスの機能をサブクラスで上書きすることを「オーバーライド」と言います。オーバーライドされなかったスーパークラスのメソッドはサブクラスでもそのまま引き継がれ、あたかも自分自身で定義したメソッドであるかのように利用できます。
<?php class MyClass { protected $data; public function __construct($data) { $this->data = $data; } public function showData() { return '入力値は「'.$this->data.'」です。'; } } class MySubClass extends MyClass { public function showData(){ return '***入力値は「'.$this->data.'」です。***'; } } $obj=new MySubClass ('PEAR'); print($obj->showData()); ?> [出力] ***入力値は「PEAR」です。***TOP
parent命令
同じくオーバーライドするにも、スーパークラスの機能を完全に塗り替えるのではなく、スーパークラスの機能を受け継ぎながらサブクラス側で機能を追加したいという場合があります。そのような場合にはparent命令でスーパークラスのメソッドを呼び出すことも可能です。parent命令を利用するとサブクラスでスーパークラスのメソッドを少しだけ改変したいと思った場合でもそれを最初から書き直す必要はなくなります。スーパークラスのメソッドの戻り値を利用しつつ必要な部分だけを修正するということが可能になります。
<?php class MyClass { protected $data; public function __construct($data){ $this->data=$data; } public function showData(){ return '入力値は「'.$this->data.'」です。'; } } class MySubClass extends MyClass { public function showData(){ return '***'.parent::showData().'***'; } } $obj=new MySubClass('PERA'); print($obj->showData()); ?>TOP
final修飾子
final修飾子は特定のメソッドをオーバーライドできないように制限するための修飾子です。継承をすることを想定していないメソッドについてはfinal修飾子をつけることで不用意にオーバーライドされることを防ぐことができます。
<?php class MyClass { protected $data; public function __construct($data){ $this->data=$data; } public final function showData(){ return '入力値は「'.$this->data.'」です。'; } } class MySubClass extends MyClass{ public function showData(){ return '***入力値は「'.$this->data.'」です。***'; } } ?> [出力] Fatal error: Cannot override final methot MyClass::showData() in filan.phpTOP
ポリモーフィズム
ポリモーフィズムとは同名のメソッドで異なる挙動を実現することをいいます。ポリモーフィズムのメソッドは、同じ目的の機能に同名のメソッドを割り当てることができるということです。これは一連の関連するクラスを利用する場合に、異なるメソッド名を覚えなくていいため、利用者にとって利便性が増します。実装には、単なる継承とオーバーライドだけではそれぞれのサブクラスが同名のメソッドを持つことが必ずしも保証できないため、抽象メソッドという概念をPHPの場合利用します。
・polymorphism.php <?php class Figure { protected $width; protected $height; public function __construct($width, $height){ $this->width=$width; $this->height=$height; } protected function getArea(){} } class Triangle extends Figure { public final function getArea(){ return $this->width * $this->height / 2; } } class Square extends Figure { public final function getArea(){ return $this->width * $this->height; } } $tri = new Triangle(10, 5); $sqr = new Square(10, 5); print('三角形の面積は'.$tri->getArea().'です。<br>'); print('四角形の面積は'.$sqr->getArea().'です。<br>'); ?> [出力] 三角形の面積は25です。 四角形の面積は50です。TOP
抽象メソッド
抽象メソッドとは、メソッド定義の先頭にabstract修飾子を付加したメソッドであり、抽象メソッド自体は動作を定義しない空のメソッドです。抽象メソッドは、サブクラスで必ずオーバーライドしなければいけません。クラス内の抽象メソッドがサブクラスで必ずオーバーライドされていなければそのクラスはインスタンス化できません。これにより、同名のメソッドがサブクラスで再定義されることを保証します。抽象メソッドの定義では、中身が空であっても { } のようなブロックを定義しません。
また、抽象メソッドを含むクラスのことを抽象クラスといい、classキーワードの前にabstract修飾子を付加する必要があります。抽象クラスのサブクラスが抽象メソッドをすべてオーバーライドしていない場合、エラーが出ます。
・abstract.php <?php abstract class Figure { protected $width; protected $height; public function __construct($width, $height){ $this->width = $width; $this->height = $height; } protected abstract function getArea(); } class Triangle extends Figure { public final function getArea() { return $this->width * $this->height / 2; } } class Square extends Figure { public final function getArea() { return $this->width * $this->height; } } $tri = new Triangle(10, 5); $sqr = new Square(10, 5); print('三角形の面積は'.$tri->getArea().'です。<br>'); print('四角形の面積は'.$sqr->getArea().'です。<br>'); ?>TOP
インターフェイス
抽象クラスによるポリモーフィズムの実現には問題もあります。それは、PHPでは多重継承、つまり、サブクラスが同時に複数のスーパークラスを継承できないという点です。この性質を単一継承といいます。多重継承ができないということはポリモーフィズムを実現したいすべての機能(メソッド)をひとつの抽象クラスに含めなければいけないことを意味します。これは必ずしもサブクラスがスーパークラスの機能を必要としない場合でも、機能をオーバーライドしなければならなくなり、当然、コードは冗長になります。コードが冗長になるということはサブクラスの役割が分かりにくくする一因をつくることにつながります。そこで、PHPでは、インターフェイスを利用します。インターフェイスとは配下のメソッドがすべて抽象メソッドである特別なクラスを言います。インターフェイスを定義する場合には、classキーワードの代わりにinterfeceキーワードを使用します。また、配下のメソッドが抽象メソッドであることはinterfeceキーワードから明らかなので個々のメソッドにはabstract修飾子は必要ありません。
インターフェイスとクラスとの決定的な違いはいわゆる多重継承が可能になるということです。インターフェイスを採用することにより、サブクラス側では必要なメソッドを含むインターフェイスを選択し継承することが可能となります。このとき、インターフェイスの機能を受け継ぐことは「継承する」ではなく「実装する」と言います。インターフェイスを実装する場合には、extendsキーワードの代わりにimplementsキーワードを使用します。インターフェイスを実装したクラスのことを「実装クラス」といいます。また、複数のインターフェイスを実装する必要がある場合には、インターフェイス名をカンマ区切りで記述します。
・Figure.class.php <?php interface Figure { public function getArea(); } ?> ・interface.php <?php require_once('Figure.class.php'); class Triangle implements Figure { private $width; private $height; public function __construct($width, $height){ $this->width = $width; $this->height = $height; } public final function getArea(){ return $this->width * $this->height / 2; } } class Square implements Figure { private $width; private $height; public function __construct($width, $height){ $this->width = $width; $this->height = $height; } public final function getArea(){ return $this->width * $this->height; } } $tri = new Triangle(10, 5); $sqr = new Square(10, 5); print('三角形の面積は'.$tri->getArea().'です。<br>'); print('四角形の面積は'.$sqr->getArea().'です。<br>'); ?>TOP
__autoload関数
PHP5では、オブジェクト指向構文が強化され、限りなくJAVAライクなオブジェクト指向プログラミングが可能になりました。さらに、PHP5では独自で使える構文規則も追加されています。そのひとつがautoload関数です。もともとクラスは複数のスクリプトから再利用されるというその性質上、1クラス1ファイルで管理することが望ましいとされています(ただ、短いプログラムなどは可読性を考慮して設計されていることもあるので例外はあります)。1クラス1ファイルなら、無駄なクラスを読み込む必要もありませんし、ファイル管理という観点からも整理しやすくなります。ただ、1クラス1ファイル方式で作成していくと扱うクラスが増えてきた場合にひとつひとつのクラスファイルについてinclude_once関数やrequire_once関数を記述することが大きな手間になりますし、記述漏れや誤りの原因にもなります。そこで役に立つのが__autoload関数です。
__autoload関数は、未定義クラスを呼び出したタイミングで自動的に呼び出される特別な関数であり、呼び出した未定義のクラスの名前が引数として渡されます。__autoload関数は、それ自体はなんら実装を持たない名前だけ予約された関数です。一般的には、「クラス名.class.php」のような形式であらかじめファイル名に一定の規則性を設けた上で、__autoload関数内でrequire_once関数を呼び出し、クラスが呼び出されたタイミングで自動的に同名のクラスファイルをインクルードするような用途で使用します。
__autoload関数を利用すると、クラスごとにrequire_once関数を呼び出す必要がなくなるので、コードがシンプルになります。また、スクリプト内で使用するかどうか分からないクラスをインクルードしなくても済むので処理上のオーバーヘッドが軽減します。なお、__autoload関数を定義したスクリプトは、その性質上、アプリケーション内のすべてのスクリプトで有効にしておくことをお勧めします。アプリケーション配下のファイルに対してautoload.phpを自動的に読み込むためには、.htaccessファイルを利用します。
・autoload.php <?php function __autoload($name){ require_once($name . '.class.php'); } ?> ・auto_load.php <?php require_once('autoload.php'); $obj = new MyClass(); $obj -> width = 10; $obj -> height = 5; print('三角形の面積は'.$obj->triangle().'です。<br>'); ?>TOP
.htaccess
.htaccessファイル(先頭にドットがつく。UNIX系列では先頭にドットがつくファイルは隠しファイル属性の意味になる)は、Apache標準の設定ファイルで、ドキュメントルート配下の任意のディレクトリに配置することで、該当するディレクトリと、その配下のサブディレクトリに対してだけ適用されるパラメータを設定することができます。php.iniを利用するとサーバー全体に対して設定が適用されてしまいますが、このように特定のアプリケーションに対して設定を適用したいという場合は、.htaccessを利用します。書式は以下のとおりです。
<IfModule mod_php5.c> php_value パラメータ名 パラメータ値 php_flag パラメータ名 on | off <IfModule>パラメータ値がonまたはoffで表される場合には、php_flagを、それ以外の値である場合にはphp_valueを使用します。php_value,php_flagは必要な数だけ記述できます。また、.htaccessでPHPの設定を行う場合には、次の2点について注意する必要があります。
http.confのAllowOverrideディレクティブを"All"に設定
AllowOverrideディレクティブは、.htaccessファイルによるパラメータの上書きを可能にするかどうかを決めるためのパラメータです。AllowOverrideディレクティブが"None"に設定されている場合は.htaccessファイルは無視されます。
.htaccessファイルで設定可能なパラメータは決まっている
.htaccessファイルでは、すべてのphp.iniのパラメータを設定できるわけではありません。パラメータによっては、php.iniでしか設定できないものがあるので注意してください。どのパラメータが.htaccessファイルで設定可能かは、ini_get_all関数のaccess情報を参照することで確認できます。アクセスレベルが6または7である場合、そのパラメータは.htaccessで設定可能です。
<? print '<PRE>'; print_r(ini_get_all()); print '</PRE>'; ?> [出力] Array ( [allow_call_time_pass_reference] => Array ( [global_value] => 1 [local_value] => 1 [access] => 6 ) 中略 )TOP
__callメソッド
__callメソッドは、未定義のメソッドが呼び出された場合の挙動を定義するためのメソッドです。__autoload関数と同様PHP5独自のものであり、それ自体はなんら実装を持たない名前だけ予約されたメソッドですので必要に応じて中身を実装する必要があります。__callメソッドは引数として、メソッド名と引数値の配列を受け取ることができます。変わり種の機能ではありますが、メソッド名に応じて共通的な処理を分岐したいなどのケースで利用できるでしょう。
<?php class MyClass{ public function __call($name,$args){ print('メソッド名:'.$name.'<br>'); print_r($args); } } $obj = new MyClass(); $obj -> nothing('x','y'); ?> [出力] メソッド名:nothing Array ( [0] => x [1] => y )TOP
__get,__setメソッド
__get,__setメソッドは、未定義のプロパティを取得・設定しようとしたタイミングで呼び出されるメソッドです。__autoload関数と同様PHP5独自のものであり、それ自体はなんら実装を持たない名前だけ予約されたメソッドですので必要に応じて中身を実装する必要があります。__getメソッドは、取得しようとした未定義のプロパティの名前を引数として受け取ります。__setメソッドは、設定しようとした未定義のプロパティの名前と値を引数として受け取ります。これらのメソッドを使用して、未定義のプロパティが参照されたときの処理を記述します。
<?php class MyClass{ public function __get($name){ print($name . 'プロパティが参照されました。<br>'); } public function __set($name, $value){ print($name . 'プロパティ値' . $value . 'がセットされました。<br>'); } } $obj = new MyClass(); $obj -> nobody = 1; print($obj->nobody); ?> [出力] nobodyプロパティ値1がセットされました。 nobodyプロパティが参照されました。TOP