ITHACK
~ みんなのIT部門 ~

【PHP】アクセス修飾子 – クラスへのアクセス制御

クラスにはアクセス修飾子と呼ばれる仕組みがあります。
アクセス修飾子はクラスのプロパティやメソッドへのアクセスを制限する仕組みです。

ここではアクセス修飾子について解説します。

  • アクセス修飾子

アクセス修飾子とは

アクセス修飾子はクラスのプロパティやメソッドへのアクセスを制限する仕組みです。
クラスへのアクセス元はクラス自身、サブクラス、クラス利用元の3種類あります。

種類

アクセス修飾子の種類はpublic、protected、privateの3つあり、各アクセス修飾子の制限は次のようになります。

アクセス元 public protected private
クラス自身
サブクラス ×
クラス利用元 × ×

基本構文

アクセス修飾子の基本構文は次のようになります。

class クラス名 {
    // クラス定数
    アクセス修飾子 クラス定数名;
    // クラス変数
    アクセス修飾子 static クラス変数名;
    // クラスメソッド
    アクセス修飾子 static function メソッド名() {
    }
    // フィールド
    アクセス修飾子 フィールド名;
    // メソッド
    アクセス修飾子 function メソッド名() {
    }
}

アクセス修飾子はクラス定数・クラス変数・クラスメソッドやフィールド・メソッドの定義の先頭に記述します。

また、アクセス修飾子の記述がないものは、プログラム実行時にpublicになりますが、コードの意図や分かりやすさのため明記することを心がけましょう。

検証コード

上記表のアクセスを次のAccessTestクラスを使って確認しましょう。

<?php

// クラス
class AccessTest {
    
    /*
    * クラス定数
    *****************************************************/
    public    const CONST_PUBLIC    = "CONST_PUBLIC             : SUCCESS!\n";
    protected const CONST_PROTECTED = "CONST_PROTECTED          : SUCCESS!\n";
    private   const CONST_PRIVATE   = "CONST_PRIVATE            : SUCCESS!\n";

    /*
    * クラス変数
    *****************************************************/
    public     static $class_variable_public    = "class_variable_public    : SUCCESS!\n";
    protected  static $class_variable_protected = "class_variable_protected : SUCCESS!\n";
    private    static $class_variable_private   = "class_variable_private   : SUCCESS!\n";

    /*
    * クラスメソッド
    *****************************************************/
    public    static function class_method_public()    { echo "class_method_public      : SUCCESS!\n"; }
    protected static function class_method_protected() { echo "class_method_protected   : SUCCESS!\n"; }
    private   static function class_method_private()   { echo "class_method_private     : SUCCESS!\n"; }

    /*
    * フィールド
    *****************************************************/
    public    $field_public    = "field_public             : SUCCESS!\n";
    protected $field_protected = "field_protected          : SUCCESS!\n";
    private   $field_private   = "field_private            : SUCCESS!\n";

    /*
    * メソッド
    *****************************************************/
    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"; }
    
}

?>

AccessTestクラスはクラス定数・クラス変数・クラスメソッド・メンバー変数・メンバーメソッドのそれぞれに対して3つのアクセス修飾子(public/protected/private)を用意しています。

このクラスを使ってアクセス修飾子の動作を確認します。

クラス自身からのアクセス

クラス自身から定数・変数・メソッドにアクセスするため、executeメソッドを定義し、呼び出します。

<?php

// クラス
class AccessTest {
    
    /*
    * クラス定数
    *****************************************************/
    public    const CONST_PUBLIC    = "CONST_PUBLIC             : SUCCESS!\n";
    protected const CONST_PROTECTED = "CONST_PROTECTED          : SUCCESS!\n";
    private   const CONST_PRIVATE   = "CONST_PRIVATE            : SUCCESS!\n";

    /*
    * クラス変数
    *****************************************************/
    public     static $class_variable_public    = "class_variable_public    : SUCCESS!\n";
    protected  static $class_variable_protected = "class_variable_protected : SUCCESS!\n";
    private    static $class_variable_private   = "class_variable_private   : SUCCESS!\n";

    /*
    * クラスメソッド
    *****************************************************/
    public    static function class_method_public()    { echo "class_method_public      : SUCCESS!\n"; }
    protected static function class_method_protected() { echo "class_method_protected   : SUCCESS!\n"; }
    private   static function class_method_private()   { echo "class_method_private     : SUCCESS!\n"; }

    /*
    * フィールド
    *****************************************************/
    public    $field_public    = "field_public             : SUCCESS!\n";
    protected $field_protected = "field_protected          : SUCCESS!\n";
    private   $field_private   = "field_private            : SUCCESS!\n";

    /*
    * メソッド
    *****************************************************/
    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"; }
    
