PHPでアクセス指定子を用いたデータ隠蔽の実践方法を徹底解説

アクセス指定子を使用してクラスのデータを適切に隠蔽することは、PHPのオブジェクト指向プログラミングにおいて重要な概念です。データ隠蔽とは、クラス内部のデータを外部から直接アクセスできないように制限し、クラスの使用者が意図しない操作を行わないようにする手法です。これにより、ソフトウェアのセキュリティとメンテナンス性が向上し、バグの発生リスクを軽減できます。

本記事では、PHPでアクセス指定子を使ってデータ隠蔽を実現する方法について、基本的な概念から実践的な応用までを解説します。パブリック、プライベート、プロテクテッドといったアクセス指定子の違いや、それぞれの利点と活用方法を具体的な例を交えて紹介し、アクセス指定子を使用することでコードの安全性を高める方法を学びます。

目次

アクセス指定子とは何か


アクセス指定子とは、クラス内のプロパティやメソッドに対するアクセス範囲を制御するためのキーワードです。PHPのオブジェクト指向プログラミングにおいて、アクセス指定子はクラスの外部からクラス内部のデータへのアクセスを制限する役割を果たします。

アクセス指定子の種類


PHPでは、主に以下の3つのアクセス指定子が提供されています。

  • パブリック (public):クラスの外部からもアクセスできる。制限が最も少なく、自由にデータを操作できる。
  • プライベート (private):クラス内部でのみアクセス可能。外部からは直接アクセスできず、データの保護に適している。
  • プロテクテッド (protected):クラス内部および継承したサブクラスからアクセスできる。親クラスとサブクラス間のデータ共有に利用される。

アクセス指定子を適切に活用することで、コードの安全性や保守性を高め、ソフトウェアの品質を向上させることが可能です。

パブリック、プライベート、プロテクテッドの違い


アクセス指定子であるパブリック、プライベート、プロテクテッドは、それぞれ異なるアクセス範囲を持ちます。これらの違いを理解することで、クラスの設計における適切なデータ管理が可能になります。

パブリック (public)


パブリック指定子は、クラス外部からでもアクセス可能で、最も制限が少ないアクセス指定子です。外部コードから直接プロパティやメソッドにアクセスしたい場合に使用されます。しかし、自由度が高い分、意図しないデータの変更が行われるリスクもあります。

プライベート (private)


プライベート指定子は、クラス内部からのみアクセスでき、外部からの直接操作を防ぎます。これにより、データの不正な改変を防ぎ、クラスの内部構造を隠蔽できます。プライベート指定子は、外部に公開したくない内部ロジックやデータを保護する際に使用されます。

プロテクテッド (protected)


プロテクテッド指定子は、クラス内部および継承したサブクラスからのみアクセス可能です。親クラスとその派生クラス間でデータやメソッドを共有する場合に使用されます。これにより、サブクラスで親クラスのプロパティを操作しやすくし、コードの再利用性を高めます。

これらの指定子を適切に使い分けることで、クラスのデータ管理がより安全で柔軟になります。

アクセス指定子を使ったデータ隠蔽のメリット


データ隠蔽は、クラスの設計において重要な概念であり、アクセス指定子を使用することで様々な利点を得られます。適切にデータを隠蔽することで、ソフトウェアの品質向上やセキュリティの強化に寄与します。

1. セキュリティの向上


プライベートやプロテクテッド指定子を使用することで、外部からデータへの不正アクセスを防ぎ、内部データの安全性を確保します。これにより、重要なデータが外部のコードによって意図せず変更されたり、破壊されたりするリスクを軽減できます。

2. カプセル化によるメンテナンス性の向上


データ隠蔽を行うことで、クラスの内部実装を変更しても外部への影響を最小限に抑えられます。外部からアクセスできるインターフェース(メソッド)のみを公開することで、内部ロジックの修正が必要になった際も他の部分のコードに影響を与えずに対応できます。

3. バグの発生リスクを低減


