PHP

トレイトによるアクセサの自動実装

More than 1 year has passed since last update.

2016年6月30日 更新


  • リフレクションを使わない方法を思いついたので,オーバーヘッドの少ない方法に変更しました.

  • 型チェックはPHP7.0+のスカラータイプヒントにしました.


実装

マジックメソッド__call()を利用してGetterメソッドとして実装するのは大文字小文字の区別などの面で厄介事が多いので,素直にマジックメソッド__get()を利用して外部から読み取り可能なプロパティとして実装することにしました.


全プロパティを対象にする


トレイト定義

<?php

trait AllReadable
{
public function __get(string $name)
{
if (array_key_exists($name, get_object_vars($this))) {
return $this->$name;
}
if (property_exists($this, $name)) {
throw new \OutOfRangeException("Cannot access static property: $name");
}
throw new \OutOfRangeException("Undefined property: $name");
}

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



使用例

class Test

{
use AllReadable;

private $a = 'A';
protected $b = 'B';
public static $c = 'C';
}

$t = new Test;
echo $t->a; // A
echo $t->b; // B
echo $t->c; // Cannot access static property: c



$__readableで指定したプロパティのみを対象にする

少し気持ち悪いかもしれませんが,マジックメソッド__get()が存在しているのであれば,まぁPHPらしくプロパティ$__readableなんか作っちゃってもいいかなぁと.ちなみにこのプロパティ自体は静的プロパティであってもインスタンスプロパティであっても動作しますが,前者として書いておいた方が望ましいでしょう.


トレイト定義

<?php

trait PartiallyReadable
{
public function __get(string $name)
{
if (array_key_exists($name, get_object_vars($this))) {
if (in_array($name, (array)(static::$__readable ?? []), true)) {
return $this->$name;
}
throw new \OutOfRangeException("Inaccessible property: $name");
}
if (property_exists($this, $name)) {
throw new \OutOfRangeException("Cannot access static property: $name");
}
throw new \OutOfRangeException("Undefined property: $name");
}

public function __isset(string $name) : bool
{
return in_array($name, (array)(static::$__readable ?? []), true)
& isset($this->$name);
}
}



使用例

class Test

{
use PartiallyReadable;
protected static $__readable = ['a', 'c', 'd'];

private $a = 'A';
protected $b = 'B';
public static $c = 'C';
}

$t = new Test;
echo $t->a; // A
echo $t->b; // Inaccessible property: b
echo $t->c; // Cannot access static property: c
echo $t->d; // Undefined property: d