【PHP】レッスン5-03:アクセス修飾子とカプセル化を理解しよう

記事内に商品プロモーションを含む場合があります

この記事で学べる知識:アクセス修飾子とカプセル化

この記事の練習問題を解くために必要な知識:
基礎文法・制御構造・関数・データ構造(レッスン1~4)クラスの定義と使用コンストラクタアクセス修飾子とカプセル化クラスメンバクラスの継承メソッドのオーバーライド抽象クラスインターフェーストレイト

オブジェクト指向プログラミング(OOP)では、データの安全性や管理性を高めるためにアクセス修飾子カプセル化が使用されます。

これによりプログラム内でデータのアクセス範囲を制限し、不正な操作を防ぎます。

本節ではPHPにおけるアクセス修飾子の種類とカプセル化の概念、さらにゲッターとセッターについて学びます。

<<前のページ PHP記事一覧 次のページ>>

アクセス修飾子とは?

アクセス修飾子とは、クラスのプロパティやメソッドへのアクセス範囲を制御するためのキーワードです。

PHPには以下の3種類のアクセス修飾子があります。

  1. public(パブリック):クラスの外部や内部からアクセス可能。
  2. protected(プロテクテッド):クラス自身とその子クラスからのみアクセス可能。
  3. private(プライベート):クラス自身からのみアクセス可能。
class Sample {
    public $publicVar;       // 外部からアクセス可能
    protected $protectedVar; // 子クラスからのみアクセス可能
    private $privateVar;     // 自クラス内からのみアクセス可能
}

$obj = new Sample();
$obj->publicVar = 'OK';      // publicはアクセス可能
$obj->protectedVar = 'NG';   // protectedはエラー
$obj->privateVar = 'NG';     // privateはエラー

カプセル化とは?

カプセル化とはクラス内のデータや処理を外部から直接操作できないようにし、必要に応じて安全にデータをやり取りする仕組みです。

これによりデータの保護や管理が容易になります。

class User {
    private $name; // privateなのでクラス外から直接アクセス不可

    // クラス外からデータの取得するためのゲッターメソッドの定義
    public function getName() {
        return $this->name;
    }

    // クラス外からデータを設定するためのセッターメソッドの定義
    public function setName($name) {
        $this->name = $name;
    }
}

$user = new User();
$user->setName('Taro');     // セッターで値を設定
echo $user->getName();      // ゲッターで値を取得

上記のコードでは$nameプロパティはprivateなので外部から直接変更できませんが、ゲッターとセッターを使うことで安全に操作できます。

ゲッターとセッターの使用例

以下は、ゲッターとセッターを使った具体例です。

例:銀行口座クラスの設計 

class BankAccount {
    private $balance = 0; // 口座残高は直接変更できない

    // 残高を取得するゲッターメソッド
    public function getBalance() {
        return $this->balance;
    }

    // 入金処理を行うセッターメソッド
    public function deposit($amount) {
        if ($amount > 0) { // 入金額は正の数のみ許可
            $this->balance += $amount;
        } else {
            echo '無効な金額です。' . PHP_EOL;
        }
    }

    // 出金処理を行うセッターメソッド
    public function withdraw($amount) {
        if ($amount > 0 && $this->balance >= $amount) {
            $this->balance -= $amount;
        } else {
            echo '残高不足または無効な金額です。' . PHP_EOL;
        }
    }
}

// インスタンス作成と操作例
$account = new BankAccount();
$account->deposit(1000);   // 入金
echo $account->getBalance(); // 残高表示(1000)

$account->withdraw(500);  // 出金
echo $account->getBalance(); // 残高表示(500)

$account->withdraw(1000); // エラーメッセージ(残高不足)

この例では、残高はprivateで直接操作できないため、不正なアクセスや誤操作を防ぐことができます。

まとめ

