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

クラス継承ではオーバーライドはアクセス修飾子よって制限されます。

ここではオーバーライドとアクセス修飾子の関係性について解説します。

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

★ 目的

  • オーバーライドとアクセス修飾子の関係性を理解する。

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

クラス継承ではオーバーライドはアクセス修飾子によって制限されます。

主に制限されることは次の2つです。

  1. オーバーライドできるかどうか
  2. オーバーライドできるアクセス修飾子の種類

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

privateなメソッドはオーバーライドできません。

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

2. オーバーライドできるアクセス修飾子の種類

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

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

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

スーパークラスのアクセス修飾子publicprotectedprivate
オーバーライド×
サブラクスのアクセス修飾子publicpublic/protectedpublic/prtected/private

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

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

検証コード

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

次の検証コードをご覧ください。

ソースコード

<?php

// クラス定義
class AccessOverride {

    /*
    * メンバーメソッド
    *****************************************************/
    // public
    public function member_method_public() {
        echo "member_method_public: SUCCESS!\n";
    }
    // protected
    protected function member_method_protected() {
        echo "member_method_protected: SUCCESS!\n";
    }
    // private
    private function member_method_private() {
        echo "member_method_private: SUCCESS!\n";
    }
    
    public function execute() {
        $this->member_method_public();
        $this->member_method_protected();
        $this->member_method_private();
    }
    
}

// クラス定義
class SubAccessOverride extends AccessOverride {
    
    /*
    * オーバーライド(メンバメソッド)
    *****************************************************/
    // public
    public function member_method_public() {
        echo "sub member_method_public: SUCCESS!\n";
    }
    // protected
    protected function member_method_protected() {
        echo "sub member_method_protected: SUCCESS!\n";
    }
    // private
    private function member_method_private() {
        echo "sub member_method_private: SUCCESS!\n";
    }
    
}

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

?>

実行結果

sub member_method_public: SUCCESS!
sub member_method_protected: SUCCESS!
member_method_private: SUCCESS!

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

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

行数概要
4行目〜28行目AccessOverrideクラスを定義。
31行目〜49行目SubAccessOverrideクラス(AccessOverrideクラスを継承)を定義。
51行目SubAccessOverrideクラスのインスタンスを生成し、$testに代入。
52行目$testのexecuteメソッドを実行。

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

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

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

ソースコード

<?php

// クラス定義
class AccessOverride {

    /*
    * メンバーメソッド
    *****************************************************/
    // public
    public function member_method_public() {
        echo "member_method_public: SUCCESS!\n";
    }
    // protected
    protected function member_method_protected() {
        echo "member_method_protected: SUCCESS!\n";
    }
    // private
    private function member_method_private() {
        echo "member_method_private: SUCCESS!\n";
    }
    
}

// クラス定義
class SubAccessOverride extends AccessOverride {
    
    /*
    * オーバーライド(メンバメソッド)
    *****************************************************/
    // public
    public function member_method_public() {
        echo "sub member_method_public: SUCCESS!\n";
    }
    // protected
    protected function member_method_protected() {
        echo "sub member_method_protected: SUCCESS!\n";
    }
    // private
    private function member_method_private() {
        echo "sub member_method_private: SUCCESS!\n";
    }
    
    public function execute() {
        $this->member_method_public();
        $this->member_method_protected();
        $this->member_method_private();
    }
    
}

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

?>

実行結果

sub member_method_public: SUCCESS!
sub member_method_protected: SUCCESS!
sub member_method_private: SUCCESS!

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

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

また、上記オーバーライドのアクセス修飾子の制限を1段階厳しくしてみましょう。

具体的にはpublic→protected、protected→privateに変更します。

ソースコード

<?php

// クラス定義
class AccessOverride {

    /*
    * メンバーメソッド
    *****************************************************/
    // public
    public function member_method_public() {
        echo "member_method_public: SUCCESS!\n";
    }
    // protected
    protected function member_method_protected() {
        echo "member_method_protected: SUCCESS!\n";
    }
    // private
    private function member_method_private() {
        echo "member_method_private: SUCCESS!\n";
    }
    
}

// クラス定義
class SubAccessOverride extends AccessOverride {
    
    /*
    * オーバーライド(メンバメソッド)
    *****************************************************/
    // public
    protected function member_method_public() {
        echo "sub member_method_public: SUCCESS!\n";
    }
    // protected
    private function member_method_protected() {
        echo "sub member_method_protected: SUCCESS!\n";
    }
    // private
    private function member_method_private() {
        echo "sub member_method_private: SUCCESS!\n";
    }
    
    public function execute() {
        $this->member_method_public();
        $this->member_method_protected();
        $this->member_method_private();
    }
    
}

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

?>

実行結果

PHP Fatal error:  Access level to SubAccessOverride::member_method_public() must be public (as in class AccessOverride) in /source-code/sample.php on line 31

Fatal error: Access level to SubAccessOverride::member_method_public() must be public (as in class AccessOverride) in /source-code/sample.php on line 31

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

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

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

まとめ

オーバーライドはスーパークラスのアクセス修飾子によって制限がかかります。

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

1つの仕組みとして、覚えてプログラミングに挑みましょう。