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

チャレンジ

簡単

継承におけるアクセス修飾子の振る舞いを探求するデバイス管理システムを構築しましょう。異なる可視性レベルのプロパティを持つベースクラス Device を作成し、それを Smartphone クラスで継承して、子クラスがどのメンバにアクセスでき、どのメンバにアクセスできないかを確認します。

コードは以下の3つのファイルに分けて構成します:

  • Device.php — データ感度のレベルが異なる電子デバイスを表す Device クラスを作成します。以下を含めてください:
    • 製造元名のための public プロパティ $brand
    • 内部識別用の protected プロパティ $modelNumber
    • 工場専用データのための private プロパティ $manufacturingCode
    コンストラクタはこれら3つの値をすべて受け取るようにします。製造コードを返す private メソッド getManufacturingCode() を追加します。"Model: [modelNumber]" を返す public メソッド getModelInfo() を追加します。最後に、"[brand]-[manufacturingCode]" を返す public メソッド getFullCode() を追加します。これは、クラス自身が自身のプライベートメンバにどのようにアクセスできるかを示しています。
  • Smartphone.phpDevice を継承する Smartphone クラスを作成します。Device ファイルをインクルードしてください。コンストラクタは brand、modelNumber、manufacturingCode、およびオペレーティングシステム名を受け取るようにします。最初の3つの値で親のコンストラクタを呼び出し、OSをプライベートプロパティに保存します。"[brand] [modelNumber] running [os]" を返すパブリックメソッド getDeviceDetails() を追加します。パブリックな $brand やプロテクトされた $modelNumber には直接アクセスできますが、プライベートな $manufacturingCode には直接アクセスできないことに注目してください。代わりに、継承されたパブリックメソッド getFullCode() を使用する必要があります。
  • main.php — Smartphone ファイルをインクルードします。ブランド名、モデル番号、製造コード、オペレーティングシステムの4つの入力を受け取ります。これらの値を使用して Smartphone インスタンスを作成します。次の3行を出力してください:
    • getDeviceDetails() を呼び出した結果
    • 継承された getModelInfo() メソッドを呼び出した結果
    • 継承された getFullCode() メソッドを呼び出した結果

このチャレンジは重要な区別を浮き彫りにします。Smartphone クラスは Device から継承されたプロテクトプロパティ $modelNumber を自由に使用できますが、プライベートな $manufacturingCodegetManufacturingCode() は完全に隠されたままであり、Device が公開することを選択したパブリックインターフェースを通じてのみアクセス可能です。

チートシート

継承において、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

子クラスがアクセスできるもの:

  • public プロパティとメソッド
  • protected プロパティとメソッド

子クラスがアクセスできないもの:

  • private プロパティとメソッド(これらは親クラス専用のままです)

ベストプラクティス: 子クラスが内部データやメソッドにアクセスする必要がある場合は protected を使用し、子クラスであっても特定の実装詳細に触れるべきでない場合は private を使用します。

自分で試してみよう

<?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腕試し

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

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