アクセス制限を設けることで、クラス外部からの不適切な操作を防止し、予期しないデータの変更を回避できます。これにより、予測可能な動作を保証し、バグの発生率を低減させることができます。

4. コードの可読性と理解の向上


データ隠蔽によって、クラスの利用者は公開されたメソッドのみを使用すればよくなり、内部の複雑な実装を意識する必要がなくなります。これにより、クラスの利用方法が明確になり、コード全体の可読性が向上します。

これらのメリットを活用することで、より堅牢で保守しやすいシステムを構築することが可能です。

アクセス指定子の実践例:パブリックの使用ケース


パブリック指定子は、最も制限が少なく、クラスの外部からプロパティやメソッドに自由にアクセスできるため、使い方に注意が必要です。パブリック指定子を適切に使用することで、クラスの外部からデータを柔軟に操作したり、他のクラスや関数と連携したりすることが可能です。

パブリック指定子の使用例


以下の例では、Carクラスのmodelプロパティがパブリックに宣言されており、クラス外部から直接アクセスして値を変更できます。

class Car {
    public $model;

    public function __construct($model) {
        $this->model = $model;
    }

    public function displayModel() {
        echo "This car is a " . $this->model;
    }
}

$myCar = new Car("Toyota");
$myCar->model = "Honda"; // クラス外部から直接プロパティを変更
$myCar->displayModel(); // 出力: This car is a Honda

この例では、modelプロパティがパブリックなので、Carクラスの外部から自由に変更できます。しかし、自由に操作できる分、予期しない変更が加えられるリスクがあるため、使い方には注意が必要です。

パブリック指定子の使用が適しているケース

  1. シンプルなデータモデル:データの変更が問題にならないシンプルなクラスに適しています。
  2. クラスの動作が単純で、変更が予測しやすい場合:クラスの状態が外部から変更されても問題が発生しない場合に有効です。
  3. 迅速なプロトタイピング:開発初期段階で、アクセス制限を設ける必要がない場合には、パブリックを使用することで開発の迅速化が図れます。

ただし、クラスが複雑になるにつれて、パブリック指定子の使用は控えめにし、データを適切に保護するための他の指定子を検討することが推奨されます。

プライベート指定子でのデータ保護実践例


プライベート指定子を使用することで、クラスのプロパティやメソッドへのアクセスをクラス内部に限定し、外部から直接アクセスされるのを防ぐことができます。これにより、データを保護し、クラスの内部実装を隠蔽することが可能です。

プライベート指定子の使用例


以下の例では、BankAccountクラスのbalanceプロパティがプライベートに宣言されており、クラス外部からは直接アクセスできません。その代わり、depositおよびwithdrawメソッドを通じてのみ操作が可能です。

class BankAccount {
    private $balance;

    public function __construct($initialBalance) {
        $this->balance = $initialBalance;
    }

    public function deposit($amount) {
        if ($amount > 0) {
            $this->balance += $amount;
        }
    }

    public function withdraw($amount) {
        if ($amount > 0 && $amount <= $this->balance) {
            $this->balance -= $amount;
        }
    }

    public function getBalance() {
        return $this->balance;
    }
}

$account = new BankAccount(1000);
$account->deposit(500); // バランスを1500に増やす
$account->withdraw(300); // バランスを1200に減らす
echo $account->getBalance(); // 出力: 1200

この例では、balanceプロパティはプライベートであり、クラス外部から直接アクセスすることはできません。代わりに、depositwithdraw、およびgetBalanceメソッドを使用して、間接的にbalanceを操作します。これにより、不正な操作からデータを保護し、安全な操作のみが許可される仕組みを構築できます。

プライベート指定子の利点

  1. データの保護:クラス内部のデータに対する不正アクセスや不正操作を防ぎます。
  2. 内部実装の変更に強い:内部データの構造を変更しても、公開されたメソッドのインターフェースが変わらなければ、外部への影響を抑えることができます。
  3. クラスの責務を明確にする:外部に公開するメソッドを絞ることで、クラスの機能と責務が明確になり、コードの理解が容易になります。

