アクセス修飾子を深く学ぶ
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 - V6Car クラスは $brand(public)にアクセスし、getEngineInfo()(protected)を呼び出せますが、$serialNumber や getSerial() にはアクセスできません。これらは Vehicle に対して private だからです。この違いにより、他の内部詳細を完全に隠したまま、一部の内部詳細を子クラスと共有できます。
重要なポイント:子クラスが内部データやメソッドにアクセスする必要がある場合はprotectedを使用し、子クラスでさえ特定の実装の詳細に触れるべきでない場合はprivateを使用します。
チャレンジ
簡単継承全体で access modifiers がどのように振る舞うかを探る、デバイス管理システムを構築しましょう。異なる可視性レベルの properties を持つ基底 Device class を作成し、それを Smartphone class で拡張して、子 class がどのメンバーに access でき、どのメンバーには access できないかを示します。
コードを3つのファイルに分けて整理します。
Device.php: データの機密性が異なる電子デバイスを表すDeviceclass を Create します。以下を含めます。- メーカー名用の
publicproperty$brand - 内部識別用の
protectedproperty$modelNumber - 工場専用データ用の
privateproperty$manufacturingCode
privatemethodgetManufacturingCode()を追加します。"Model: [modelNumber]"を返すpublicmethodgetModelInfo()を追加します。最後に、"[brand]-[manufacturingCode]"を返すpublicmethodgetFullCode()を追加します。これは、class 自体が自身の private members に access できることを示しています。- メーカー名用の
Smartphone.php:Deviceを extends するSmartphoneclass を Create します。Device file を Include します。constructor は brand、modelNumber、manufacturingCode、operating system name を受け取るようにします。最初の3つの値を parent constructor に渡し、その後 OS を private property に保存します。"[brand] [modelNumber] running [os]"を返す public methodgetDeviceDetails()を追加します。ここでは、public$brandには directly access でき、protected$modelNumberにも access できますが、private$manufacturingCodeには directly access できないことに注目してください。代わりに、inherited public methodgetFullCode()を使う必要があります。main.php: Smartphone file を Include します。4つの inputs、つまり brand name、model number、manufacturing code、operating system を受け取ります。これらの値でSmartphoneinstance を Create します。3行を Print します。getDeviceDetails()を Call した結果- inherited
getModelInfo()method を Call した結果 - inherited
getFullCode()method を Call した結果
この challenge は重要な違いを示しています。Smartphone class は Device から inherited した protected $modelNumber を自由に使用できますが、private $manufacturingCode と getManufacturingCode() は完全に隠されたままです。これらに 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()メソッドの結果を出力する
?>このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: PHPオンラインコンパイラ