本記事では、
PHPのアクセス修飾子(public, protected, private)の違いについて解説していこうと思う。
PHPも他のオブジェクト指向言語と同様に、クラスやメソッドにアクセス修飾子を指定することができる。
アクセス修飾子を適切に設定することで、より安全性の高いプログラムとすることができるので、本記事をきっかけに理解を深めてもらえれば幸い。
PHPのアクセス修飾子の違い
PHPのアクセス修飾子それぞれの違いは次のようになる。
それぞれの修飾子のアクセス制御を理解する上で、前提としてしっかり理解しておきたい場所の概念として、大別すると「クラス外」と「クラス内」がまず存在する。
そして、クラスには「継承」というものが存在するので、クラスを「継承元」と「継承先」に分別する必要がある。
すなわち、全部で「継承元クラス」「継承先クラス」「クラス外」の、3つの場所的関係があることを理解しておこう。

public
どこからでもアクセス可能な修飾子。
アクセス修飾子がない場合は、publicを指定したものと同じになる。
public $var;
public function testfunc() {
}
※「どこからでも」と説明上分かりやすくするために記述したが、違いを理解するためには、「クラスの外からでも」と理解しておこう。理由は全てのアクセス修飾子は、クラス内部からアクセス可能だからだ。
protected
そのクラス自身と継承クラスからアクセス可能な修飾子。
クラス外からはアクセスできない。
protected $var;
protected function testfunc() {
}
private
同じクラスの中でのみアクセス可能な修飾子。
クラス外、および継承関係にあるクラスからもアクセスできない。
private $var;
private function testfunc() {
}
サンプルコード
4つのメソッドを持つクラスを定義して、それぞれにアクセス修飾子をつける。
protectedの挙動を確かめるために継承クラスも用意する。
サンプルコード(クラス外からアクセス可能:public)
まずは、publicの修飾子について、
new()したオブジェクトからアクセスしてみて、アクセス可能であることを確認する。
class Super {
public function publicFunc(){
echo "Public\n";
}
}
$super = new Super;
$super->publicFunc();
実行結果
Public
特に問題なく、クラスの外からアクセス可能だ。
サンプルコード(Superクラス)
class Super {
protected function protectedFunc(){
echo "Protected\n";
}
private function privateFunc(){
echo "Private\n";
}
}
$super = new Super;
$super->protectedFunc(); // エラー
$super->privateFunc(); // エラー
privateとprotectedのメソッドにアクセスしようとしているのでエラーとなる。
サンプルコード(クラス外からアクセス可能 ※継承関係:protected)
最後にSuperクラスを継承したSubクラスからメソッドにアクセスしてみる。
class Super {
protected function protectedFunc(){
echo "Protected\n";
}
private function privateFunc(){
echo "Private\n";
}
}
class Sub extends Super {
public function publicFunc(){
parent::protectedFunc();
}
}
$sub = new Sub();
$sub->publicFunc();
実行結果
Protected
上記サンプルコードで注目する点は、異なるclassなのにも関わらず、継承関係にあるクラスのprotectedのメソッドには継承先クラスからアクセスが可能となっている点だ。
先ほど、単純なクラス外からのアクセスでエラーとなっていたprotectedのメソッドだが、protectedのメソッドを定義しているSuperクラスを継承しているSubクラスからはアクセス可能となっているのが、上記コードから確認できると思う。
どのアクセス修飾子を使うべきか
アクセス修飾子を指定せず、すべてをpublicにしてもプログラムの動作に支障はありません。
まずprivateにできないか考える
覚えておきたいプログラムを書く上での大原則として、
「まずはprivateにできないかを考える」というのを覚えておこう。
理由は、可能な限りアクセス権限を制限しておくことで、より安全性の高いプログラムを書くことが可能だからだ。プログラムの安全性を高めるためには、privateにできるものはprivateにしたほうが、開発者目線でも、ユーザ目線でも、思わぬバグの発生を未然に防ぐことができる。特にプロパティは、外部から変更されると困るというケースが多いので、まずはprivateで実装することを考慮し、getterやsetterと言った同クラス内のpublicなメソッドを介してアクセスすると言った手法をとるように心がけよう、それがスタンダードだ。
getter, setterメソッドをつくる
上記で少し触れたが、プロパティはprivateにして、プロパティを取得するメソッドと変更するメソッド(いわゆるgetter, setter)を作成し、そのメソッドでプロパティのバリデーションをするなどの手法が取られることが多い。
一見「二度手間では?最初からpublicなプロパティにすれば良くない?」と思うだろうが、筆者も実際のところ(そう言った場面を経験していないので)良く分からないが、publicにしておくということは、全てのアクセスを許可するということなので、便利な反面、思わぬ値の書き換えが起こってしまったりと、安全性の面で問題があるということなのだ。便利さと安全性を天秤にかけた時、通常、プログラミングでは安全性が優先されるため。なるべくgetterとsetterをprivateなプロパティと同じクラスに用意して、それらを仲介してprivateなプロパティにアクセスするよう心がけよう。
https://www.php.net/manual/ja/language.oop5.visibility.php
public :どこからでもアクセス可能な修飾子
protected:そのクラス自身と継承クラスからアクセス可能な修飾子
private :同じクラスの中でのみアクセス可能な修飾子