プライベート指定子は、データを安全に管理し、クラスの内部実装を隠蔽するのに適しています。特に、外部からの誤操作を避けたい場合や、データの整合性を保ちたい場合に有効です。

プロテクテッド指定子の応用方法


プロテクテッド指定子を使用することで、クラス内およびそのサブクラスからアクセスできるプロパティやメソッドを定義することができます。これにより、継承関係にあるクラス間でデータを共有しつつ、外部からの直接アクセスを制限することが可能です。プロテクテッド指定子は、親クラスとサブクラス間での共通処理やデータの利用を効果的に行うために利用されます。

プロテクテッド指定子の使用例


以下の例では、Employeeクラスがprotected指定のsalaryプロパティを持ち、Managerクラスがそのサブクラスとして継承しています。Managerクラスからはsalaryにアクセスできますが、クラスの外部からは直接アクセスできません。

class Employee {
    protected $salary;

    public function __construct($salary) {
        $this->salary = $salary;
    }

    protected function getSalary() {
        return $this->salary;
    }
}

class Manager extends Employee {
    private $bonus;

    public function __construct($salary, $bonus) {
        parent::__construct($salary);
        $this->bonus = $bonus;
    }

    public function getTotalCompensation() {
        // サブクラスから親クラスのprotectedプロパティにアクセス可能
        return $this->salary + $this->bonus;
    }
}

$manager = new Manager(5000, 2000);
echo $manager->getTotalCompensation(); // 出力: 7000

この例では、salaryプロパティはプロテクテッドであるため、Managerクラス内で使用できますが、クラスの外部からは直接アクセスできません。このように、プロテクテッド指定子を利用することで、親クラスとそのサブクラス間で共有されるデータの管理を効率的に行うことができます。

プロテクテッド指定子の利点

  1. 継承を通じたデータ共有:親クラスから派生したサブクラス間でデータを共有し、共通の機能を提供できます。
  2. 柔軟な拡張性:親クラスのプロテクテッドメソッドやプロパティを再利用することで、サブクラスで機能を拡張する際に重複コードを減らすことができます。
  3. 外部からのアクセス制限:クラス外部からの不正アクセスを防ぎつつ、クラス階層内で必要なデータの利用を可能にします。

プロテクテッド指定子は、オブジェクト指向プログラミングにおける継承の強みを活かし、親クラスとサブクラスの関係を効率的に管理するための有用な手段です。

アクセス指定子の誤用によるトラブルシューティング


アクセス指定子の誤用は、意図しない動作やエラーの原因となります。パブリック、プライベート、プロテクテッドのいずれかを誤って設定することで、アクセス権の問題やクラスの設計ミスが発生する可能性があります。ここでは、典型的なエラーとその対処法について解説します。

1. プライベートメンバーへの外部アクセスエラー


プライベート指定子を使用したプロパティやメソッドは、クラス外部から直接アクセスできません。これにより、次のようなエラーが発生します。

class User {
    private $username;

    public function __construct($username) {
        $this->username = $username;
    }
}

$user = new User("Alice");
echo $user->username; // エラー: 'username' プロパティにアクセスできません

対策: プライベートプロパティにアクセスするためのgetterメソッドを作成します。

class User {
    private $username;

    public function __construct($username) {
        $this->username = $username;
    }

    public function getUsername() {
        return $this->username;
    }
}

echo $user->getUsername(); // 正しく出力される

2. プロテクテッドメンバーへの外部アクセスエラー


プロテクテッド指定子も、クラス外部からの直接アクセスを禁止します。ただし、サブクラスからのアクセスは可能です。外部からアクセスしようとするとエラーが発生します。

class Animal {
    protected $species;

    public function __construct($species) {
        $this->species = $species;
    }
}

$animal = new Animal("Dog");
echo $animal->species; // エラー: 'species' プロパティにアクセスできません

