QA@IT

定義済みメソッドの中から、特定の prefix/suffix を持つメソッド全てに同じ hook をかましたい (__call の逆バージョンみたいな)

2607 PV

やりたいこと

定義済みメソッドの中から、特定の prefix or suffix を持つメソッド全てに同じ hook をかましたい

お馴染の __call() を使った例題として Hoge クラスがあるとします。

<?php

class Hoge
{
    public function __call($theMethod, $theArgs)
    {
        if ((boolean) preg_match('/^(.+)Hoge$/', $theMethod, $matches)) {
            return "Ho " . $this->$matches[1]() . " ge";
        }
    }

    public function abc() { return "abc"; }
    public function xyz() { return "xyz"; }
    public function xyzHoge() { return "xyzHoge"; }
}

$hoge = new Hoge;

var_dump($hoge->abc(),
         $hoge->abcHoge(),
         $hoge->xyz(),
         $hoge->xyzHoge());

/**
 * 出力はこう
 *
 * string(3) "abc"
 * string(9) "Ho abc ge"
 * string(3) "xyz"
 * string(7) "xyzHoge"
 */

__call なので、もちろん定義済みの xyzHoge() は呼ばれません。

この時、xyzHoge() の結果が "Ho xyzHoge ge" になって欲しい。

<?php

    public function __hook($theMethod, $theArgs)
    {
        if ((boolean) preg_match('/^(.+)Hoge$/', $theMethod, $matches)) {
            return "Ho " . $this->$matches[1]() . " ge";
        }
    }

みたいな感じで、定義済みメソッドに対してのみ行われる __call みたいなイメージです。

なんでこんなことしたいのか

具体的に言うと、class PHPUnit_Extensions_SeleniumTestCase を継承したテストクラス書く時、
「~AndWait」 メソッドの時だけある処理を入れたいです。
全てのメソッドをオーバーライドすればいいんですが、全部書くのなんかめんどくさかったです。

  • サンプルコードで言えば、

    > この時、xyzHoge() の結果が "Ho xyzHoge ge" になって欲しい。

    "Ho xyzHoge ge" ではなく、"Ho xyz ge" でしょうか?
    -
  • いえ。 "Ho xyzHoge ge" です。 ・・と思いましたが、よくよく考えて `xyz()` でも `xyzHoge()` でもどちらでもよかったです。今回のやりたい事に関していえば、どちらかに hook できれば嬉しいです。 -

回答

自己回答です。

タイトルのような機能はわかりませんでしたが、本来やりたかった

具体的に言うと、class PHPUnit_Extensions_SeleniumTestCase を継承したテストクラス書く時、
「~AndWait」 メソッドの時だけある処理を入れたいです。

ができたので、それを載せて閉じます。

<?php
    public function __call($theMethod, $theArgs)
    {
        if ((boolean) preg_match('/^(.+)AndWait$/', $theMethod, $matches)) {
            hoge();
            parent::__call($matches[1], $theArgs);
            fuga();
        } else {
            return parent::__call($theMethod, $theArgs);
        }
    }

よくよく考えて、PHPUnit_Extensions_SeleniumTestCase の~AndWait って未定義メソッドで
元々が __call で呼ばれるものだったので、その子クラスでも同じことやればいいって気づきました。
最終的にタイトルで述べたことは地味に関係なかったです・・お手数おかけしました。

編集 履歴 (0)

委譲でしょうか。
メソッドにパラメータを渡す時はcall_user_func_array関数を使うとよいと思います。

<?php

class Hoge
{
    public function abc() { return "abc"; }
    public function xyz() { return "xyz"; }
    public function xyzHoge() { return "xyzHoge"; }
}

class Hoge2
{
    private $hoge;

    public function __construct()
    {
        $this->hoge = new Hoge;
    }

    public function __call($theMethod, $theArgs)
    {
        if ((boolean) preg_match('/^(.+)Hoge$/', $theMethod, $matches)) {
            return "Ho " . $this->hoge->$matches[1]() . " ge";
        } else {
            return $this->hoge->$theMethod();
        }
    }
}

//$hoge = new Hoge;
$hoge = new Hoge2;
var_dump($hoge->abc(),
         $hoge->abcHoge(),
         $hoge->xyz(),
         $hoge->xyzHoge());

/**
 * 出力はこう
 *
 * string(3) "abc"
 * string(9) "Ho abc ge"
 * string(3) "xyz"
 * string(7) "Ho xyz ge"
 */
編集 履歴 (1)
  • 回答ありがとうございます。今回は`PHPUnit_Extensions_SeleniumTestCase` を継承したテストクラスで行いたかったので、委譲とは少し違いました。 -
  • 継承したクラスを委譲すればいいのではないですか? -
  • 回答ありがとうございます。遅くなりました。

    phpunit で実行されるクラスは「`PHPUnit_Extensions_SeleniumTestCase` を継承したクラス」のため、委譲して後にテスト実行するには phpunit の runnner を変える必要があるような気がしています。すいません、タイトルの問題からどんどんずれていってますね。。。
    -
ウォッチ

この質問への回答やコメントをメールでお知らせします。