| 1 | <?php |
| 2 | |
| 3 | namespace Civi\Test; |
| 4 | |
| 5 | /** |
| 6 | * The "Invasive" helper makes it a bit easier to write unit-tests which |
| 7 | * touch upon private or protected members. |
| 8 | * |
| 9 | * @package Civi\Test |
| 10 | */ |
| 11 | class Invasive { |
| 12 | |
| 13 | /** |
| 14 | * Call a private/protected method. |
| 15 | * |
| 16 | * This is only intended for unit-testing. |
| 17 | * |
| 18 | * @param array $callable |
| 19 | * Ex: [$myObject, 'myPrivateMethod'] |
| 20 | * Ex: ['MyClass', 'myPrivateStaticMethod'] |
| 21 | * @param array $args |
| 22 | * Ordered list of arguments. |
| 23 | * @return mixed |
| 24 | */ |
| 25 | public static function call($callable, $args = []) { |
| 26 | list ($class, $object, $member) = self::parseRef($callable); |
| 27 | $reflection = new \ReflectionMethod($class, $member); |
| 28 | $reflection->setAccessible(TRUE); |
| 29 | return $reflection->invokeArgs($object, $args); |
| 30 | } |
| 31 | |
| 32 | /** |
| 33 | * Get the content of a private/protected method. |
| 34 | * |
| 35 | * This is only intended for unit-testing. |
| 36 | * |
| 37 | * @param array $ref |
| 38 | * A reference to class+property. |
| 39 | * Ex: [$myObject, 'myPrivateField'] |
| 40 | * Ex: ['MyClass', 'myPrivateStaticField'] |
| 41 | * @return mixed |
| 42 | */ |
| 43 | public static function get($ref) { |
| 44 | list ($class, $object, $member) = self::parseRef($ref); |
| 45 | $reflection = new \ReflectionProperty($class, $member); |
| 46 | $reflection->setAccessible(TRUE); |
| 47 | return $reflection->getValue($object); |
| 48 | } |
| 49 | |
| 50 | /** |
| 51 | * Get the content of a private/protected method. |
| 52 | * |
| 53 | * This is only intended for unit-testing. |
| 54 | * |
| 55 | * @param array $ref |
| 56 | * A reference to class+property. |
| 57 | * Ex: [$myObject, 'myPrivateField'] |
| 58 | * Ex: ['MyClass', 'myPrivateStaticField'] |
| 59 | * @param mixed $value |
| 60 | * @return mixed |
| 61 | */ |
| 62 | public static function set($ref, $value) { |
| 63 | list ($class, $object, $member) = self::parseRef($ref); |
| 64 | $reflection = new \ReflectionProperty($class, $member); |
| 65 | $reflection->setAccessible(TRUE); |
| 66 | $reflection->setValue($object, $value); |
| 67 | } |
| 68 | |
| 69 | /** |
| 70 | * @param array $callable |
| 71 | * Ex: [$myObject, 'myPrivateMember'] |
| 72 | * Ex: ['MyClass', 'myPrivateStaticMember'] |
| 73 | * @return array |
| 74 | * Ordered array of [string $class, object? $object, string $memberName]. |
| 75 | */ |
| 76 | private static function parseRef($callable) { |
| 77 | if (is_string($callable)) { |
| 78 | list ($class, $member) = explode('::', $callable); |
| 79 | return [$class, NULL, $member]; |
| 80 | } |
| 81 | elseif (is_string($callable[0])) { |
| 82 | return [$callable[0], NULL, $callable[1]]; |
| 83 | } |
| 84 | elseif (is_object($callable[0])) { |
| 85 | return [get_class($callable[0]), $callable[0], $callable[1]]; |
| 86 | } |
| 87 | else { |
| 88 | throw new \RuntimeException("Cannot parse reference to private member"); |
| 89 | } |
| 90 | } |
| 91 | |
| 92 | } |