対策: サブクラスでプロパティを利用するか、パブリックなメソッドを通じてアクセスするようにします。

3. 継承時のプライベートプロパティのアクセスエラー


プライベートプロパティは親クラスの外部からはもちろん、サブクラスからもアクセスできません。これによって、以下のような問題が発生することがあります。

class ParentClass {
    private $secret = "秘密のデータ";
}

class ChildClass extends ParentClass {
    public function revealSecret() {
        return $this->secret; // エラー: 'secret' プロパティにアクセスできません
    }
}

対策: プロパティをプロテクテッドに変更するか、親クラスに公開用のメソッドを作成します。

class ParentClass {
    protected $secret = "秘密のデータ";

    public function getSecret() {
        return $this->secret;
    }
}

4. パブリック指定子によるデータ改変のリスク


パブリック指定子を使ってデータを公開している場合、外部から予期しない変更が行われるリスクがあります。これはセキュリティ上の問題やバグの原因となります。

対策: 重要なデータにはパブリック指定子を使用せず、プライベートまたはプロテクテッドに設定し、アクセスは専用のメソッドで管理します。

これらの対策を講じることで、アクセス指定子の誤用によるエラーを防ぎ、安全で堅牢なコード設計を実現できます。

getterおよびsetterメソッドの活用方法


getterおよびsetterメソッドを使用することで、クラスのプロパティへのアクセスを制御しながらデータの取得と設定を行うことができます。これにより、プロパティをプライベートまたはプロテクテッドに設定したまま、外部から安全にデータを操作することが可能になります。

getterおよびsetterメソッドとは

  • getterメソッド: プロパティの値を取得するためのメソッド。プロパティの直接公開を避け、読み取り専用のアクセスを提供します。
  • setterメソッド: プロパティの値を設定するためのメソッド。データの検証や制約を加えた上で値を変更できるようにします。

これらのメソッドを使用することで、データの安全性を確保し、クラスの内部状態を一貫性のあるものに保つことができます。

getterおよびsetterメソッドの実装例


以下の例では、Personクラスにnameageプロパティを持たせ、それぞれのgetterおよびsetterメソッドを通じてアクセスします。

class Person {
    private $name;
    private $age;

    public function __construct($name, $age) {
        $this->setName($name);
        $this->setAge($age);
    }

    // getterメソッド
    public function getName() {
        return $this->name;
    }

    public function getAge() {
        return $this->age;
    }

    // setterメソッド
    public function setName($name) {
        if (is_string($name) && strlen($name) > 0) {
            $this->name = $name;
        }
    }

    public function setAge($age) {
        if (is_int($age) && $age >= 0) {
            $this->age = $age;
        }
    }
}

$person = new Person("John", 30);
echo $person->getName(); // 出力: John
$person->setAge(35);
echo $person->getAge(); // 出力: 35

この例では、nameageプロパティはプライベートであるため、クラス外部から直接アクセスできません。しかし、getterおよびsetterメソッドを通じて値の取得や設定が可能です。setterメソッドには入力値の検証が含まれており、不正なデータが設定されるのを防ぎます。

getterおよびsetterメソッドを活用するメリット

  1. データの整合性を保つ: setterメソッドでデータの検証を行うことで、プロパティに不正な値が設定されるのを防止します。
  2. データの読み取り専用アクセスを提供: 必要に応じてgetterメソッドのみを公開し、データを外部から変更できないようにすることで、クラスの安全性を高めます。
  3. 将来的な変更に強い設計: クラスの内部実装を変更しても、getterおよびsetterメソッドのインターフェースを維持することで、他のコードへの影響を最小限に抑えることができます。

getterおよびsetterメソッドを活用することで、クラスのプロパティ管理がより安全で柔軟になり、データの保護やコードのメンテナンス性が向上します。

アクセス指定子とインターフェースの組み合わせ


アクセス指定子とインターフェースを組み合わせることで、クラスの設計をより柔軟にし、標準化された方法でデータを操作することができます。インターフェースを使用すると、クラスに特定のメソッドの実装を強制し、アクセス指定子を通じてデータの制御を強化できます。

