Menu
Coddy logo textTech

アクセス修飾子を深く学ぶ

CoddyのPHPジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 39/91。

3つのアクセス修飾子を理解したところで、継承の場面でそれらがどのように振る舞うかを見ていきましょう。重要なポイントは、protected メンバーは子クラスからアクセス可能になる一方、private メンバーは子クラスからも隠されたままであるということです。

<?php
class Vehicle {
    public $brand;
    protected $engineType;
    private $serialNumber;
    
    public function __construct($brand, $engine, $serial) {
        $this->brand = $brand;
        $this->engineType = $engine;
        $this->serialNumber = $serial;
    }
    
    private function getSerial() {
        return $this->serialNumber;
    }
    
    protected function getEngineInfo() {
        return $this->engineType;
    }
}

class Car extends Vehicle {
    public function getDetails() {
        return $this->brand . " - " . $this->getEngineInfo();
        // $this->serialNumber はエラーを引き起こします - private!
        // $this->getSerial() も失敗します - private メソッド!
    }
}

$car = new Car("Toyota", "V6", "ABC123");
echo $car->getDetails();

出力:

Toyota - V6

Car クラスは $brand(public)にアクセスし、getEngineInfo()(protected)を呼び出せますが、$serialNumbergetSerial() にはアクセスできません。これらは Vehicle に対して private だからです。この違いにより、他の内部詳細を完全に隠したまま、一部の内部詳細を子クラスと共有できます。

重要なポイント:子クラスが内部データやメソッドにアクセスする必要がある場合はprotectedを使用し、子クラスでさえ特定の実装の詳細に触れるべきでない場合はprivateを使用します。

challenge icon

チャレンジ

簡単

継承全体で access modifiers がどのように振る舞うかを探る、デバイス管理システムを構築しましょう。異なる可視性レベルの properties を持つ基底 Device class を作成し、それを Smartphone class で拡張して、子 class がどのメンバーに access でき、どのメンバーには access できないかを示します。

コードを3つのファイルに分けて整理します。

  • Device.php: データの機密性が異なる電子デバイスを表す Device class を Create します。以下を含めます。
    • メーカー名用の public property $brand
    • 内部識別用の protected property $modelNumber
    • 工場専用データ用の private property $manufacturingCode
    constructor は3つすべての値を受け取るようにします。manufacturing code を返す private method getManufacturingCode() を追加します。"Model: [modelNumber]" を返す public method getModelInfo() を追加します。最後に、"[brand]-[manufacturingCode]" を返す public method getFullCode() を追加します。これは、class 自体が自身の private members に access できることを示しています。
  • Smartphone.php: Device を extends する Smartphone class を Create します。Device file を Include します。constructor は brand、modelNumber、manufacturingCode、operating system name を受け取るようにします。最初の3つの値を parent constructor に渡し、その後 OS を private property に保存します。"[brand] [modelNumber] running [os]" を返す public method getDeviceDetails() を追加します。ここでは、public $brand には directly access でき、protected $modelNumber にも access できますが、private $manufacturingCode には directly access できないことに注目してください。代わりに、inherited public method getFullCode() を使う必要があります。
  • main.php: Smartphone file を Include します。4つの inputs、つまり brand name、model number、manufacturing code、operating system を受け取ります。これらの値で Smartphone instance を Create します。3行を Print します。
    • getDeviceDetails() を Call した結果
    • inherited getModelInfo() method を Call した結果
    • inherited getFullCode() method を Call した結果

この challenge は重要な違いを示しています。Smartphone class は Device から inherited した protected $modelNumber を自由に使用できますが、private $manufacturingCodegetManufacturingCode() は完全に隠されたままです。これらに access できるのは、Device が公開することを選択した public interface を通した場合だけです。

自分で試してみよう

<?php
require_once 'Smartphone.php';

// 入力を読み取る
$brand = trim(fgets(STDIN));
$modelNumber = trim(fgets(STDIN));
$manufacturingCode = trim(fgets(STDIN));
$os = trim(fgets(STDIN));

// TODO: 入力値でSmartphoneインスタンスを作成する

// TODO: getDeviceDetails()の結果を出力する

// TODO: 継承されたgetModelInfo()メソッドの結果を出力する

// TODO: 継承されたgetFullCode()メソッドの結果を出力する
?>
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: PHPオンラインコンパイラ