アクセス修飾子とカプセル化は、オブジェクト指向プログラミングにおいて重要な概念です。

  • アクセス修飾子を使うことでデータの公開範囲を制御し、安全性を高めます。
  • カプセル化によりデータを保護し、ゲッターやセッターを通じて安全に操作します。

これらを正しく理解して使用することで、より安全で保守性の高いコードを作成できるようになります。

アクセス修飾子とカプセル化の練習問題:セッターとゲッターを活用してみよう!

ユーザーの名前と年齢を管理するプログラムを作成しましょう。

このプログラムではアクセス修飾子を使用してデータを保護し、カプセル化によりデータへのアクセスを安全に制御します。

具体的にはゲッターセッターを用いて名前と年齢の設定や取得を行い、無効なデータが設定されないようにバリデーションを組み込みます。

最後にユーザー情報を表示し、年齢を変更して再度情報を表示する機能を実装します。

この問題の要件

以下の要件に従ってコードを完成させてください。

  1. クラス User を作成すること。
  2. クラス内に以下のprivateプロパティを定義すること:
    • 名前($name):文字列型
    • 年齢($age):整数型
  3. コンストラクタを定義し、オブジェクト作成時に名前と年齢を初期化できるようにすること。
  4. 以下のゲッターとセッターを実装すること:
    • getName(): 名前を取得する。
    • setName($name): 名前を設定する。ただし、空文字は許可しない。
    • getAge(): 年齢を取得する。
    • setAge($age): 年齢を設定する。ただし、0以上の数値のみ許可する。
  5. ユーザー情報を表示する関数 displayInfo() を作成すること。
  6. 例外処理を実装し、無効なデータが入力された場合はエラーメッセージを表示すること。

ただし、以下のような実行結果となるコードを書くこと。

*****↓↓正解コードの実行結果の例↓↓*****

名前: 太郎
年齢: 25
年齢を更新しました。
名前: 太郎
年齢: 30

この問題を解くヒント

1からコードを組み立てることが難しい場合は、以下のヒントを開いて参考にしましょう。

ヒント1【コードの構成を見る】

正解のコードは上から順に以下のような構成となっています。
(※下記の□はコード内のインデントを表しています)

1:PHPの開始タグを宣言
2:Userクラスを宣言
  □ privateスコープの文字列型プロパティ$nameを定義
  □ privateスコープの整数型プロパティ$ageを定義
  □ コンストラクタを宣言(名前と年齢を初期化する)
  □ □ setNameメソッドで名前を設定
  □ □ setAgeメソッドで年齢を設定
  □ getNameメソッドを宣言し、プロパティ$nameの値を返す
  □ setNameメソッドを宣言し、名前のバリデーションと設定を行う
  □ □ 名前が空欄の場合は例外をスロー
  □ getAgeメソッドを宣言し、プロパティ$ageの値を返す
  □ setAgeメソッドを宣言し、年齢のバリデーションと設定を行う
  □ □ 年齢が0未満の場合は例外をスロー
  □ displayInfoメソッドを宣言し、ユーザー情報を表示
3:tryブロックを開始
  □ Userクラスのインスタンス$userを作成(名前「太郎」、年齢25で初期化)
  □ $userオブジェクトのdisplayInfoメソッドを呼び出し、情報を表示
  □ setAgeメソッドを使用して年齢を30に更新
  □ 「年齢を更新しました。」と出力
  □ 更新後の情報を再度displayInfoメソッドで表示
4:catchブロックを宣言し、例外発生時の処理を定義
  □ 例外メッセージを「エラー:」とともに出力

ヒント2【穴埋め問題にする】

以下のコードをコピーし、コメントに従ってコードを完成させて下さい。

<?php
// ユーザー情報を管理するクラス
class User {
    // プロパティの宣言(privateでカプセル化)
    /* 【穴埋め問題1】
    ここでユーザー名と年齢を格納するprivateスコープのプロパティを2つ定義してください。
    名前は文字列型、年齢は整数型とします。
    また、このプロパティはクラス外から直接アクセスできないようにしてください。
    */

