第3章 アクセス修飾子とカプセル化
3.1 メンバのアクセスを制限する
前章では雛形であるクラスを用いて、オブジェクトを生成する方法を学習してきました。本節では、実際にアクセス制限を行う簡単なプログラムを作成し、「クラスメンバへのアクセスを制限する」方法ついて説明していきます。
3.1.1 メンバ変数に直接アクセスする方法
アクセス制限の方法を知る前に、今まで作成していたアクセス制限の無いプログラムを再確認します。
以下のフィールド変数に直接アクセスするプログラムを見て下さい。
ソースコード
ソース・フォルダー :myproj_framework_basic/ch03
ファイル名 :directAccessObjectVariable.php
アクセスURL :http://localhost/myproj_framework_basic/ch03/directAccessObjectVariable.php
➢ directAccessObjectVariable.php
<?php // クラスの定義作成 class Computer1{ public $os; public $memory; // フィールド変数の値を表示するメソッド public function show(){ echo "パソコンのOSは「" . $this->os . "」です。<br>"; echo "メモリサイズは「" . $this->memory . "MByte」です。<br>"; } } // Computer1クラスからオブジェクトを生成する $com = new Computer1(); // フィールド変数に直接アクセスし代入 $com->os = "WindowsXP"; $com->memory = 2048; ?> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>メンバ変数に直接アクセス</title> </head> <body> <?php // 画面出力 $com->show(); ?> </body> </html>
このプログラムでは呼び出し元でフィールド変数に直接アクセスし、OS名やメモリサイズの値を代入しています。パソコンのOSを「WindowsXP」、メモリサイズを「2048」と設定(代入)しているわけですが、この処理では問題が起きてしまう場合があります。
例えば、DirectAccessObjectVariableの呼び出し元の方で以下のような記述ができてしまいます。
抜粋したこの下記のコードは何を意味しているでしょうか。これまで学習してきた内容で考えると、変数$comが指すオブジェクトのフィールド変数memoryの値を-5445と設定するという処理が行われています。しかし、この処理はおかしな状況です。本来パソコンはメモリのサイズをマイナス値にすることはありません。
本来ならば、このような不具合がおこならないように、様々な仕組みを組み込んでいきます。
ではその仕組みについて次の項より1つずつみていきましょう。
3.1.2 メンバにprivate修飾子をつける
前項のdirectAccessObjectVariableでメモリサイズにマイナスな値が入ってしまう誤りは何が原因だったでしょうか。その原因はメンバに制限なくアクセスし、勝手な値(ここでは-5445)を代入してしまったことにあるといえます。PHPプログラミングではこのような間違いをおこさせないように、クラスの外からメンバに自由にアクセスできない仕組みを設けることが可能です。そのようなクラスの外から直接アクセスできないメンバのことをprivateメンバと言います。
ではどのように設定するか基本構文を以下に紹介します。
書式:privateメンバ
フィールド変数やメソッドにprivate修飾子をつけることにより、他のクラスからのアクセスを禁止し、自身のクラス内からしかアクセスできない特徴を持ちます。
凡例:privateメンバ
前節で示したサンプルのクラス「Computer1」を例にします。
privateメンバは定義するのは至って簡単です。これまでクラスで定義してきたフィールド変数やメソッドの頭にpublicではなくprivateと記述するだけです。では次の項でサンプルを使って説明していきます。
3.1.3 フィールド変数にprivate修飾子をつけたプログラム
privateメンバに直接アクセスし、実際にメンバにはアクセスできないことを確認します。
ソースコード
ソース・フォルダー :myproj_framework_basic/ch03
ファイル名 :privateMember.php
アクセスURL :http://localhost/myproj_framework_basic/ch03/privateMember.php
➢ privateMember.php
<?php // クラスの定義作成 class Computer2{ private $os; private $memory; // フィールド変数の値を表示するメソッド public function show(){ echo "パソコンのOSは「" . $this->os . "」です。<br>"; echo "メモリサイズは「" . $this->memory . "MByte」です。<br>"; } } // Computer2クラスからオブジェクトを生成する $com = new Computer2(); // フィールド変数に直接アクセスし代入 $com->os = "WindowsXP"; $com->memory = -5445; ?> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title> private修飾子のフィールド変数</title> </head> <body> <?php $com->show(); ?> </body> </html>
実行結果
以下のような実行時エラーが出力されます。
解説
Computer2クラス内の4、5行を見るとフィールド変数($os,$memory)がprivateメンバになっています。これにより呼び出し元の18行と19行で、フィールド変数にはアクセスすることができなくなっています。Computer2 クラスのフィールド変数を「private」にしたことによりクラスの外側からはアクセスすることができなくなります。
図 3.1.1: メンバアクセス制限
さて、メンバをprivateにすることで、不正な値が設定されることはなくなりましたが、このままで良いのでしょうか?不正な値の設定を防ぐと同時に、値の設定自体もできなくなってしまいました。このままでは値の変更を行いたい場合にアクセスする手段がありません。そのような場合にPHPプログラミングではどのようにして行うかを、次の項で説明していきます。キーワードはこれまで目にしてきている「public」になります。
3.1.4 メソッドにpublicをつける
メンバをprivateにすることで不正なアクセスを禁止できました。しかし正常な値を設定したい場合の手段も同時に失ってしまいました。そのような場合、PHPプログラムでは「正常な値」を「正しい手続きに従い」行える操作(メソッド)を用意します。このメソッドはprivateにしたメンバと、他のクラスからのアクセスを繋ぐためのメソッドになるため、どこからでもアクセスが可能なpublicをつけます。このような他の全てのクラスからアクセスできるメソッドをpublicメソッドと呼びます。
「public」というキーワードはこれまで意識せずに目にしてきている筈ですが、改めて基本構文を紹介します。
書式:publicメソッド
メソッドにpublic修飾子をつけることにより、どこからでもアクセスできる特徴を持ちます。
凡例:publicメソッド
publicメソッドも定義するのは至って簡単です。クラスで定義してきたメソッドの頭にpublicと記述するだけです。では次の項でサンプルを使って説明していきます。
アクセス修飾子について
これまでの範囲で学習した「private」、「public」を総称してアクセス修飾子と呼びます。この他には「protected」があり、それぞれアクセス制限の範囲が異なります。
なお、PHPではフィールド変数のアクセス修飾子を省略することはできません。
3.1.5 メソッドにpublic修飾子をつけたプログラム
publicメソッドを利用して、クラス内のprivateフィールド変数に値を設定します。
直接値を設定することのできないprivateフィールド変数に、publicメソッドを利用することで値を設定できることを確認しましょう。
ソースコード
ソース・フォルダー :myproj_framework_basic/ch03
ファイル名 :publicMember.php
アクセスURL :http://localhost/myproj_framework_basic/ch03/publicMember.php
➢ publicMember.php
<?php // クラスの定義作成 class Computer3{ private $os; private $memory; // publicメソッドshow public function show(){ echo "パソコンのOSは「" . $this->os . "」です。<br>"; echo "メモリサイズは「" . $this->memory . "MByte」です。<br>"; } // publicメソッドsetOsMemory public function setOsMemory($os, $memory){ // 設定するメモリの値が正常か判定 if($memory > 0){ // 正常な引数の値をフィールド変数に設定 $this->os = $os; $this->memory = $memory; echo "OSを「" . $os . "」に、メモリサイズを「" . $memory . "MByte」に変更しました。<br>"; } else{ echo "「" . $memory . "」は正しいメモリサイズではないため、変更は行いません。<br>"; } } } // Computer3クラスからオブジェクトを生成する $com = new Computer3(); // 他クラス内のprivate変数にはアクセスできないので以下2行はコメントアウト //$com->os = "WindowsXP"; //$com->memory = -5445; ?> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>public修飾子のメソッド</title> </head> <body> <?php // 正しい値を正式な操作を呼び出して設定 $com->setOsMemory("WindowsXP", 2048); // publicメソッドsetOsMemoryを呼び出して値を設定 $com->show(); // publicメソッドshowを呼び出す // 不正な値を設定しようとしてみる echo"<br>メモリに不正な値(-5445)を指定してみます。<br>"; $com->setOsMemory("WindowsXP", -5445); $com->show(); ?> </body> </html>
実行結果
解説
「Computer3」クラスのフィールド変数は「private」になっているので31、32行のような直接アクセスはできません。今回のプログラムでは実行時エラーを出さない為にコメントアウトしています。
42行でsetOsMemoryメソッドに正しい値「WindowsXP、2048」を引数に与えてアクセスし、43行のshowメソッドで結果を画面に表示しています。このsetOsMemoryメソッドは引数の値をチェックして、問題なければフィールド変数に設定する機能を持っています。
publicメンバにはどこからでも自由にアクセスができ、privateメンバは同一クラス内の処理からなら自由にアクセスできるため、値の変更、参照が可能になります。
図 3.1.2: アクセス修飾子とメンバアクセスの関係
47行目では$memoryに設定する値を不正な数値で設定しています。setOsMemoryメソッド内では第2引数の$memoryの値が「正の値」でなければフィールド変数に設定しないため、今回($memoryが負の数(-5445))は変更が行われません。
結果48行目のshowメソッド呼び出しでは結果が変わっていないことが確認できます。
一般的に、今回のサンプルのようにクラスの外から自由にアクセスさせるメンバには「public」、そうでないメンバ(主にフィールド変数)には「private」を設定します。フィールド変数にprivateを設定することで、不正なアクセスを防ぎ、フィールド変数に値を設定したければ正規の操作にあたるpublicメソッドを呼び出すことで不正な値も防ぐことができるようになる仕組みです。
このように、クラスの中に属性(フィールド)と機能(メソッド)をひとまとめにし、保護したいメンバに「private」をつけて自由にアクセスできなくする仕組みをカプセル化と呼びます。カプセル化については3.3節で詳しく紹介します。