__callによる未定義メソッドの呼び出し

著者:杉浦

__callによる未定義メソッドの呼び出し

 PHPには予約関数マジックメソッドがあり、__call()はその一つです。
PHP: マジックメソッド – Manual

__call() は、 アクセス不能メソッドをオブジェクトのコンテキストで実行したときに起動します。

 要は、未定義のメソッドを呼び出した時は代わりに__call()が呼ばれますよ、ということです。__call()は次の様に定義されます。

public mixed __call ( string $name , array $arguments )

$nameには呼ばれた際に使われたメソッド名、$argumentsには呼ばれた際に使われた引数が入ってきます。__call()を利用する事でな様々なことが出来ます。例えばエラーメッセージです。あるクラスが存在しないメソッドに向かってアクセスされようとした時、エラーメッセージを返すには次の様なコードが使えます。

public function __call($method, $parameters)
{
    sprintf('Method %s::%s does not exist.', static::class, $method);
}

 また、よく行うであろう動作をあらかじめ定義し、その動作の省略に割り当てるという使い方もあります。次の例はあるモデルにクエリビルダを繋ぎ、新規クエリビルダ呼び出しを省略する手法です。この手法を用いることで、クエリビルダと同等の働きができ、なおかつDBから引き出されたphp上における振る舞いのメソッドも多様に持つ、という風に見えるモデルを簡単に記述できます。

class Model
{
    public function __call($method, $parameters)
    {
        return $this->newQuery()->$method(...$parameters);
    }
    //省略
}

 クエリビルダへつなげる手法では更にクエリビルダの持つメソッドへチェーンしていくことが出来ます。これにより一見存在しないメソッドが存在するかのように振る舞います。この存在しないように見えるが使用されるメソッドが無秩序に増えた場合、コードを追うことが非常に大変な作業になります。これはgrepや参照呼出しを一発で当てられなくなるためです。何が呼び出されているかをいちいち確認する必要があることが面倒なのです。
 PHPDocを書くことでこの問題を解決できます。PHPDocの@methodはどの様なメソッドがあるかを示す文言で、多くのIDEはこれを追ってくれます。次の様に記述した場合、IDEはselectメソッド、whereメソッドが存在するかの様にModelクラスを扱ってくれます。

/**
 * @method QueryBuilder select(QueryBuilder $query)
 * @method QueryBuilder where(QueryBuilder $query)
 */
class Model
{
    public function __call($method, $parameters)
    {
        return $this->newQuery()->$method(...$parameters);
    }
    //省略
}
  • この記事いいね! (0)

著者について

杉浦 administrator