自動で使えるマジックメソッド

コンストラクターを作成するとき、「__construct」というメソッドを定義しました。このアンダースコア2つから始まるメソッドは、PHPのクラス定義にあらかじめ決められている「マジックメソッド」と呼ばれるメソッドの一つです。次の種類があり、それぞれ決められたタイミングで呼び出されます。

__constructコンストラクター。生成される時に実行される
__destructデストラクター。利用を終了するときに実行される
__callprivate, protectedなどで宣言されたメソッドが呼び出されたとき
__callStatic同上の静的メソッドが呼び出されたとき
__get同上のプロパティを呼び出されたとき
__set同上のプロパティに値を代入しようとしたとき
__issetisset, emptyのパラメーターとして同上のプロパティを指定したとき
__unsetunsetのパラメーターとして同上のプロパティが呼び出されたとき
__debugInfovar_dumpのパラメーターに指定されたとき
__sleepserialize()が実行されるとき
__wakeupunserialize()が実行されるとき
__invokeインスタンスをファンクションとして呼び出したとき
__set_statevar_export() によって エクスポートされるとき
__cloneインスタンスがクローンされるとき

インスタンスを直接出力できる __toString

例えば、「__toString」を利用すると、インスタンスを直接出力できるようになります。例えば、次のようなクラスを準備しましょう。

class Item {
  public string $name;
  public string $price;

  // インスタンスの内容を出力する
  public function __toString() {
    return $this->name, ' / ', number_format($this->price), '円';
  }
}

これで次のようにインスタンスを作成しましょう。

$item = new Item();
$item->name = 'PHP入門';
$item->price = 2300;

そして、この「$item」を直接画面に出力してみます。

echo $item;

すると、自動的に「__toString」メソッドが呼び出されて、次のように画面に表示されます。

PHP入門 / 1,500円

プロパティを決められたフォーマットで出力することが多い場合などに、便利に利用できます。

プロパティの代わりにゲッター・セッターを準備する – __get, __set

プロパティに直接アクセスしてしまうと、不正な値を代入してしまうことがあるため、ゲッターやセッターを準備するのが一般的です。しかし、「setXXX」や「getXXX」といった独自のメソッドをプロパティの数だけ準備する代わりに、マジックメソッドを利用するとスマートに実装することができます。次の例を見てみましょう。

class Item {
  private string $name;
}

ここでは、商品名を管理する「$item」というプロパティを定義しましたが、privateで宣言しているためこのままでは次のように呼び出すことはできません。

$item = new Item();
$item->name = 'PHP入門';

ここで、次のようにマジックメソッドを定義します。

class Item {
  private $props = [];

  // セッター
  public function __set($name, $value) {
    $this->props[$name] = $value;
  }
  // ゲッター
  public function __get($name) {
    return $this->props[$name];
  }
}

こうすると、次のように「$name」というプロパティ(のようなもの)に値を入れることができます。

$item = new Item();
$item->name = 'PHP入門';

この時、正確には「$name」というプロパティがあるわけではなく、「$props」という配列のプロパティがあり、そこの各プロパティの要素を格納するというしくみになっています。これを利用するメリットは、セッター・ゲッターとして検査などを入れやすい点があります。

検査のロジックを入れる

次のように検査ロジックを入れやすいことがあります。

  // セッター
  public function __set($name, $value) {
    if ($name === 'name' && $value === '') {
      // 名前が空の場合は「名前未設定」と代入する
      $this->props[$name] = '名称未設定';
    } else {
      $this->props[$name] = $value;
    }
  }

うまく利用すると便利ですが、どんなプロパティがあるかなどが分かりにくくなってしまうため、多用はしない方がよいでしょう。

ともすたチャンネルに
チャンネル登録する