    // コンストラクタ(初期化処理)
    public function __construct(string $name, int $age) {
        /* 【穴埋め問題2】
        ここでコンストラクタを実装し、名前と年齢のバリデーションを行うメソッドを呼び出して初期化してください。
        */
    }

    // 名前を取得するゲッター
    /* 【穴埋め問題3】
    ここで名前を取得するゲッターメソッドを定義してください。
    このメソッドは名前を文字列型で返す必要があります。
    */

    // 名前を設定するセッター(バリデーション付き)
    public function setName(string $name): void {
        /* 【穴埋め問題4】
        名前が空欄でないことを確認し、バリデーションに失敗した場合は例外をスローしてください。
        バリデーションを通過した場合はプロパティに値を設定してください。
        */
    }

    // 年齢を取得するゲッター
    /* 【穴埋め問題5】
    ここで年齢を取得するゲッターメソッドを定義してください。
    このメソッドは年齢を整数型で返す必要があります。
    */

    // 年齢を設定するセッター(バリデーション付き)
    public function setAge(int $age): void {
        /* 【穴埋め問題6】
        年齢が0以上であることを確認し、バリデーションに失敗した場合は例外をスローしてください。
        バリデーションを通過した場合はプロパティに値を設定してください。
        */
    }

    // ユーザー情報を表示する関数
    public function displayInfo(): void {
        echo "名前: " . $this->getName() . PHP_EOL;
        echo "年齢: " . $this->getAge() . PHP_EOL;
    }
}

// クラスの使用例
try {
    /* 【穴埋め問題7】
    ここでUserクラスのインスタンスを作成し、名前「太郎」と年齢25を設定してください。
    また、displayInfoメソッドを呼び出して初期状態の情報を表示してください。
    */

    /* 【穴埋め問題8】
    年齢を30に更新し、更新メッセージを表示した後、再度displayInfoメソッドを呼び出して最新の情報を表示してください。
    */
} catch (Exception $e) {
    echo "エラー: " . $e->getMessage() . PHP_EOL;
}

以上がこの問題の穴埋めコードです。

このヒントを見てもまだ回答を導き出すのが難しいと感じる場合は、先に正解のコードと解説を見て内容を理解するようにしましょう。



練習問題の解答と解説

この問題の一つの正解例とそのコードの解説を以下に示します。

正解コードの例

例えば以下のようなプログラムが考えられます。

<?php
// ユーザー情報を管理するクラス
class User {
    // プロパティの宣言(privateでカプセル化)
    private string $name;   // ユーザー名(文字列)
    private int $age;       // 年齢(整数)

    // コンストラクタ(初期化処理)
    public function __construct(string $name, int $age) {
        // 名前と年齢を設定(初期化時にバリデーションを適用)
        $this->setName($name);
        $this->setAge($age);
    }

    // 名前を取得するゲッター
    public function getName(): string {
        return $this->name;
    }

    // 名前を設定するセッター(バリデーション付き)
    public function setName(string $name): void {
        // 名前が空でないことを確認
        if (trim($name) === '') {
            throw new Exception('名前は空欄にできません。');
        }
        $this->name = $name;
    }

    // 年齢を取得するゲッター
    public function getAge(): int {
        return $this->age;
    }

    // 年齢を設定するセッター(バリデーション付き)
    public function setAge(int $age): void {
        // 年齢が0以上であることを確認
        if ($age < 0) {
            throw new Exception('年齢は0以上である必要があります。');
        }
        $this->age = $age;
    }

    // ユーザー情報を表示する関数
    public function displayInfo(): void {
        echo "名前: " . $this->getName() . PHP_EOL;
        echo "年齢: " . $this->getAge() . PHP_EOL;
    }
}