インターフェースとは何か


インターフェースは、クラスが実装しなければならないメソッドの定義を提供するための構造です。インターフェース自体にはメソッドの実装がなく、インターフェースを実装するクラスがその具体的な処理を定義します。これにより、異なるクラスであっても同じインターフェースを共有することで、一貫した方法でオブジェクトを操作することが可能になります。

アクセス指定子とインターフェースの実践例


以下の例では、AccountInterfaceインターフェースを定義し、そのインターフェースを実装するBankAccountクラスを作成します。インターフェースには、depositwithdrawメソッドが定義されており、クラス内部でプライベートなプロパティbalanceを操作する方法を提供します。

interface AccountInterface {
    public function deposit($amount);
    public function withdraw($amount);
    public function getBalance();
}

class BankAccount implements AccountInterface {
    private $balance;

    public function __construct($initialBalance) {
        $this->balance = $initialBalance;
    }

    public function deposit($amount) {
        if ($amount > 0) {
            $this->balance += $amount;
        }
    }

    public function withdraw($amount) {
        if ($amount > 0 && $amount <= $this->balance) {
            $this->balance -= $amount;
        }
    }

    public function getBalance() {
        return $this->balance;
    }
}

$account = new BankAccount(1000);
$account->deposit(500);
$account->withdraw(300);
echo $account->getBalance(); // 出力: 1200

この例では、BankAccountクラスはAccountInterfaceインターフェースを実装しており、depositwithdraw、およびgetBalanceメソッドを提供しています。balanceプロパティはプライベートに設定されており、インターフェースを通じて安全に操作できます。

アクセス指定子とインターフェースの組み合わせの利点

  1. 標準化されたインターフェースの提供: インターフェースを使用することで、異なるクラス間で一貫した操作方法を確保できます。たとえば、複数の支払い方法があっても、共通のインターフェースで処理できるようになります。
  2. カプセル化の強化: アクセス指定子を活用して、クラスの内部データへの直接アクセスを防ぎ、インターフェースを通じてのみデータを操作することができます。
  3. 柔軟な拡張性: インターフェースを使用することで、新しいクラスを追加する際にも同じインターフェースを実装するだけで済み、既存のコードを変更せずに機能を拡張できます。

インターフェースを使用したアクセス制御のベストプラクティス

  1. プライベートまたはプロテクテッドなプロパティを使用し、インターフェースで操作を提供: 直接データにアクセスせず、インターフェースを介した安全な操作を実現します。
  2. インターフェースを通じて一貫したメソッドの実装を強制: インターフェースを使うことで、クラスに共通の機能を持たせ、外部からの使用方法を標準化できます。

アクセス指定子とインターフェースの組み合わせにより、堅牢で拡張可能なクラス設計が可能になります。

アクセス指定子を使ったデザインパターンの応用例


アクセス指定子を活用することで、デザインパターンの実装をより効果的に行うことができます。特に、プライベートやプロテクテッド指定子を利用してデータの隠蔽を行うことで、パターンの意図を明確にし、コードの保守性と安全性を向上させることが可能です。

シングルトンパターンでのアクセス指定子の応用


シングルトンパターンは、特定のクラスのインスタンスが1つしか存在しないことを保証するデザインパターンです。プライベートなコンストラクタとプロパティを使用することで、外部からの直接インスタンス化を防ぎ、唯一のインスタンスを管理します。

class Singleton {
    private static $instance = null;

    // コンストラクタをプライベートにして外部からのインスタンス化を禁止
    private function __construct() {}

    // 唯一のインスタンスを取得するための静的メソッド
    public static function getInstance() {
        if (self::$instance === null) {
            self::$instance = new Singleton();
        }
        return self::$instance;
    }

    public function showMessage() {
        echo "This is the singleton instance.";
    }
}

$singleton1 = Singleton::getInstance();
$singleton1->showMessage(); // 出力: This is the singleton instance.

