Skip to content

Commit d94d67e

Browse files
committed
feat: add ReflectionHelper
1 parent a87171e commit d94d67e

File tree

3 files changed

+200
-0
lines changed

3 files changed

+200
-0
lines changed

src/ReflectionHelper.php

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Kenjis\PhpUnitHelper;
6+
7+
use Closure;
8+
use ReflectionClass;
9+
use ReflectionException;
10+
use ReflectionMethod;
11+
use ReflectionObject;
12+
use ReflectionProperty;
13+
14+
use function func_get_args;
15+
use function gettype;
16+
use function is_object;
17+
18+
trait ReflectionHelper
19+
{
20+
/**
21+
* @param object|string $obj object or class name
22+
* @param string $method method name
23+
*
24+
* @throws ReflectionException
25+
*/
26+
public static function getPrivateMethodInvoker($obj, string $method): Closure
27+
{
28+
$refMethod = new ReflectionMethod($obj, $method);
29+
$refMethod->setAccessible(true);
30+
$obj = gettype($obj) === 'object' ? $obj : null;
31+
32+
return static function () use ($obj, $refMethod) {
33+
$args = func_get_args();
34+
35+
return $refMethod->invokeArgs($obj, $args);
36+
};
37+
}
38+
39+
/**
40+
* @param object|string $obj
41+
*
42+
* @throws ReflectionException
43+
*/
44+
protected static function getAccessibleRefProperty($obj, string $property): ReflectionProperty
45+
{
46+
if (is_object($obj)) {
47+
$refClass = new ReflectionObject($obj);
48+
} else {
49+
$refClass = new ReflectionClass($obj);
50+
}
51+
52+
$refProperty = $refClass->getProperty($property);
53+
$refProperty->setAccessible(true);
54+
55+
return $refProperty;
56+
}
57+
58+
/**
59+
* @param object|string $obj object or class name
60+
* @param string $property property name
61+
* @param mixed $value value
62+
*
63+
* @throws ReflectionException
64+
*/
65+
public static function setPrivateProperty($obj, string $property, $value): void
66+
{
67+
$refProperty = self::getAccessibleRefProperty($obj, $property);
68+
$refProperty->setValue($obj, $value);
69+
}
70+
71+
/**
72+
* @param object|string $obj object or class name
73+
* @param string $property property name
74+
*
75+
* @return mixed value
76+
*
77+
* @throws ReflectionException
78+
*/
79+
public static function getPrivateProperty($obj, string $property)
80+
{
81+
$refProperty = self::getAccessibleRefProperty($obj, $property);
82+
83+
return $refProperty->getValue($obj);
84+
}
85+
}

tests/Fake/ForReflectionHelper.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Kenjis\PhpUnitHelper;
6+
7+
class ForReflectionHelper
8+
{
9+
/**
10+
* @var string
11+
*/
12+
private $private = 'secret';
13+
14+
/**
15+
* @var string
16+
*/
17+
private static $staticPrivate = 'xyz';
18+
19+
public function getPrivate(): string
20+
{
21+
return $this->private;
22+
}
23+
24+
public static function getStaticPrivate(): string
25+
{
26+
return self::$staticPrivate;
27+
}
28+
29+
private function privateMethod(string $param1, string $param2): string
30+
{
31+
return 'private ' . $param1 . $param2;
32+
}
33+
34+
private static function privateStaticMethod(string $param1, string$param2): string
35+
{
36+
return 'private_static ' . $param1 . $param2;
37+
}
38+
}

tests/ReflectionHelperTest.php

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Kenjis\PhpUnitHelper;
6+
7+
use PHPUnit\Framework\TestCase;
8+
9+
class ReflectionHelperTest extends TestCase
10+
{
11+
use ReflectionHelper;
12+
13+
public function test_getPrivateProperty_object(): void
14+
{
15+
$obj = new ForReflectionHelper();
16+
$actual = $this->getPrivateProperty($obj, 'private');
17+
$this->assertEquals('secret', $actual);
18+
}
19+
20+
public function test_getPrivateProperty_static(): void
21+
{
22+
$actual = $this->getPrivateProperty(
23+
ForReflectionHelper::class,
24+
'staticPrivate'
25+
);
26+
$this->assertEquals('xyz', $actual);
27+
}
28+
29+
public function test_setPrivateProperty_object(): void
30+
{
31+
$obj = new ForReflectionHelper();
32+
$this->setPrivateProperty(
33+
$obj,
34+
'private',
35+
'open'
36+
);
37+
$this->assertEquals('open', $obj->getPrivate());
38+
}
39+
40+
public function test_setPrivateProperty_static(): void
41+
{
42+
$this->setPrivateProperty(
43+
ForReflectionHelper::class,
44+
'staticPrivate',
45+
'abc'
46+
);
47+
$this->assertEquals(
48+
'abc',
49+
ForReflectionHelper::getStaticPrivate()
50+
);
51+
}
52+
53+
public function test_getPrivateMethodInvoker_object(): void
54+
{
55+
$obj = new ForReflectionHelper();
56+
$method = $this->getPrivateMethodInvoker(
57+
$obj,
58+
'privateMethod'
59+
);
60+
$this->assertEquals(
61+
'private param1param2',
62+
$method('param1', 'param2')
63+
);
64+
}
65+
66+
public function test_getPrivateMethodInvoker_static(): void
67+
{
68+
$method = $this->getPrivateMethodInvoker(
69+
ForReflectionHelper::class,
70+
'privateStaticMethod'
71+
);
72+
$this->assertEquals(
73+
'private_static param1param2',
74+
$method('param1', 'param2')
75+
);
76+
}
77+
}

0 commit comments

Comments
 (0)