(旧版) private,protectedなメソッドを呼び出してテストする

## 注意

2018年8月に[private,protectedなメソッドを呼び出してテストする(新)](https://qiita.com/tadsan/items/8e178d6d3d19202590df)を書いたので、そちらを参考にしてください。

----------

どうしても`public`にしたくないメソッドをテストしたいなー、ってときに無理やりメソッドを呼び出す。

```php
/**
 * メソッドと同じように呼べる無名函数を返す
 */
function callMethodAsPublic($class, $method)
{
    $ref = new \ReflectionMethod($class, $method);
    $ref->setAccessible(true);
    $obj = (gettype($class) === 'object') ? $class : null;

    return function () use ($class, $ref, $obj) {
        $args = func_get_args();
        return $ref->invokeArgs($obj, $args);
    };
}
```

静的メソッドでも動的メソッドでも呼べるようにした。でもバッドノウハウくさくてうーんって感じだ。うーん…

うーんって感じなので、作ったはいいものの、自分でも使ってない。

例
--

[gistにも置いた](https://gist.github.com/zonuexe/9324923)。

```Testklass.php
<?php

class Testklass
{
   public function publicMethod ($str)
   {
        return "public: $str";
   }

   public static function publicStaticMethod ($str)
   {
        return "public+static: $str";
   }

   private function privateMethod ($str)
   {
        return "private: $str";
   }

   private static function privateStaticMethod ($str)
   {
        return "private+static: $str";
   }

   protected function protectedMethod ($str)
   {
        return "protected: $str";
   }

   protected static function protectedStaticMethod ($str)
   {
        return "protected+static: $str";
   }
}
```

```TestklassTest.php
<?php
require_once './Testklass.php';

class TestklassTest extends PHPUnit_Framework_TestCase
{
    public static function methodAsPublic ($class, $method)
    {
        $ref = new \ReflectionMethod($class, $method);
        $ref->setAccessible(true);
        $obj = (gettype($class) === 'object') ? $class : null;

        return function () use ($class, $ref, $obj) {
            $args = func_get_args();
            return $ref->invokeArgs($obj, $args);
        };
    }

    public function test_publicMethod ()
    {
        $method = self::methodAsPublic(new Testklass, 'publicMethod');
        $actual = $method('$str');
        $expected = 'public: $str';

        $this->assertSame($expected, $actual);
    }

    public function test_publicStaticMethod ()
    {
        $method = self::methodAsPublic('Testklass', 'publicStaticMethod');
        $actual = $method('$str');
        $expected = 'public+static: $str';

        $this->assertSame($expected, $actual);
    }

    public function test_privateMethod ()
    {
        $method = self::methodAsPublic(new Testklass, 'privateMethod');
        $actual = $method('$str');
        $expected = 'private: $str';

        $this->assertSame($expected, $actual);
    }

    public function test_privateStaticMethod ()
    {
        $method = self::methodAsPublic('Testklass', 'privateStaticMethod');
        $actual = $method('$str');
        $expected = 'private+static: $str';

        $this->assertSame($expected, $actual);
    }

    public function test_protectedMethod ()
    {
        $method = self::methodAsPublic(new Testklass, 'protectedMethod');
        $actual = $method('$str');
        $expected = 'protected: $str';

        $this->assertSame($expected, $actual);
    }

    public function test_protectedStaticMethod ()
    {
        $method = self::methodAsPublic('Testklass', 'protectedStaticMethod');
        $actual = $method('$str');
        $expected = 'protected+static: $str';

        $this->assertSame($expected, $actual);
    }
}
```

当然だけどテスト用途以外に使ってはならない(戒め)。