gallu’s blog

エンジニアでゲーマーで講師で占い師なおいちゃんのブログです。

privateやprotectdのメソッドのテストをどうやる? って話の備忘録

PHPでprivateなメソッドを外から叩く時ってどうやるんだっけ?」で、リフレクションって単語をしょっちゅう忘れるから「それの備忘録用」って見方をしないように*1
さっきもまぁ「リダイレクト……リファラー……り……り……」で、そこそこ悩んでたのは秘密だ。

おいといて。

protectedだと割と本当に色々あって、一番雑なのが
・テスト用に継承クラス作る
ってやりかた。

<?php
declare(strict_types=1);

// テスト対象のクラス
class TestTarget {
    protected function t()
    {
        return mt_rand(1, 10);
    }
}

// テスト用クラス
class Test extends TestTarget
{
    public function h() {
        return $this->t();
    }
}

//
$obj = new Test();
var_dump( $obj->h() );

PHP7の無名クラス使うなら

<?php
declare(strict_types=1);

// テスト対象のクラス
class TestTarget {
    protected function t()
    {
        return mt_rand(1, 10);
    }
}

// テスト用クラス
$obj = new class extends TestTarget {
    public function h() {
        return $this->t();
    }
};

var_dump( $obj->h() );

これでもOK。

この辺りだと、staticなメソッドでも自由自在。
継承クラス書いてもよいし、無名クラス使うんなら

<?php
declare(strict_types=1);

// テスト対象のクラス
class TestTarget {
    protected static function t()
    {
        return mt_rand(1, 10);
    }
}

// テスト用クラス
$obj = new class extends TestTarget {
    public function h() {
        return static::t();
    }
};

var_dump( $obj->h() );

とも書ける。

……で片付けたいので、正直「メソッドはprivateにすんな面倒だ」って、色々な角度から思う。
んだけど、まぁ「時すでに遅し」なケースもあろうかと思うので、少しだけ考察。

普通のメソッドなら、ReflectionMethodのsetAccessible()が手っ取り早いっつか綺麗だとは思う。

<?php
declare(strict_types=1);

// テスト対象のクラス
class TestTarget {
    private function t()
    {
        return mt_rand(1, 10);
    }
}

//
$m = new ReflectionMethod('TestTarget', 't');
$m->setAccessible(true);

var_dump( $m->invoke(new TestTarget) );

なお実はstaticも普通にいける。

<?php
declare(strict_types=1);

// テスト対象のクラス
class TestTarget {
    private static function t()
    {
        return mt_rand(1, 10);
    }
}

//
$m = new ReflectionMethod('TestTarget', 't');
$m->setAccessible(true);

var_dump( $m->invoke(new TestTarget) );

プロパティをダイレクトにやりとりする事は基本やらないので、メソッドベースだとこの辺があれば「とりあえず」かなぁ、的な。

*1:事実だが