$singleton2 = Singleton::getInstance();
var_dump($singleton1 === $singleton2); // 出力: bool(true)(同じインスタンスであることを示す)

この例では、Singletonクラスのコンストラクタがプライベートに設定されているため、new Singleton()によるインスタンス化ができません。唯一のインスタンスはgetInstanceメソッドを通じて取得し、アクセス指定子を使用してシングルトンの特徴を実現しています。

ファサードパターンでのプロテクテッドメソッドの使用


ファサードパターンは、複雑なシステムへの簡易的なインターフェースを提供するデザインパターンです。内部の複雑な処理はプロテクテッドメソッドで隠蔽し、公開されたメソッドからのみアクセス可能にします。

class Subsystem1 {
    public function operation1() {
        return "Subsystem1: Operation1\n";
    }
}

class Subsystem2 {
    public function operation2() {
        return "Subsystem2: Operation2\n";
    }
}

class Facade {
    protected $subsystem1;
    protected $subsystem2;

    public function __construct() {
        $this->subsystem1 = new Subsystem1();
        $this->subsystem2 = new Subsystem2();
    }

    public function performOperations() {
        // 内部でプロテクテッドメソッドを使用
        return $this->subsystem1->operation1() . $this->subsystem2->operation2();
    }
}

$facade = new Facade();
echo $facade->performOperations();
// 出力:
// Subsystem1: Operation1
// Subsystem2: Operation2

この例では、Facadeクラスの内部でSubsystem1Subsystem2のオブジェクトをプロテクテッドプロパティとして保持し、外部からは直接アクセスできないようにしています。ファサードパターンを使用することで、複雑なシステムの操作を単純化し、アクセス指定子を活用して内部実装を隠蔽できます。

ストラテジーパターンでのアクセス制御


ストラテジーパターンは、動的にアルゴリズムの選択を可能にするデザインパターンです。具体的なアルゴリズムの実装はプライベートまたはプロテクテッドにし、公開メソッドからアクセスすることで安全に切り替えられるようにします。

interface Strategy {
    public function execute();
}

class ConcreteStrategyA implements Strategy {
    public function execute() {
        echo "Executing Strategy A\n";
    }
}

class ConcreteStrategyB implements Strategy {
    public function execute() {
        echo "Executing Strategy B\n";
    }
}

class Context {
    private $strategy;

    public function setStrategy(Strategy $strategy) {
        $this->strategy = $strategy;
    }

    public function executeStrategy() {
        $this->strategy->execute();
    }
}

$context = new Context();
$context->setStrategy(new ConcreteStrategyA());
$context->executeStrategy(); // 出力: Executing Strategy A

$context->setStrategy(new ConcreteStrategyB());
$context->executeStrategy(); // 出力: Executing Strategy B

この例では、Contextクラスのstrategyプロパティはプライベートであり、外部から直接アクセスできません。setStrategyメソッドを通じて戦略を設定し、executeStrategyメソッドで選択された戦略を実行します。これにより、戦略の選択と実行を安全に管理できます。

アクセス指定子を使ったデザインパターンの利点

  1. データの隠蔽と保護: プライベートやプロテクテッド指定子を使用して、内部データへの不正アクセスを防ぎます。
  2. パターンの意図を明確にする: アクセス制御を活用することで、パターンの目的をより明確にし、コードの可読性を高めます。
  3. 柔軟な拡張性: デザインパターンとアクセス指定子を組み合わせることで、システムの柔軟性と拡張性を向上させます。

アクセス指定子を使ったデザインパターンの実装により、オブジェクト指向設計の品質が向上し、より堅牢なコードを実現できます。

演習問題:アクセス指定子を使ったクラス設計


実践的な演習問題を通じて、アクセス指定子の使い方をより深く理解しましょう。以下の演習問題では、アクセス指定子を適切に使用してクラスを設計し、データの隠蔽と安全なアクセスを実現します。

演習1: 銀行口座クラスの設計


