基礎

PHPのプロパティ変更|オブジェクトのプロパティ値を操作する方法

PHPのオブジェクトが持つプロパティは、インスタンスの生成後も値を変更することができます。-> 演算子を使ってプロパティにアクセスし、代入演算子で新しい値を設定します。

ただし、プロパティを直接変更できるのは public なプロパティだけです。データの整合性を保つため、実際の開発では setter メソッドを通じて変更するのが一般的です。ここではプロパティの変更方法と、安全な値の管理方法を解説します。

基本的な使い方

public プロパティは、オブジェクトの外部から直接読み書きできます。

PHP
<?php
class User {
    public string $name;
    public int $age;

    public function __construct(string $name, int $age) {
        $this->name = $name;
        $this->age = $age;
    }
}

$user = new User("田中", 25);
echo "変更前: {$user->name}({$user->age}歳)\n";

// プロパティを変更
$user->name = "佐藤";
$user->age = 30;
echo "変更後: {$user->name}({$user->age}歳)\n";
実行結果
変更前: 田中(25歳)
変更後: 佐藤(30歳)

setterメソッドによる安全な変更

プロパティを private にし、setterメソッドを通じて値を変更すると、バリデーションを挟むことができます。

PHP
<?php
class Product {
    private string $name;
    private int $price;
    private int $stock;

    public function __construct(string $name, int $price, int $stock) {
        $this->name = $name;
        $this->setPrice($price);
        $this->setStock($stock);
    }

    // getter
    public function getName(): string { return $this->name; }
    public function getPrice(): int { return $this->price; }
    public function getStock(): int { return $this->stock; }

    // setter(バリデーション付き)
    public function setPrice(int $price): void {
        if ($price < 0) {
            throw new InvalidArgumentException("価格は0以上にしてください");
        }
        $this->price = $price;
    }

    public function setStock(int $stock): void {
        if ($stock < 0) {
            throw new InvalidArgumentException("在庫は0以上にしてください");
        }
        $this->stock = $stock;
    }
}

$product = new Product("りんご", 150, 100);
echo "{$product->getName()}: {$product->getPrice()}円(在庫{$product->getStock()})\n";

$product->setPrice(200);
$product->setStock(80);
echo "{$product->getName()}: {$product->getPrice()}円(在庫{$product->getStock()})\n";

// 不正な値はエラーになる
try {
    $product->setPrice(-100);
} catch (InvalidArgumentException $e) {
    echo "エラー: " . $e->getMessage() . "\n";
}
実行結果
りんご: 150円(在庫100)
りんご: 200円(在庫80)
エラー: 価格は0以上にしてください

メソッドチェーンによる変更

setterメソッドが $this を返すようにすると、メソッドチェーンで複数のプロパティを連続して変更できます。

PHP
<?php
class QueryBuilder {
    private string $table = "";
    private array $conditions = [];
    private ?int $limit = null;

    public function from(string $table): self {
        $this->table = $table;
        return $this;
    }

    public function where(string $condition): self {
        $this->conditions[] = $condition;
        return $this;
    }

    public function limit(int $limit): self {
        $this->limit = $limit;
        return $this;
    }

    public function toSQL(): string {
        $sql = "SELECT * FROM {$this->table}";
        if (!empty($this->conditions)) {
            $sql .= " WHERE " . implode(" AND ", $this->conditions);
        }
        if ($this->limit !== null) {
            $sql .= " LIMIT {$this->limit}";
        }
        return $sql;
    }
}

$query = (new QueryBuilder())
    ->from("users")
    ->where("age >= 20")
    ->where("active = 1")
    ->limit(10)
    ->toSQL();

echo $query . "\n";
実行結果
SELECT * FROM users WHERE age >= 20 AND active = 1 LIMIT 10

readonlyプロパティ(PHP 8.1+)

PHP 8.1以降では readonly キーワードで、一度だけ代入可能なプロパティを定義できます。

PHP
<?php
class ImmutableUser {
    public function __construct(
        public readonly string $name,
        public readonly int $age
    ) {}
}

$user = new ImmutableUser("田中", 25);
echo "{$user->name}({$user->age}歳)\n";

// $user->name = "佐藤";  // Error: Cannot modify readonly property
実行結果
田中(25歳)
ポイント

getter/setterパターン(カプセル化)は面倒に感じるかもしれませんが、後から「価格変更時にログを記録する」「在庫変更時に通知を送る」といった処理を追加しやすくなります。大規模な開発では必須のテクニックです。

注意

publicプロパティは外部から自由に変更できるため、意図しない値(負の価格やnullの名前など)がセットされるリスクがあります。データの整合性が重要な場合は、privateプロパティ + setterメソッドで保護しましょう。

まとめ

  • -> 演算子でpublicプロパティの値を直接変更できる
  • setterメソッドを使うとバリデーション付きの安全な変更が可能
  • setterが $this を返すとメソッドチェーンが実現できる
  • PHP 8.1の readonly で変更不可のプロパティを定義できる
  • カプセル化(private + setter)はデータの整合性を保つ基本テクニック