【初心者向け】PHPの可視性(public・private・protected)を徹底解説
はじめに
PHPでは、classキーワードを使ってユーザー定義の複合データ型(クラス)を作成できます。クラスから生成される新しいインスタンスが「オブジェクト」であり、その特性はクラスの定義に従います。クラスには、プロパティ(メンバ変数)、定数、メソッドといったメンバを含めることができます。
クラスメンバへのアクセス範囲(アクセス権)は、定義時に付与する「可視性」キーワードによって決まります。PHPには次の3つの可視性キーワードがあります。
- public:どこからでもアクセス可能
- protected:そのクラス自身と、それを継承した子クラスからのみアクセス可能
- private:そのメンバが定義されたクラス自身からのみアクセス可能。外部からは一切見えない
プロパティの可視性
プロパティはクラスインスタンスの属性です。オブジェクトごとに異なる値を持つインスタンスプロパティと、すべてのオブジェクトで共通の値を持つクラスプロパティがあります。プロパティには任意の有効なPHPデータ型を指定でき、デフォルトの可視性はpublicです。なお、現在は非推奨となっているvarキーワードで定義されたプロパティは、publicとして扱われます。
例
<?php
class myclass{
public $fname="Ajay";
var $lname; // publicとして扱われる
private $marks=100;
protected $age=20;
}
$obj=new myclass();
echo "$obj->fname\n";
$obj->lname="Diwan";
echo "$obj->marks\n";
$obj->age=21;
?>出力結果
この出力から、publicプロパティはクラス外からアクセスできる一方、privateおよびprotectedプロパティにアクセスすると未捕捉のエラー(Fatal error)が発生することがわかります。
Ajay PHP Fatal error: Uncaught Error: Cannot access private property myclass::$marks PHP Fatal error: Uncaught Error: Cannot access protected property myclass::$age
※ 実際にはFatal errorが発生した時点でスクリプトの実行は停止するため、上記はprivateとprotectedへのアクセスをそれぞれ個別に実行した場合の出力です。
ただし、privateやprotectedのプロパティも、同じクラス内のメソッドからであれば自由に利用できます。
例
<?php
class myclass{
public $fname="Ajay";
var $lname;
private $marks=100;
protected $age=20;
function displaydata(){
$this->lname="Diwan";
echo "$this->fname $this->lname\n";
echo "marks=$this->marks age=$this->age";
}
}
$obj=new myclass();
$obj->displaydata();
?>出力結果
Ajay Diwan marks=100 age=20
メソッドの可視性
クラスのプロパティと同様に、メソッドにもpublic・private・protectedの各キーワードで可視性を設定できます。メソッドもデフォルトではpublicとして扱われます。
例
<?php
class myclass{
public $fname="Ajay";
var $lname;
private $marks=100;
protected $age=20;
public function setname(){
$this->fname="Anil";
$this->lname="Dave";
echo "name changed\n";
}
private function setmarks(){
$this->marks=90;
}
protected function setage(){
$this->age=21;
}
function setdata(){
$this->setname();
$this->setmarks();
$this->setage();
}
function displaydata(){
$this->lname="Diwan";
echo "$this->fname $this->lname\n";
echo "marks=$this->marks age=$this->age";
}
}
$obj=new myclass();
$obj->setname();// OK
$obj->setmarks();// エラー
$obj->setage(); // エラー
$obj->setdata(); // publicメソッド内からprivate/protectedメソッドを呼び出し
$obj->displaydata();
?>出力結果
name changed PHP Fatal error: Uncaught Error: Call to private method myclass::setmarks() from context '' PHP Fatal error: Uncaught Error: Call to protected method myclass::setage() from context '' Anil Dave marks=90 age=21
※ 上記のエラー行は、それぞれの呼び出しを個別に実行した場合の出力です。setdata()経由であれば、クラス内部からの呼び出しとなるためエラーにはならず、最後の2行が出力されます。
継承におけるメソッドの可視性
親クラスのメソッドは、子クラスの定義内でオーバーライド(上書き)できます。親クラスのprivateおよびprotectedメソッドは、子クラスのオブジェクトから直接呼び出すことはできません。ただし、親クラスでprotectedとして定義されたメソッドは、子クラスのメソッド内であれば使用できます。
例
<?php
class testclass{
public $x=10;
private $y=20;
protected $z=30;
private function test(){
echo "testclass private method\n";
}
public function test1(){
echo "testclass public method\n";
}
protected function test2(){
echo "testclass protected method\n";
}
function test3(){
echo "x=$this->x y=$this->y z=$this->z\n";
}
}
class newclass extends testclass{
function test1(){
echo "newclass public method\n";
}
public function test4(){
$this->test();
$this->test1();
$this->test2();
}
}
$obj=new newclass();
echo $obj->test1();
echo $obj->test3();
echo $obj->test4();
?>出力結果
newclass public method x=10 y=20 z=30 PHP Fatal error: Uncaught Error: Call to private method testclass::test() from context 'newclass'
※ 子クラスnewclassのメソッド内からは、親クラスのprivateメソッドtest()を呼び出せないためエラーになります。一方、protectedメソッドtest2()は子クラス内から呼び出し可能です。
定数の可視性
PHP 7.1以降では、クラス定数にも可視性キーワードを指定できるようになりました。定数のデフォルトの可視性はpublicです。
例
<?php
class testclass{
public const X=10;
private const Y=20;
protected const Z=30;
function showconst(){
echo "x=" . self::X ;
echo "y=" . self::Y;
echo "z=" . self::Z ;
}
}
$obj=new testclass();
$obj->showconst();
echo testclass::Y . "\n";
echo testclass::Z . "\n";
?>出力結果
x=10y=20z=30 PHP Fatal error: Uncaught Error: Cannot access private const testclass::Y PHP Fatal error: Uncaught Error: Cannot access protected const testclass::Z
まとめ
可視性キーワードによるアクセス範囲の違いを整理すると、以下の表のようになります。
| キーワード | クラス自身 | 継承クラス | クラス外 |
|---|---|---|---|
| public | ○ | ○ | ○ |
| protected | ○ | ○ | × |
| private | ○ | × | × |
適切な可視性を設定することで、クラス内部の実装を隠蔽し、意図しない操作からオブジェクトの状態を守る「カプセル化」を実現できます。公開が必要なメンバだけをpublicにし、それ以外はprotectedやprivateで保護するのが、堅牢なオブジェクト指向設計の基本です。
-
PHPのclass_exists()関数とは?使い方とサンプルコードをわかりやすく解説
概要PHPのclass_exists()関数は、指定したクラスがすでに定義されているかどうかをチェックするための関数です。クラスが定義済みであればTRUEを、未定義であればFALSEを返します。プラグインの読み込みや条件分岐によるクラスの動的な利用など、柔軟なプログラミングに役立ちます。構文class_exists(class, autoload)パラメータclass − 存在を確認したいクラスの名前。autoload − デフォルトでオートロード機構(__autoload / spl_autoload_call)を呼び出すかどうか。省略した場合のデフォルト値はTRUE
-
C#の静的クラス(static class)とは?特徴と使い方を実例で解説
C#における静的クラス(static class)は、インスタンス化できない特殊なクラスです。静的クラスには静的メンバーのみを持たせることができ、インスタンスメンバーを定義することはできません。また、静的クラスは自動的にシールクラス(sealed)として扱われるため、継承することもできません。さらに、インスタンスコンストラクターを含めることはできませんが、静的コンストラクターを定義することは可能です。静的クラスの主な特徴newキーワードによるインスタンス化ができない静的メンバー(staticメンバー)のみを持つことができる暗黙的にsealedとして扱われ、継承できないインスタンスコンストラクタ