Last active
February 11, 2022 16:17
-
-
Save coisa/a59340cd7b2dc9e9654250a213ae2228 to your computer and use it in GitHub Desktop.
Defines a class to help replace static calls inside objects, using dependency injection to control the unit tests, without the need to re-implement the static call (changing every place that calls methods statically from a specific class).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| namespace CoiSA\Helper; | |
| /** | |
| * Defines a class that can be used to proxy non-static calls to the corresponding static method of an object. | |
| * It is used to help implement unit tests for classes that have static methods. | |
| * | |
| * @example | |
| * <code> | |
| * // @param string|ObjectClassName $object | |
| * public function __construct($object = null) | |
| * { | |
| * $this->object = new ProxyCallStaticMethodInterceptor($object ?: ObjectClassName::class); | |
| * } | |
| * </code> | |
| */ | |
| final class ProxyCallStaticMethodInterceptor | |
| { | |
| /** @var int Code for exception when method not exists. */ | |
| const METHOD_NOT_FOUND_CODE = 1; | |
| /** @var int Code for exception when method is not static. */ | |
| const METHOD_NOT_STATIC_CODE = 2; | |
| /** @var int Code for exception when method is not public. */ | |
| const METHOD_NOT_PUBLIC_CODE = 3; | |
| /** | |
| * @var object|string Either a string containing the name of the class to reflect, or an object. | |
| */ | |
| private $wrappedObject; | |
| /** | |
| * ProxyCallStaticMethodInterceptor constructor. | |
| * | |
| * @param object|string $wrappedObject Either a string containing the name of the class to reflect, or an object. | |
| */ | |
| public function __construct($wrappedObject) | |
| { | |
| $this->wrappedObject = $wrappedObject; | |
| } | |
| /** | |
| * Redirects calls from non-static methods to the corresponding static method of the wrapped object. | |
| * | |
| * @param string $method | |
| * @param array $args | |
| * @return mixed | |
| */ | |
| public function __call($method, array $args = []) | |
| { | |
| try { | |
| $reflectionMethod = new ReflectionMethod($this->wrappedObject, $method); | |
| } catch (ReflectionException $reflectionException) { | |
| throw new BadMethodCallException( | |
| "Method $method does not exist", | |
| self::METHOD_NOT_FOUND_CODE, | |
| $reflectionException | |
| ); | |
| } | |
| if (false === $reflectionMethod->isStatic()) { | |
| throw new BadMethodCallException("Method $method is not static", self::METHOD_NOT_STATIC_CODE); | |
| } | |
| if (false === $reflectionMethod->isPublic()) { | |
| throw new BadMethodCallException("Method $method is not public", self::METHOD_NOT_PUBLIC_CODE); | |
| } | |
| return call_user_func_array([$this->wrappedObject, $method], $args); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| namespace CoiSA\Helper\Test; | |
| use PHPUnit\Framework\TestCase; | |
| use Prophecy\Argument; | |
| final class ProxyCallStaticMethodInterceptorTest extends TestCase | |
| { | |
| public function testCallNonExistentMethodThrowBadMethodCallException() | |
| { | |
| $this->expectException(BadMethodCallException::class); | |
| $this->expectExceptionCode(ProxyCallStaticMethodInterceptor::METHOD_NOT_FOUND_CODE); | |
| $proxy = new ProxyCallStaticMethodInterceptor(stdClass::class); | |
| $proxy->nonExistentMethod(); | |
| } | |
| public function testCallNonStaticMethodThrowBadMethodCallException() | |
| { | |
| $this->expectException(BadMethodCallException::class); | |
| $this->expectExceptionCode(ProxyCallStaticMethodInterceptor::METHOD_NOT_STATIC_CODE); | |
| $object = new class { | |
| public function nonStaticMethod() | |
| { | |
| return 'nonStaticMethod'; | |
| } | |
| }; | |
| $proxy = new ProxyCallStaticMethodInterceptor($object); | |
| $proxy->nonStaticMethod(); | |
| } | |
| public function testCallNonPublicStaticMethodThrowBadMethodCallException() | |
| { | |
| $this->expectException(BadMethodCallException::class); | |
| $this->expectExceptionCode(ProxyCallStaticMethodInterceptor::METHOD_NOT_PUBLIC_CODE); | |
| $object = new class { | |
| private static function staticMethod() | |
| { | |
| return 'privateStaticMethod'; | |
| } | |
| }; | |
| $proxy = new ProxyCallStaticMethodInterceptor($object); | |
| $proxy->staticMethod(); | |
| } | |
| public function testCallWillReturnStaticMethodResult() | |
| { | |
| $args = [uniqid('arg1'), uniqid('arg2'), uniqid('arg3')]; | |
| $expected = Stub\StubStaticMethodClass::staticMethod($args); | |
| $proxy = new ProxyCallStaticMethodInterceptor(Stub\StubStaticMethodClass::class); | |
| $this->assertEquals($expected, $proxy->staticMethod($args)); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| namespace CoiSA\Helper\Test\Stub; | |
| final class StubStaticMethodClass | |
| { | |
| private static $value; | |
| public static function staticMethod() | |
| { | |
| if (empty(self::$value)) { | |
| self::$value = uniqid('test'); | |
| } | |
| return [self::$value, func_get_args()]; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment