ITHACK
~ みんなのIT部門 ~

【PHP】アクセス修飾子とオーバーライド – privateはオーバーライドできない

アクセス修飾子よってオーバーライドできるメソッドが制限されます。
ここではオーバーライドとアクセス修飾子の関係性について解説します。

なお、継承・オーバーライド・アクセス修飾子については次の記事をご覧ください。

  • アクセス修飾子とオーバーライドの関係性

アクセス修飾子とオーバーライド

アクセス修飾子によってオーバーライドできるメソッドは制限されます。
主に次の2つが制限されます。

  1. オーバーライドできるかどうか
  2. オーバーライドしたメソッドのアクセス修飾子

1. オーバーライドできるかどうか

privateなメソッドはオーバーライドできません。
サブクラスでオーバーライドできるメソッドはスーパークラスのpublicまたはprotectedなメソッドのみになります。

2. オーバーライドしたメソッドのアクセス修飾子

メソッドをオーバーライドする場合、アクセス修飾子はスーパークラスのものより、厳しくすることができません。

アクセス修飾子はprivate>protected>publicの順で制限されており、例えば、スーパークラスがprotectedの場合、サブクラスではpublicまたはprotectedのアクセス修飾子のみでオーバーライドできます。

アクセス修飾子とオーバーライドの関係性をまとめると次の表のようになります。

スーパークラスのアクセス修飾子 public protected private
オーバーライド ×
オーバーライドした
メソッドの
アクセス修飾子
public public
protected
public
protected
private

スーパークラスのprivateなメソッドに対するサブクラスのアクセス修飾子は全て使うことができますが、これはそもそもオーバーライドにならないためです。

privateなメソッドと同じ名前のメソッドを定義しても、それはオーバーライド(再定義)ではなく、『新しいメソッドを定義した』とみなされます。

検証コード

アクセス修飾子とオーバーライドの関係性についてコードで確認しましょう。

<?php

class AccessOverride {
    
    public    function method_public()    { echo "method_public        : SUCCESS!\n"; }
    protected function method_protected() { echo "method_protected     : SUCCESS!\n"; }
    private   function method_private()   { echo "method_private       : SUCCESS!\n"; }
    
    public function execute() {
        $this->method_public();
        $this->method_protected();
        $this->method_private();
    }
}

class SubAccessOverride extends AccessOverride {
    
    public    function method_public()    { echo "sub_method_public    : SUCCESS!\n"; }
    protected function method_protected() { echo "sub_method_protected : SUCCESS!\n"; }
    private   function method_private()   { echo "sub_method_private   : SUCCESS!\n"; }
    
}

$test = new SubAccessOverride();
$test->execute();

?>
sub_method_public    : SUCCESS!
sub_method_protected : SUCCESS!
method_private       : SUCCESS!

このコードではAccessOverrideクラスをSubAccessOverrideクラスで継承し、各メソッドをオーバーライドしています。

各コードの概要は次を参考にしてください。

行数 概要
3~14 AccessOverrideクラスを定義。
16~22 SubAccessOverrideクラス(AccessOverrideクラスを継承)を定義。
24 SubAccessOverrideクラスのインスタンスを生成し、$testに代入。
25 $testのexecuteメソッドを実行。

executeメソッドは各メソッドを実行していますが、実行結果からpublic、protectedなメソッドはサブラクスのメソッドが、privateなメソッドはスーパークラスのメソッドが実行されていることが分かります。

この結果からprivateなメソッドはオーバーライドできていないということになります。

ただし、オーバーライドできないだけで定義することはできます。
executeメソッドをサブクラスに定義して実行してみましょう。

<?php

class AccessOverride {
    
    public    function method_public()    { echo "method_public        : SUCCESS!\n"; }
    protected function method_protected() { echo "method_protected     : SUCCESS!\n"; }
    private   function method_private()   { echo "method_private       : SUCCESS!\n"; }
    
}

class SubAccessOverride extends AccessOverride {
    
    public    function method_public()    { echo "sub_method_public    : SUCCESS!\n"; }
    protected function method_protected() { echo "sub_method_protected : SUCCESS!\n"; }
    private   function method_private()   { echo "sub_method_private   : SUCCESS!\n"; }
    
    public function execute() {
        $this->method_public();
        $this->method_protected();
        $this->method_private();
    }
    
}

$test = new SubAccessOverride();
$test->execute();

?>
sub_method_public    : SUCCESS!
sub_method_protected : SUCCESS!
sub_method_private   : SUCCESS!

実行結果から各メソッドはサブクラスのものが実行されていることが分かります。

これは、executeメソッドがサブクラスで定義されていることにより、サブクラス起点でメソッドが呼び出されるためです。

また、オーバーライドのアクセス修飾子の制限を1段階厳しくしてみましょう。
具体的にはpublic→protected、protected→privateに変更します。

<?php

class AccessOverride {
    
    public    function method_public()    { echo "method_public        : SUCCESS!\n"; }
    protected function method_protected() { echo "method_protected     : SUCCESS!\n"; }
    private   function method_private()   { echo "method_private       : SUCCESS!\n"; }
    
}

class SubAccessOverride extends AccessOverride {
    
    protected    function method_public()    { echo "sub_method_public    : SUCCESS!\n"; }
    private function method_protected() { echo "sub_method_protected : SUCCESS!\n"; }
    private   function method_private()   { echo "sub_method_private   : SUCCESS!\n"; }
    
    public function execute() {
        $this->method_public();
        $this->method_protected();
        $this->method_private();
    }
    
}

$test = new SubAccessOverride();
$test->execute();

?>
PHP Fatal error:  Access level to SubAccessOverride::method_public() must be public (as in class AccessOverride) in sample.php on line 13

Fatal error: Access level to SubAccessOverride::method_public() must be public (as in class AccessOverride) in sample.php on line 13

実行するとエラーになります。
これはアクセス修飾子はスーパークラスより厳しくできないため発生するエラーです。

実行結果では13行目でエラーが発生し、処理が止まっていますが、14行目でも同様のエラーになります。

このようにオーバーライドはスーパークラスのアクセス修飾子より厳しくすることはできません。

まとめ

アクセス修飾子によってオーバーライドは制限されます。
privateなメソッドはオーバーライドすることができず、public、protectedなメソッドはそれより厳しいアクセス修飾子で定義することはできせん。

意図したプログラムを作成するため覚えていきましょう。