    /**************************************************************
    * クラス自身
    ***************************************************************/
    function execute() {
        
        /*
        * クラス定数
        *****************************************************/
        echo self::CONST_PUBLIC;
        echo self::CONST_PROTECTED;
        echo self::CONST_PRIVATE;

        /*
        * クラス変数
        *****************************************************/
        echo self::$class_variable_public;
        echo self::$class_variable_protected;
        echo self::$class_variable_private;

        /*
        * クラスメソッド
        *****************************************************/
        self::class_method_public();
        self::class_method_protected();
        self::class_method_private();

        /*
        * フィールド
        *****************************************************/
        echo $this->field_public;
        echo $this->field_protected;
        echo $this->field_private;

        /*
        * メソッド
        *****************************************************/
        $this->method_public();
        $this->method_protected();
        $this->method_private();
        
    }
    
}

$access_test = new AccessTest();
$access_test->execute();

?>
CONST_PUBLIC             : SUCCESS!
CONST_PROTECTED          : SUCCESS!
CONST_PRIVATE            : SUCCESS!
class_variable_public    : SUCCESS!
class_variable_protected : SUCCESS!
class_variable_private   : SUCCESS!
class_method_public      : SUCCESS!
class_method_protected   : SUCCESS!
class_method_private     : SUCCESS!
field_public             : SUCCESS!
field_protected          : SUCCESS!
field_private            : SUCCESS!
method_public            : SUCCESS!
method_protected         : SUCCESS!
method_private           : SUCCESS!

実行結果から全てにアクセスできていることが分かります。

サブクラスからのアクセス

AccessTestクラスを継承したSubAccessTestクラスを定義します。
※ executeメソッドはSubAccessTestクラスのみ。

<?php

// クラス
class AccessTest {
    
    /*
    * クラス定数
    *****************************************************/
    public    const CONST_PUBLIC    = "CONST_PUBLIC             : SUCCESS!\n";
    protected const CONST_PROTECTED = "CONST_PROTECTED          : SUCCESS!\n";
    private   const CONST_PRIVATE   = "CONST_PRIVATE            : SUCCESS!\n";

    /*
    * クラス変数
    *****************************************************/
    public     static $class_variable_public    = "class_variable_public    : SUCCESS!\n";
    protected  static $class_variable_protected = "class_variable_protected : SUCCESS!\n";
    private    static $class_variable_private   = "class_variable_private   : SUCCESS!\n";

    /*
    * クラスメソッド
    *****************************************************/
    public    static function class_method_public()    { echo "class_method_public      : SUCCESS!\n"; }
    protected static function class_method_protected() { echo "class_method_protected   : SUCCESS!\n"; }
    private   static function class_method_private()   { echo "class_method_private     : SUCCESS!\n"; }

    /*
    * フィールド
    *****************************************************/
    public    $field_public    = "field_public             : SUCCESS!\n";
    protected $field_protected = "field_protected          : SUCCESS!\n";
    private   $field_private   = "field_private            : SUCCESS!\n";

    /*
    * メソッド
    *****************************************************/
    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 SubAccessTest extends AccessTest {
    
    /**************************************************************
    * サブクラス
    ***************************************************************/
    public function execute() {
        
        /*
        * クラス定数
        *****************************************************/
        echo self::CONST_PUBLIC;
        echo self::CONST_PROTECTED;
        echo self::CONST_PRIVATE;

        /*
        * クラス変数
        *****************************************************/
        echo self::$class_variable_public;
        echo self::$class_variable_protected;
        echo self::$class_variable_private;

        /*
        * クラスメソッド
        *****************************************************/
        self::class_method_public();
        self::class_method_protected();
        self::class_method_private();

        /*
        * フィールド
        *****************************************************/
        echo $this->field_public;
        echo $this->field_protected;
        echo $this->field_private;

        /*
        * メソッド
        *****************************************************/
        $this->method_public();
        $this->method_protected();
        $this->method_private();
        
    }
    
}

$access_test = new SubAccessTest();
$access_test->execute();

?>
CONST_PUBLIC             : SUCCESS!
CONST_PROTECTED          : SUCCESS!
PHP Fatal error:  Uncaught Error: Undefined constant SubAccessTest::CONST_PRIVATE in sample.php:97
Stack trace:
#0 sample.php(132): SubAccessTest->execute()
#1 {main}
  thrown in sample.php on line 97

Fatal error: Uncaught Error: Undefined constant SubAccessTest::CONST_PRIVATE in sample.php:97
Stack trace:
#0 sample.php(132): SubAccessTest->execute()
#1 {main}
  thrown in sample.php on line 97

実行結果の途中でエラーが出力されています。
これはprivateな定数にアクセスしようとして出力されているエラーです。
privateな変数・メソッドにアクセスしようとした場合も同様のエラーが出力されます。

それでは正常に動作させるため、上記コードから下記のprivateへのアクセスを削除して実行してみましょう。

echo self::CONST_PRIVATE;
echo self::$class_variable_private;
self::class_method_private();
echo $this->field_private;
$this->method_private();
CONST_PUBLIC             : SUCCESS!
CONST_PROTECTED          : SUCCESS!
class_variable_public    : SUCCESS!
class_variable_protected : SUCCESS!
class_method_public      : SUCCESS!
class_method_protected   : SUCCESS!
field_public             : SUCCESS!
field_protected          : SUCCESS!
method_public            : SUCCESS!
method_protected         : SUCCESS!

正常に実行されました。
この結果からサブクラスではpublicとprotectedにアクセスできることが分かります。

クラス利用元からのアクセス

AccessTestクラスについて外部(クラス自身でもサブクラスでもないところ)からアクセスしてみましょう。

<?php

// クラス
class AccessTest {
    
