ITHACK
~ みんなのIT部門 ~
【PHP】アクセス修飾子とオーバーライド - オーバーライド可否とアクセス修飾子の種類

【PHP】アクセス修飾子とオーバーライド - オーバーライド可否とアクセス修飾子の種類

アクセス修飾子によってオーバーライド可能なメソッドが制限されます。

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

検証環境

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

オーバーライドするメソッドは、アクセス修飾子の種類(public / protected / private)によって次の2点の制限が付与されます。

  1. オーバーライド可否
  2. アクセス修飾子の種類

1.オーバーライド可否

オーバーライド可否は“オーバーライドが可能かどうか”です。

アクセス修飾子がprivateなメソッドはオーバーライドできません。

protectedまたはpublicなメソッドのみオーバーライドが可能です。

アクセス修飾子の種類

オーバーライドするメソッドのアクセス修飾子によって、付与できる種類(アクセス権)が異なります。

アクセス権はオーバーライドするメソッドより厳しくすることができません。

アクセス修飾子はprivate>protected>publicの順で制限されています。

そのため、例えば、スーパークラスがprotectedの場合、サブクラスではpublicまたはprotectedのアクセス修飾子のみでオーバーライドできます。


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

アクセス修飾子とオーバーライドの関係性
オーバーライド対象メソッドの
アクセス修飾子
public protected private
オーバーライド可否 ×
アクセス修飾子の種類 public public
protected
public
protected
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();

?>
$ php sample.php
sub_method_public    : SUCCESS!
sub_method_protected : SUCCESS!
method_private       : SUCCESS!

SubAccessOverrideクラスはAccessOverrideクラスを継承し、各メソッド(executeメソッドを除く)をオーバーライドしています。

実行結果から分かるようにSubAccessOverrideクラスのオブジェクトからexecuteメソッドを呼び出すと、publicprotectedなメソッドはサブクラスのメソッドが実行されました。

しかし、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"; }
    
    ___ih_diff_start
-    public function execute() {
-        $this->method_public();
-        $this->method_protected();
-        $this->method_private();
-    }
    ___ih_diff_end
    
}

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"; }
    
    ___ih_diff_start
+    public function execute() {
+        $this->method_public();
+        $this->method_protected();
+        $this->method_private();
+    }
    ___ih_diff_end
    
}

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

?>
$ php sample.php
sub_method_public    : SUCCESS!
sub_method_protected : SUCCESS!
sub_method_private   : SUCCESS!

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

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

また、オーバーライドのアクセス修飾子の制限を1段階厳しく(publicprotectedprotectedprivate)してみます。

<?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 {
    
    ___ih_diff_start
-    public    function method_public()    { echo "sub_method_public    : SUCCESS!\n"; }
+    protected function method_public()    { echo "sub_method_public    : SUCCESS!\n"; }
-    protected function method_protected() { echo "sub_method_protected : SUCCESS!\n"; }
+    private   function method_protected() { echo "sub_method_protected : SUCCESS!\n"; }
    private   function method_private()   { echo "sub_method_private   : SUCCESS!\n"; }
    ___ih_diff_end
    
    public function execute() {
        $this->method_public();
        $this->method_protected();
        $this->method_private();
    }
    
}

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

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

このコードは実行するとエラーが発生します。

原因はオーバーライドするメソッドより、アクセス権を厳しくしたためです。

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

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