基礎

PHPのアクセス修飾子|public・protected・privateの違いと使い方

PHPのアクセス修飾子は、クラスのプロパティやメソッドへのアクセス範囲を制御するキーワードです。public(どこからでもアクセス可能)、protected(自クラスと子クラスからのみ)、private(自クラスからのみ)の3種類があります。

アクセス修飾子を適切に設定することで、クラスの内部実装を外部から隠蔽し、意図しない変更を防ぐカプセル化を実現できます。これはオブジェクト指向設計の基本原則のひとつです。

基本的な使い方

PHP
<?php
class User {
    public string $name;        // どこからでもアクセス可能
    protected string $email;    // 自クラスと子クラスのみ
    private string $password;   // 自クラスのみ

    public function __construct(string $name, string $email, string $password) {
        $this->name = $name;
        $this->email = $email;
        $this->password = password_hash($password, PASSWORD_DEFAULT);
    }

    public function getEmail(): string {
        return $this->email;
    }

    public function verifyPassword(string $input): bool {
        return password_verify($input, $this->password);
    }
}

$user = new User("田中", "tanaka@example.com", "secret123");

echo $user->name . "\n";          // OK: public
echo $user->getEmail() . "\n";    // OK: publicメソッド経由
// echo $user->email;              // Error: protected
// echo $user->password;           // Error: private

echo "パスワード検証: " . ($user->verifyPassword("secret123") ? "成功" : "失敗") . "\n";
実行結果
田中
tanaka@example.com
パスワード検証: 成功

アクセス範囲の比較

PHP
<?php
class ParentClass {
    public string $pub = "public";
    protected string $prot = "protected";
    private string $priv = "private";

    public function showAll(): void {
        // 自クラス内:すべてアクセス可能
        echo "自クラス: {$this->pub}, {$this->prot}, {$this->priv}\n";
    }
}

class ChildClass extends ParentClass {
    public function showFromChild(): void {
        echo "子クラス: {$this->pub}, {$this->prot}\n";
        // echo $this->priv;  // Error: private は子クラスからもアクセス不可
    }
}

$parent = new ParentClass();
$parent->showAll();

$child = new ChildClass();
$child->showFromChild();

// 外部からのアクセス
echo "外部: {$parent->pub}\n";
// echo $parent->prot;  // Error
// echo $parent->priv;  // Error
実行結果
自クラス: public, protected, private
子クラス: public, protected
外部: public

この表がアクセス範囲をまとめたものです。

アクセス範囲の一覧

public:自クラス ○ / 子クラス ○ / 外部 ○
protected:自クラス ○ / 子クラス ○ / 外部 ×
private:自クラス ○ / 子クラス × / 外部 ×

getter/setterパターン

privateプロパティに対してpublicなgetter/setterメソッドを用意する設計パターンです。

PHP
<?php
class Temperature {
    private float $celsius;

    public function __construct(float $celsius) {
        $this->setCelsius($celsius);
    }

    public function getCelsius(): float {
        return $this->celsius;
    }

    public function setCelsius(float $value): void {
        if ($value < -273.15) {
            throw new InvalidArgumentException("絶対零度以下は設定できません");
        }
        $this->celsius = $value;
    }

    public function getFahrenheit(): float {
        return $this->celsius * 9 / 5 + 32;
    }
}

$temp = new Temperature(100);
echo "{$temp->getCelsius()}°C = {$temp->getFahrenheit()}°F\n";

$temp->setCelsius(0);
echo "{$temp->getCelsius()}°C = {$temp->getFahrenheit()}°F\n";

try {
    $temp->setCelsius(-300);
} catch (InvalidArgumentException $e) {
    echo "エラー: {$e->getMessage()}\n";
}
実行結果
100°C = 212°F
0°C = 32°F
エラー: 絶対零度以下は設定できません

実用的な例

PHP
<?php
class DatabaseConnection {
    private static ?self $instance = null;
    private string $status = "disconnected";

    // privateコンストラクタ:外部からのnewを禁止
    private function __construct(
        private string $host,
        private string $dbName
    ) {
        $this->status = "connected";
    }

    // シングルトンパターン
    public static function getInstance(string $host = "localhost", string $db = "app"): self {
        if (self::$instance === null) {
            self::$instance = new self($host, $db);
        }
        return self::$instance;
    }

    public function getStatus(): string {
        return "{$this->host}/{$this->dbName}: {$this->status}";
    }
}

$db1 = DatabaseConnection::getInstance("localhost", "myapp");
$db2 = DatabaseConnection::getInstance();  // 同じインスタンス

echo $db1->getStatus() . "\n";
echo ($db1 === $db2 ? "同一インスタンス" : "別インスタンス") . "\n";
実行結果
localhost/myapp: connected
同一インスタンス
設計の指針

迷ったらまず private にして、必要に応じて公開範囲を広げましょう。一度 public にしたプロパティを後から private に変更すると、利用側のコードが壊れる可能性があります。最初は厳しく制限し、必要に応じて緩める方が安全です。

まとめ

  • public:どこからでもアクセス可能
  • protected:自クラスと子クラスからのみアクセス可能
  • private:自クラスからのみアクセス可能
  • getter/setterパターンでバリデーション付きのアクセスを提供できる
  • まず private で始め、必要に応じて公開範囲を広げるのが設計のコツ