// クラスの使用例
try {
    // ユーザーオブジェクトを作成
    $user = new User('太郎', 25);

    // ユーザー情報の表示
    $user->displayInfo();

    // 年齢を変更
    $user->setAge(30);
    echo "年齢を更新しました。" . PHP_EOL;

    // 更新後のユーザー情報の表示
    $user->displayInfo();
} catch (Exception $e) {
    // エラーメッセージを表示
    echo "エラー: " . $e->getMessage() . PHP_EOL;
}

正解コードの解説

このコードは「アクセス修飾子」と「カプセル化」を用いて、ユーザー情報(名前と年齢)を安全に管理するプログラムです。

以下のブロックごとに解説します。

クラス定義とプロパティの宣言

class User {
    private string $name;
    private int $age;
  • class User: クラスはオブジェクトを作成するための設計図です。このクラスはユーザー情報を管理します。
  • private: アクセス修飾子の1つで、このプロパティはクラスの外部から直接アクセスできません。これによりデータの不正操作を防ぎます。
  • $name, $age: ユーザー名と年齢を保持する変数です。それぞれ文字列と整数型として型指定されています。型指定によりデータの誤入力を防ぎます。

コンストラクタの定義

public function __construct(string $name, int $age) {
    $this->setName($name);
    $this->setAge($age);
}
  • public: アクセス修飾子の1つで、この関数は外部から呼び出すことができます。
  • __construct: コンストラクタは、オブジェクトが作成されるときに自動的に実行されます。
  • $this: このキーワードはクラスの現在のインスタンスを指します。$this->setName() はインスタンス内の setName メソッドを呼び出します。

ゲッターとセッターの定義

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

public function setName(string $name): void {
    if (trim($name) === '') {
        throw new Exception('名前は空欄にできません。');
    }
    $this->name = $name;
}
  • getName(): プロパティ $name の値を外部から取得するための関数(ゲッター)。外部から直接 $name にアクセスできないため、代わりにこの関数を使用します。
  • setName(): プロパティ $name の値を設定するための関数(セッター)。バリデーション(データの検証)も行い、空文字を防ぎます。
  • 例外処理 (throw new Exception): 無効なデータが入力された場合にエラーを発生させ、プログラムの不正動作を防ぎます。

ユーザー情報の表示関数

public function displayInfo(): void {
    echo "名前: " . $this->getName() . PHP_EOL;
    echo "年齢: " . $this->getAge() . PHP_EOL;
}
  • displayInfo(): ユーザー情報を表示する関数です。
  • PHP_EOL: 改行を表す定数で、環境によらず改行を統一できます。

クラスの使用例

$user = new User('太郎', 25);
$user->displayInfo();
$user->setAge(30);
$user->displayInfo();
  • new User(‘太郎’, 25): クラス User の新しいインスタンスを作成し、名前と年齢を初期化します。
  • $user->displayInfo(): ユーザー情報を表示します。
  • $user->setAge(30): 年齢を更新します。この操作もバリデーションを通じて安全に行われます。

例外処理

} catch (Exception $e) {
    echo "エラー: " . $e->getMessage() . PHP_EOL;
}
  • try-catchブロック: エラーが発生した場合にプログラムを停止させず、安全にエラーメッセージを表示します。
  • getMessage(): 例外メッセージの内容を取得します。

まとめ

このコードではアクセス修飾子を使用してデータを保護し、カプセル化により安全にデータを操作する方法を学びました。

  • アクセス修飾子はデータを外部から守り、不正アクセスを防ぐ仕組みです。
  • カプセル化は、ゲッターとセッターを通じて安全にデータを管理し、バリデーションを実装することでデータの整合性を保ちます。

このようにオブジェクト指向プログラミングの基本を押さえることで、安全で保守しやすいコードが書けるようになります。

<<前のページ PHP記事一覧 次のページ>>

この記事への質問・コメント

この記事を作成するにあたりAIを活用しています。

問題ないことは確認していますが、もし間違いや表現の違和感などありましたら、ご指摘頂けると大変助かります。






    PHPのテキスト&問題集トップへ戻る
    トップページへ戻る