BankAccountクラスを作成し、以下の要件を満たすようにアクセス指定子を設定してください。

  • プライベートなプロパティbalance(口座残高)を持つ。
  • パブリックなメソッドdeposit(入金)とwithdraw(出金)を実装し、それぞれ入出金のロジックを記述する。
  • 残高を取得するためのgetBalanceメソッドを追加する。
  • 入出金時に、負の金額や出金額が残高を超える場合は処理を無効にする。

解答例

class BankAccount {
    private $balance;

    public function __construct($initialBalance) {
        $this->balance = $initialBalance;
    }

    public function deposit($amount) {
        if ($amount > 0) {
            $this->balance += $amount;
        }
    }

    public function withdraw($amount) {
        if ($amount > 0 && $amount <= $this->balance) {
            $this->balance -= $amount;
        }
    }

    public function getBalance() {
        return $this->balance;
    }
}

// 使用例
$account = new BankAccount(1000);
$account->deposit(200);
$account->withdraw(500);
echo $account->getBalance(); // 出力: 700

演習2: 社員クラスの設計


Employeeクラスを作成し、以下の要件を満たしてください。

  • プロテクテッドなプロパティname(名前)とsalary(給与)を持つ。
  • 名前を設定するsetNameメソッドと給与を設定するsetSalaryメソッドを実装する(入力の検証を追加する)。
  • 名前を取得するgetNameメソッドを作成し、給与はサブクラスからのみ取得可能にする。

解答例

class Employee {
    protected $name;
    protected $salary;

    public function __construct($name, $salary) {
        $this->setName($name);
        $this->setSalary($salary);
    }

    public function setName($name) {
        if (is_string($name) && strlen($name) > 0) {
            $this->name = $name;
        }
    }

    public function setSalary($salary) {
        if (is_numeric($salary) && $salary >= 0) {
            $this->salary = $salary;
        }
    }

    public function getName() {
        return $this->name;
    }

    protected function getSalary() {
        return $this->salary;
    }
}

// サブクラスの例
class Manager extends Employee {
    public function getEmployeeSalary() {
        return $this->getSalary();
    }
}

$manager = new Manager("Alice", 5000);
echo $manager->getName(); // 出力: Alice
echo $manager->getEmployeeSalary(); // 出力: 5000

演習3: 商品クラスとインターフェースの組み合わせ


以下の要件に従って、Productクラスとインターフェースを作成してください。

  • インターフェースPricedItemを定義し、getPriceメソッドを含める。
  • ProductクラスはPricedItemインターフェースを実装し、プライベートなプロパティpriceを持つ。
  • getPriceメソッドで商品の価格を取得できるようにする。
  • プロテクテッドなメソッドsetDiscountを実装し、割引価格を設定する。

解答例

interface PricedItem {
    public function getPrice();
}

class Product implements PricedItem {
    private $price;

    public function __construct($price) {
        $this->price = $price;
    }

    public function getPrice() {
        return $this->price;
    }

    protected function setDiscount($discount) {
        if ($discount > 0 && $discount < $this->price) {
            $this->price -= $discount;
        }
    }
}

// 使用例
$product = new Product(100);
echo $product->getPrice(); // 出力: 100

これらの演習を通じて、アクセス指定子を使ったクラス設計の基本的な考え方を習得できます。さまざまなシナリオで適切にアクセス指定子を使い分け、クラスの設計をより安全で柔軟にすることを目指しましょう。

まとめ


本記事では、PHPにおけるアクセス指定子の使い方とデータ隠蔽の重要性について解説しました。パブリック、プライベート、プロテクテッドの違いを理解し、それぞれの指定子を適切に使い分けることで、クラスの安全性や保守性を向上させることができます。また、getterおよびsetterメソッド、インターフェース、デザインパターンなどを組み合わせることで、柔軟で堅牢なコードを実現できます。アクセス指定子を活用して、より良いクラス設計を目指しましょう。

コメント

コメントする

目次