基礎

PHPの__getメソッド|アクセスできないプロパティの読み取りを制御する

PHPの__get()は、アクセスできないプロパティ(未定義またはprivate/protected)を読み取ろうとしたときに自動的に呼び出されるマジックメソッドです。動的なプロパティアクセスや、仮想的なプロパティの提供に使われます。

例えば、データベースから取得したカラムを動的にプロパティとしてアクセスしたり、計算結果を仮想プロパティとして公開したりする場面で活用できます。

基本的な使い方

PHP
<?php
class MagicProperty {
    private array $data = [
        "name" => "田中",
        "age" => 30,
        "email" => "tanaka@example.com",
    ];

    public function __get(string $name): mixed {
        if (isset($this->data[$name])) {
            return $this->data[$name];
        }
        throw new RuntimeException("プロパティ '{$name}' は存在しません");
    }
}

$obj = new MagicProperty();
echo $obj->name . "\n";
echo $obj->age . "\n";
echo $obj->email . "\n";

try {
    echo $obj->phone;
} catch (RuntimeException $e) {
    echo "エラー: " . $e->getMessage() . "\n";
}
実行結果
田中
30
tanaka@example.com
エラー: プロパティ 'phone' は存在しません

$obj->name にアクセスすると、name というpublicプロパティが存在しないため、__get("name") が呼ばれます。内部の配列から値を返すことで、あたかもプロパティが存在するかのようにアクセスできます。

仮想プロパティの実装

計算結果を仮想的なプロパティとして提供できます。

PHP
<?php
class Circle {
    public function __construct(private float $radius) {}

    public function __get(string $name): float {
        return match($name) {
            "diameter" => $this->radius * 2,
            "area" => M_PI * $this->radius ** 2,
            "circumference" => 2 * M_PI * $this->radius,
            default => throw new RuntimeException("未定義のプロパティ: {$name}")
        };
    }
}

$circle = new Circle(5);
echo "半径: 5\n";
echo "直径: {$circle->diameter}\n";
echo "面積: " . round($circle->area, 2) . "\n";
echo "円周: " . round($circle->circumference, 2) . "\n";
実行結果
半径: 5
直径: 10
面積: 78.54
円周: 31.42

データアクセスオブジェクト

PHP
<?php
class DataObject {
    private array $attributes;

    public function __construct(array $data = []) {
        $this->attributes = $data;
    }

    public function __get(string $name): mixed {
        return $this->attributes[$name] ?? null;
    }

    public function __isset(string $name): bool {
        return isset($this->attributes[$name]);
    }
}

// データベースの行をオブジェクトとして扱う
$row = new DataObject([
    "id" => 1,
    "username" => "tanaka",
    "email" => "tanaka@example.com",
    "created_at" => "2026-01-15",
]);

echo "ID: {$row->id}\n";
echo "ユーザー名: {$row->username}\n";
echo "メール: {$row->email}\n";

if (isset($row->created_at)) {
    echo "作成日: {$row->created_at}\n";
}
echo "削除日: " . ($row->deleted_at ?? "未削除") . "\n";
実行結果
ID: 1
ユーザー名: tanaka
メール: tanaka@example.com
作成日: 2026-01-15
削除日: 未削除

実用的な例

PHP
<?php
class Config {
    private array $settings;

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

    public function __get(string $name): mixed {
        $value = $this->settings[$name] ?? null;
        // ネストした配列もConfigオブジェクトとして返す
        if (is_array($value)) {
            return new self($value);
        }
        return $value;
    }

    public function __isset(string $name): bool {
        return isset($this->settings[$name]);
    }
}

$config = new Config([
    "app" => [
        "name" => "MyApp",
        "version" => "1.0",
        "debug" => true,
    ],
    "db" => [
        "host" => "localhost",
        "port" => 3306,
    ],
]);

echo $config->app->name . "\n";
echo $config->app->version . "\n";
echo $config->db->host . ":" . $config->db->port . "\n";
実行結果
MyApp
1.0
localhost:3306
__issetとセットで使う

__get() を定義する場合は、__isset() も一緒に定義しましょう。isset($obj->prop)empty($obj->prop) が正しく動作するために必要です。__isset() がないと、存在するはずのプロパティでも isset()false を返します。

注意

__get() はpublicプロパティが見つからない場合にのみ呼ばれます。同名のpublicプロパティが存在する場合は __get() は呼ばれません。また、パフォーマンスへの影響があるため、頻繁にアクセスされるプロパティには通常のプロパティ定義を使う方が効率的です。

まとめ

  • __get() はアクセスできないプロパティを読み取ろうとしたときに呼ばれる
  • 動的なプロパティアクセスや仮想プロパティの実装に使える
  • __isset() とセットで定義するのが推奨される
  • 設定オブジェクトやデータアクセスオブジェクトなどで活躍する
  • パフォーマンスへの影響があるため、頻繁なアクセスには通常のプロパティを使う