    /*
    * クラス定数
    *****************************************************/
    public    const CONST_PUBLIC    = "CONST_PUBLIC             : SUCCESS!\n";
    protected const CONST_PROTECTED = "CONST_PROTECTED          : SUCCESS!\n";
    private   const CONST_PRIVATE   = "CONST_PRIVATE            : SUCCESS!\n";

    /*
    * クラス変数
    *****************************************************/
    public     static $class_variable_public    = "class_variable_public    : SUCCESS!\n";
    protected  static $class_variable_protected = "class_variable_protected : SUCCESS!\n";
    private    static $class_variable_private   = "class_variable_private   : SUCCESS!\n";

    /*
    * クラスメソッド
    *****************************************************/
    public    static function class_method_public()    { echo "class_method_public      : SUCCESS!\n"; }
    protected static function class_method_protected() { echo "class_method_protected   : SUCCESS!\n"; }
    private   static function class_method_private()   { echo "class_method_private     : SUCCESS!\n"; }

    /*
    * フィールド
    *****************************************************/
    public    $field_public    = "field_public             : SUCCESS!\n";
    protected $field_protected = "field_protected          : SUCCESS!\n";
    private   $field_private   = "field_private            : SUCCESS!\n";

    /*
    * メソッド
    *****************************************************/
    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"; }
    
}

/**************************************************************
* クラス利用元
***************************************************************/
$access_test = new AccessTest();

/*
* クラス定数
*****************************************************/
echo AccessTest::CONST_PUBLIC;
echo AccessTest::CONST_PROTECTED;
echo AccessTest::CONST_PRIVATE;

/*
* クラス変数
*****************************************************/
echo AccessTest::$class_variable_public;
echo AccessTest::$class_variable_protected;
echo AccessTest::$class_variable_private;

/*
* クラスメソッド
*****************************************************/
AccessTest::class_method_public();
AccessTest::class_method_protected();
AccessTest::class_method_private();

/*
* フィールド
*****************************************************/
echo $access_test->field_public;
echo $access_test->field_protected;
echo $access_test->field_private;

/*
* メソッド
*****************************************************/
$access_test->method_public();
$access_test->method_protected();
$access_test->method_private();

?>
CONST_PUBLIC             : SUCCESS!
PHP Fatal error:  Uncaught Error: Cannot access protected constant AccessTest::CONST_PROTECTED in sample.php:52
Stack trace:
#0 {main}
  thrown in sample.php on line 52

Fatal error: Uncaught Error: Cannot access protected constant AccessTest::CONST_PROTECTED in sample.php:52
Stack trace:
#0 {main}
  thrown in sample.php on line 52

実行結果の途中でエラーが出力されています。
これはprotectedな定数にアクセスしようとして出力されているエラーです。
protectedな変数・メソッドにアクセスしようとした場合も同様のエラーが出力されます。

それでは下記のprotectedへアクセスの部分を削除して、実行するとどうなるでしょうか?

echo AccessTest::CONST_PROTECTED;
echo AccessTest::$class_variable_protected;
AccessTest::class_method_protected();
echo $access_test->field_protected;
$access_test->method_protected();
CONST_PUBLIC             : SUCCESS!
PHP Fatal error:  Uncaught Error: Cannot access private constant AccessTest::CONST_PRIVATE in sample.php:53
Stack trace:
#0 {main}
  thrown in sample.php on line 53

Fatal error: Uncaught Error: Cannot access private constant AccessTest::CONST_PRIVATE in sample.php:53
Stack trace:
#0 {main}
  thrown in sample.php on line 53

次はprivateへのアクセスをしようとしてエラーになります。
こちらも下記のprivateへのアクセスを削除し、実行してみましょう。

echo AccessTest::CONST_PRIVATE;
echo AccessTest::$class_variable_private;
AccessTest::class_method_private();
echo $access_test->field_private;
$access_test->method_private();
CONST_PUBLIC             : SUCCESS!
class_variable_public    : SUCCESS!
class_method_public      : SUCCESS!
field_public             : SUCCESS!
method_public            : SUCCESS!

正常に動作しました。これらの結果から外部(クラス利用元)からはpublicにしかアクセスできないことが分かります。

まとめ

アクセス修飾子はクラスへのアクセスを制限する仕組みです。

アクセス修飾子はアプリケーション設計で重要な役割を果たします。
使い所は設計の知識が必要になりますが、初めはコードを読めるようになるためにアクセス修飾子とその動作について覚えておきましょう。