diff --git a/.gitattributes b/.gitattributes index b1f085d..d5b4710 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,6 +1,6 @@ -# Auto detect text files and perform LF normalization -*.* text=auto +*.* text=lf tests/ export-ignore .travis.yml export-ignore .phpunit.xml.dist export-ignore +README.md export-ignore diff --git a/.travis.yml b/.travis.yml index 49dc447..55b6608 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,9 @@ language: php php: - - 5.4 - - 5.5 - 5.6 - 7 - - hhvm + - 7.1 before_script: - curl -s http://getcomposer.org/installer | php diff --git a/LICENSE b/LICENSE index 44344d1..48ba0d9 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2015 Giuseppe Mazzapica +Copyright (c) 2017 Giuseppe Mazzapica Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 560aec0..21434c9 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,9 @@ ------- -[![travis-ci status](https://img.shields.io/travis/Giuseppe-Mazzapica/Andrew.svg?style=flat-square)](https://travis-ci.org/Giuseppe-Mazzapica/Andrew) -[![codecov.io](https://img.shields.io/codecov/c/github/Giuseppe-Mazzapica/Andrew.svg?style=flat-square)](http://codecov.io/github/Giuseppe-Mazzapica/Andrew?branch=master) -[![license](https://img.shields.io/github/license/Giuseppe-Mazzapica/Andrew.svg?style=flat-square)](http://opensource.org/licenses/MIT) +[![travis-ci status](https://img.shields.io/travis/gmazzap/Andrew.svg?style=flat-square)](https://travis-ci.org/Giuseppe-Mazzapica/Andrew) +[![codecov.io](https://img.shields.io/codecov/c/github/gmazzap/Andrew.svg?style=flat-square)](http://codecov.io/github/Giuseppe-Mazzapica/Andrew?branch=master) +[![license](https://img.shields.io/github/license/gmazzap/Andrew.svg?style=flat-square)](http://opensource.org/licenses/MIT) ------- @@ -22,12 +22,20 @@ It provides 2 "proxy" objects, one for dynamic properties and methods, the other Let's assume following class ```php -class Foo +class Subject { private $var = 'I am private'; + public function getVar() { + return $this->var; + } + + public function hasVar() { + return isset($this->var); + } + private function testMe() { - return 'I am private'; + return 'I am private'; } } ``` @@ -35,53 +43,63 @@ class Foo With *Andrew* is possible to: ```php -$proxy = new Andrew\Proxy(new Foo()); +$subject = new Subject(); -// getter +$proxy = new Andrew\Proxy($subject); + +// get subject private var via proxy echo $proxy->var; // 'I am private' -// setter +// set subject private var via proxy $proxy->var = 'I WAS private'; -echo $proxy->var; // 'I WAS private' +echo $subject->getVar(); // 'I WAS private' -// isser +// check subject private var is set via proxy isset($proxy->var); // true -// unsetter +// unset subject private var via proxy unset($proxy->var); -isset($proxy->var); // false +$subject->hasVar(); // false -// caller +// call subject private method via proxy echo $proxy->testMe() // 'I am private' ``` +The `Subject` class example has public getter and isser for its private variable, that we added for +test purposes, bu Andrew proxy is, of course, more useful when classes does not provide that +possibility. + # Static Proxy Let's assume following class ```php -class Foo +class Subject { - private static $var = 'I am private static'; + private static $var = 'I am private static'; - private static function testMe() { - return 'I am private static'; - } + public static function getVar() { + return self::$var; + } + + private static function testMe() { + return 'I am private static'; + } } ``` With *Andrew* is possible to: ```php -$proxy = new Andrew\StaticProxy('Foo'); // we pass class name, not object +$proxy = new Andrew\StaticProxy(Subject::class); // we pass class name, not object // getter echo $proxy->var; // 'I am private static' // setter $proxy->var = 'I WAS private static'; -echo $proxy->var; // 'I WAS private static' +echo Subject::getVar(); // 'I WAS private static' // isser isset($proxy->var); // true @@ -90,7 +108,7 @@ isset($proxy->var); // true echo $proxy->testMe() // 'I am private static' ``` -Note that `StaticProxy` has **not** unsetter, because PHP [does not allow unsett static variables](http://3v4l.org/91GTk). +Note that `StaticProxy` has **not** unsetter, because PHP [does not allow to unset static variables](http://3v4l.org/91GTk). If you try to unset anything on a `StaticProxy` object, *Andrew* will throw an Exception. @@ -119,7 +137,7 @@ No. But may be quite useful in unit tests. # Requirements -*Andrew* has no dependencies. Requires PHP 5.4+, works with PHP 7 and HHVM. +*Andrew* has no dependencies. Requires PHP 5.6+, works with PHP 7 and 7.1. # License diff --git a/composer.json b/composer.json index 8c6d22f..3a1010b 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,6 @@ { "name": "Giuseppe Mazzapica", "email": "giuseppe.mazzapica@gmail.com", - "homepage": "http://gm.zoomlab.it", "role": "Developer" } ], @@ -28,10 +27,10 @@ }, "minimum-stability": "stable", "require": { - "php": ">=5.4" + "php": ">=5.6" }, "require-dev": { - "phpunit/phpunit": "~4.4" + "phpunit/phpunit": "5.7.*" }, "config": { "optimize-autoloader": true diff --git a/phpunit.xml.dist b/phpunit.xml.dist index e4eaca4..f7a3632 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,5 +1,5 @@ ['assertProperty', 'Undeclared properties can not be retrieved.'], + self::SETTER => ['assertProperty', 'Undeclared properties can not be set.'], + self::ISSER => ['assertProperty', 'Undeclared properties can not be checked.'], + self::UNSETTER => ['assertProperty', 'Undeclared properties can not be unset.'], + self::CALLER => ['assertMethod', 'Undeclared methods can not be called.'], + ]; + /** * @var string */ private $class; /** - * @var object + * @var mixed */ private $object; @@ -36,16 +45,27 @@ final class DynamicCallbacks implements CallbacksInterface private $checker; /** - * @param object $object + * @var \Closure[] + */ + private $callbacks = []; + + /** + * @param mixed $object * @param \Andrew\Checker\Checker $checker + * @throws \Andrew\Exception\ClassException + * @throws \Andrew\Exception\ArgumentException */ public function __construct($object, Checker $checker = null) { - is_null($checker) and $checker = new Checker(); + $checker or $checker = new Checker(); $checker->assertObject($object, __CLASS__.' expects an object.'); + $class = get_class($object); + if (ltrim($class, '\\') === 'stdClass') { + throw new ClassException('It is not possible to use proxy with stdClass.'); + } $this->checker = $checker; $this->object = $object; - $this->class = get_class($object); + $this->class = $class; } /** @@ -53,14 +73,7 @@ public function __construct($object, Checker $checker = null) */ public function getter() { - $checker = $this->checker; - $getter = function ($var) use ($checker) { - $checker->assertProperty($this, $var, 'Undeclared properties can not be retrieved.'); - - return $this->$var; - }; - - return Closure::bind($getter, $this->object, $this->class); + return $this->createCallback(self::GETTER); } /** @@ -68,13 +81,7 @@ public function getter() */ public function setter() { - $checker = $this->checker; - $setter = function ($var, $value) use ($checker) { - $checker->assertProperty($this, $var, 'Undeclared properties can not be set.'); - $this->$var = $value; - }; - - return Closure::bind($setter, $this->object, $this->class); + return $this->createCallback(self::SETTER); } /** @@ -82,14 +89,7 @@ public function setter() */ public function isser() { - $checker = $this->checker; - $isser = function ($var) use ($checker) { - $checker->assertProperty($this, $var, 'Undeclared properties can not be checked.'); - - return isset($this->$var); - }; - - return Closure::bind($isser, $this->object, $this->class); + return $this->createCallback(self::ISSER); } /** @@ -97,13 +97,7 @@ public function isser() */ public function unsetter() { - $checker = $this->checker; - $unsetter = function ($var) use ($checker) { - $checker->assertProperty($this, $var, 'Undeclared properties can not be unset.'); - unset($this->$var); - }; - - return Closure::bind($unsetter, $this->object, $this->class); + return $this->createCallback(self::UNSETTER); } /** @@ -111,13 +105,51 @@ public function unsetter() */ public function caller() { - $checker = $this->checker; - $caller = function ($method, $args) use ($checker) { - $checker->assertMethod($this, $method, 'Undeclared methods can not be called.'); + return $this->createCallback(self::CALLER); + } - return call_user_func_array([$this, $method], $args); + /** + * @param string $which + * @return \Closure + */ + private function createCallback($which) + { + if (isset($this->callbacks[$which])) { + // @codeCoverageIgnoreStart + return $this->callbacks[$which]; + // @codeCoverageIgnoreEnd + } + + $checker = $this->checker; + $object = $this->object; + + $caller = function ($key, $value = null) use ($which, $checker, $object) { + list($checkMethod, $checkMessage) = DynamicCallbacks::TYPE_CHECKS_MAP[$which]; + /** @var callable $checkerCallback */ + $checkerCallback = [$checker, $checkMethod]; + $checkerCallback($object, $key, $checkMessage); + + switch ($which) { + case DynamicCallbacks::CALLER: + /** @var callable $method */ + $method = [$this, $key]; + + return $value ? $method(...$value) : $method(); + case DynamicCallbacks::GETTER: + return $this->{$key}; + case DynamicCallbacks::SETTER: + $this->{$key} = $value; + break; + case DynamicCallbacks::ISSER: + return isset($this->{$key}); + case DynamicCallbacks::UNSETTER: + unset($this->{$key}); + break; + } }; - return Closure::bind($caller, $this->object, $this->class); + $this->callbacks[$which] = Closure::bind($caller, $this->object, $this->class); + + return $this->callbacks[$which]; } } diff --git a/src/Callbacks/StaticCallbacks.php b/src/Callbacks/StaticCallbacks.php index cac1d55..e27027f 100644 --- a/src/Callbacks/StaticCallbacks.php +++ b/src/Callbacks/StaticCallbacks.php @@ -11,6 +11,7 @@ namespace Andrew\Callbacks; use Andrew\Checker\Checker; +use Andrew\Exception\ClassException; use Andrew\Exception\RuntimeException; use Closure; use ReflectionClass; @@ -22,6 +23,25 @@ */ final class StaticCallbacks implements CallbacksInterface { + const TYPE_CHECKS_MAP = [ + self::GETTER => [ + 'assertStaticProperty', + 'Undeclared static properties can not be retrieved.' + ], + self::SETTER => [ + 'assertStaticProperty', + 'Undeclared static properties can not be set.' + ], + self::ISSER => [ + 'assertStaticProperty', + 'Undeclared static properties can not be checked.' + ], + self::CALLER => [ + 'assertStaticMethod', + 'Undeclared static methods can not be called.' + ], + ]; + /** * @var string */ @@ -37,13 +57,23 @@ final class StaticCallbacks implements CallbacksInterface */ private $checker; + /** + * @var \Closure[] + */ + private $callbacks = []; + /** * @param string $class * @param \Andrew\Checker\Checker $checker + * @throws \Andrew\Exception\ClassException + * @throws \Andrew\Exception\ArgumentException */ public function __construct($class, Checker $checker = null) { - is_null($checker) and $checker = new Checker(); + if (ltrim($class, '\\') === 'stdClass') { + throw new ClassException('It is not possible to use static proxy with stdClass.'); + } + $checker or $checker = new Checker(); $checker->assertClass($class, __CLASS__.' expects a fully qualified class name.'); $this->checker = $checker; $this->class = $class; @@ -55,18 +85,7 @@ public function __construct($class, Checker $checker = null) */ public function getter() { - $checker = $this->checker; - $getter = function ($var) use ($checker) { - $checker->assertStaticProperty( - get_called_class(), - $var, - 'Undeclared static properties can not be retrieved.' - ); - - return static::$$var; - }; - - return Closure::bind($getter, $this->object, $this->class); + return $this->createCallback(self::GETTER); } /** @@ -74,17 +93,7 @@ public function getter() */ public function setter() { - $checker = $this->checker; - $setter = function ($var, $value) use ($checker) { - $checker->assertStaticProperty( - get_called_class(), - $var, - 'Undeclared static properties can not be set.' - ); - static::$$var = $value; - }; - - return Closure::bind($setter, $this->object, $this->class); + return $this->createCallback(self::SETTER); } /** @@ -92,22 +101,12 @@ public function setter() */ public function isser() { - $checker = $this->checker; - $isser = function ($var) use ($checker) { - $checker->assertStaticProperty( - get_called_class(), - $var, - 'Undeclared static properties can not be checked.' - ); - - return isset(static::$$var); - }; - - return Closure::bind($isser, $this->object, $this->class); + return $this->createCallback(self::ISSER); } /** * @return void + * @throws \Andrew\Exception\RuntimeException */ public function unsetter() { @@ -119,18 +118,48 @@ public function unsetter() */ public function caller() { + return $this->createCallback(self::CALLER); + } + + /** + * @param string $which + * @return \Closure + */ + private function createCallback($which) + { + if (isset($this->callbacks[$which])) { + // @codeCoverageIgnoreStart + return $this->callbacks[$which]; + // @codeCoverageIgnoreEnd + } + $checker = $this->checker; - $caller = function ($method, $args) use ($checker) { - $class = get_called_class(); - $checker->assertStaticMethod( - $class, - $method, - 'Undeclared static methods can not be called.' - ); - - return call_user_func_array([$class, $method], $args); + $class = $this->class; + + $caller = function ($key, $value = null) use ($which, $checker, $class) { + list($checkMethod, $checkMessage) = StaticCallbacks::TYPE_CHECKS_MAP[$which]; + /** @var callable $checkerCallback */ + $checkerCallback = [$checker, $checkMethod]; + $checkerCallback($class, $key, $checkMessage); + + switch ($which) { + case StaticCallbacks::CALLER: + /** @var callable $method */ + $method = [$class, $key]; + + return $value ? $method(...$value) : $method(); + case StaticCallbacks::GETTER: + return static::${$key}; + case StaticCallbacks::SETTER: + static::${$key} = $value; + break; + case StaticCallbacks::ISSER: + return isset(static::${$key}); + } }; - return Closure::bind($caller, $this->object, $this->class); + $this->callbacks[$which] = Closure::bind($caller, $this->object, $this->class); + + return $this->callbacks[$which]; } } diff --git a/src/Checker/Checker.php b/src/Checker/Checker.php index d6e6362..53e8564 100644 --- a/src/Checker/Checker.php +++ b/src/Checker/Checker.php @@ -25,19 +25,25 @@ */ final class Checker { + const PROPERTY = 'property'; + const STATIC_PROPERTY = 'static_property'; + const METHOD = 'method'; + const STATIC_METHOD = 'static_method'; + /** * @var array */ - private $checked = [ - 'var' => [], - 'staticvar' => [], - 'func' => [], - 'staticfunc' => [], + private static $checked = [ + self::PROPERTY => [], + self::STATIC_PROPERTY => [], + self::METHOD => [], + self::STATIC_METHOD => [], ]; /** - * @param object $object + * @param mixed $object * @param string $message + * @throws \Andrew\Exception\ArgumentException */ public function assertObject($object, $message) { @@ -49,6 +55,7 @@ public function assertObject($object, $message) /** * @param string $string * @param string $message + * @throws \Andrew\Exception\ArgumentException */ public function assertString($string, $message) { @@ -60,6 +67,8 @@ public function assertString($string, $message) /** * @param string $class * @param string $message + * @throws \Andrew\Exception\ArgumentException + * @throws \Andrew\Exception\ClassException */ public function assertClass($class, $message) { @@ -70,100 +79,146 @@ public function assertClass($class, $message) } /** - * @param object $object + * @param mixed $object * @param string $method * @param string $message + * @throws \Andrew\Exception\ArgumentException + * @throws \Andrew\Exception\MethodException */ public function assertMethod($object, $method, $message) { $this->assertString($method, $message); $this->assertObject($object, $message); $class = get_class($object); - // check same method for same class once is enough - isset($this->checked['func'][$class]) or $this->checked['func'][$class] = []; - if (! isset($this->checked['func'][$class][$method])) { - try { - $reflection = new ReflectionMethod($class, $method); - } catch (ReflectionException $exception) { - throw new MethodException($message); - } - if ($reflection->isStatic()) { - throw new MethodException($message); - } - $this->checked['func'][$class][$method] = true; + + // To check a method on same class is safely done once per request + if (isset(self::$checked[self::METHOD][$class][$method])) { + // @codeCoverageIgnoreStart + return; + // @codeCoverageIgnoreEnd + } + + try { + $reflection = new ReflectionMethod($class, $method); + } catch (ReflectionException $exception) { + throw new MethodException($message." ({$exception->getMessage()})"); } + if ($reflection->isStatic()) { + throw new MethodException($message); + } + + if (! isset(self::$checked[self::METHOD][$class])) { + self::$checked[self::METHOD][$class] = []; + } + + self::$checked[self::METHOD][$class][$method] = true; } /** * @param string $class * @param string $method * @param string $message + * @throws \Andrew\Exception\ArgumentException + * @throws \Andrew\Exception\ClassException + * @throws \Andrew\Exception\MethodException */ public function assertStaticMethod($class, $method, $message) { $this->assertString($method, $message); $this->assertClass($class, $message); - // check same method for same class once is enough - isset($this->checked['staticfunc'][$class]) or $this->checked['staticfunc'][$class] = []; - if (! isset($this->checked['staticfunc'][$class][$method])) { - try { - $reflection = new ReflectionMethod($class, $method); - } catch (ReflectionException $exception) { - throw new MethodException($message); - } - if (! $reflection->isStatic()) { - throw new MethodException($message); - } - $this->checked['staticfunc'][$class][$method] = true; + + // To check a static method on same class is safely done once per request + if (isset(self::$checked[self::STATIC_METHOD][$class][$method])) { + // @codeCoverageIgnoreStart + return; + // @codeCoverageIgnoreEnd + } + + try { + $reflection = new ReflectionMethod($class, $method); + } catch (ReflectionException $exception) { + throw new MethodException($message); + } + if (! $reflection->isStatic()) { + throw new MethodException($message); } + + if (! isset(self::$checked[self::STATIC_METHOD][$class])) { + self::$checked[self::STATIC_METHOD][$class] = []; + } + + self::$checked[self::STATIC_METHOD][$class][$method] = true; } /** - * @param object $object + * @param mixed $object * @param string $name * @param string $message + * @throws \Andrew\Exception\ArgumentException + * @throws \Andrew\Exception\PropertyException */ public function assertProperty($object, $name, $message) { $this->assertString($name, $message); $this->assertObject($object, $message); $class = get_class($object); - // check same property for same class once is enough - isset($this->checked['var'][$class]) or $this->checked['var'][$class] = []; - if (! isset($this->checked[$class]['var'][$name])) { - try { - $reflection = new ReflectionProperty($class, $name); - } catch (ReflectionException $exception) { - throw new PropertyException($message); - } - if ($reflection->isStatic()) { - throw new PropertyException($message); - } - $this->checked[$class]['var'][$name] = true; + + // To check a property on same class is safely done once per request + if (isset(self::$checked[self::PROPERTY][$class][$name])) { + // @codeCoverageIgnoreStart + return; + // @codeCoverageIgnoreEnd + } + + try { + $reflection = new ReflectionProperty($class, $name); + } catch (ReflectionException $exception) { + throw new PropertyException($message); + } + if ($reflection->isStatic()) { + throw new PropertyException($message); } + + if (! isset(self::$checked[self::PROPERTY][$class])) { + self::$checked[self::PROPERTY][$class] = []; + } + + self::$checked[self::PROPERTY][$class][$name] = true; } /** * @param string $class * @param string $name * @param string $message + * @throws \Andrew\Exception\ArgumentException + * @throws \Andrew\Exception\ClassException + * @throws \Andrew\Exception\PropertyException */ public function assertStaticProperty($class, $name, $message) { $this->assertString($name, $message); $this->assertClass($class, $message); - // check same property for same class once is enough - isset($this->checked['staticvar'][$class]) or $this->checked['staticvar'][$class] = []; - if (! isset($this->checked[$class]['staticvar'][$name])) { - try { - $reflection = new ReflectionProperty($class, $name); - } catch (ReflectionException $exception) { - throw new PropertyException($message); - } - if (! $reflection->isStatic()) { - throw new PropertyException($message); - } - $this->checked[$class]['staticvar'][$name] = true; + + // To check a static property on same class is safely done once per request + if (isset(self::$checked[self::STATIC_PROPERTY][$class][$name])) { + // @codeCoverageIgnoreStart + return; + // @codeCoverageIgnoreEnd + } + + try { + $reflection = new ReflectionProperty($class, $name); + } catch (ReflectionException $exception) { + throw new PropertyException($message); + } + if (! $reflection->isStatic()) { + throw new PropertyException($message); } + + if (! isset(self::$checked[self::STATIC_PROPERTY][$class])) { + self::$checked[self::STATIC_PROPERTY][$class] = []; + } + + self::$checked[self::STATIC_PROPERTY][$class][$name] = true; } } diff --git a/src/Proxy.php b/src/Proxy.php index a1edb76..907fb91 100644 --- a/src/Proxy.php +++ b/src/Proxy.php @@ -20,18 +20,21 @@ */ final class Proxy extends \stdClass { + /** * @var array */ private $callbacks; /** - * @param object $object + * @param mixed $object * @param \Andrew\Callbacks\CallbacksInterface|null $callbacks + * @throws \Andrew\Exception\ArgumentException + * @throws \Andrew\Exception\ClassException */ public function __construct($object, CallbacksInterface $callbacks = null) { - $this->callbacks = $callbacks ?: new DynamicCallbacks($object); + $this->callbacks = $callbacks ? : new DynamicCallbacks($object); } /** @@ -40,17 +43,20 @@ public function __construct($object, CallbacksInterface $callbacks = null) */ public function __get($name) { - return call_user_func($this->callbacks->getter(), $name); + $getter = $this->callbacks->getter(); + + return $getter($name); } /** - * @param string $name - * @param $value + * @param string $name + * @param mixed $value * @return void */ public function __set($name, $value) { - call_user_func($this->callbacks->setter(), $name, $value); + $setter = $this->callbacks->setter(); + $setter($name, $value); } /** @@ -59,7 +65,9 @@ public function __set($name, $value) */ public function __isset($name) { - return call_user_func($this->callbacks->isser(), $name); + $isser = $this->callbacks->isser(); + + return $isser($name); } /** @@ -68,7 +76,8 @@ public function __isset($name) */ public function __unset($name) { - call_user_func($this->callbacks->unsetter(), $name); + $unsetter = $this->callbacks->unsetter(); + $unsetter($name); } /** @@ -78,7 +87,9 @@ public function __unset($name) */ public function __call($name, array $arguments = []) { - return call_user_func($this->callbacks->caller(), $name, $arguments); + $caller = $this->callbacks->caller(); + + return $caller($name, $arguments); } /** @@ -86,6 +97,9 @@ public function __call($name, array $arguments = []) */ public function __invoke() { - return $this->__call('__invoke', func_get_args()); + $args = func_get_args(); + $caller = $this->callbacks->caller(); + + return $caller('__invoke', $args); } } diff --git a/src/StaticProxy.php b/src/StaticProxy.php index 715cb98..7d85b90 100644 --- a/src/StaticProxy.php +++ b/src/StaticProxy.php @@ -29,6 +29,8 @@ final class StaticProxy extends \stdClass /** * @param string $class * @param \Andrew\Callbacks\CallbacksInterface $callbacks + * @throws \Andrew\Exception\ArgumentException + * @throws \Andrew\Exception\ClassException */ public function __construct($class, CallbacksInterface $callbacks = null) { @@ -41,7 +43,9 @@ public function __construct($class, CallbacksInterface $callbacks = null) */ public function __get($name) { - return call_user_func($this->callbacks->getter(), $name); + $getter = $this->callbacks->getter(); + + return $getter($name); } /** @@ -51,7 +55,8 @@ public function __get($name) */ public function __set($name, $value) { - call_user_func($this->callbacks->setter(), $name, $value); + $setter = $this->callbacks->setter(); + $setter($name, $value); } /** @@ -60,12 +65,15 @@ public function __set($name, $value) */ public function __isset($name) { - return call_user_func($this->callbacks->isser(), $name); + $isser = $this->callbacks->isser(); + + return $isser($name); } /** * @param string $name * @return void + * @throws \Andrew\Exception\RuntimeException */ public function __unset($name) { @@ -79,6 +87,8 @@ public function __unset($name) */ public function __call($name, array $arguments = []) { - return call_user_func($this->callbacks->caller(), $name, $arguments); + $caller = $this->callbacks->caller(); + + return $caller($name, $arguments); } } diff --git a/tests/boot.php b/tests/boot.php index 68a2787..3fc3cb7 100644 --- a/tests/boot.php +++ b/tests/boot.php @@ -8,7 +8,7 @@ * file that was distributed with this source code. */ -$vendor = dirname(dirname(__FILE__)).'/vendor/'; +$vendor = dirname(__DIR__).'/vendor/'; if (! realpath($vendor)) { die('Please install via Composer before running tests.'); diff --git a/tests/src/Functional/DynamicProxyTest.php b/tests/src/Functional/DynamicProxyTest.php index 336515b..09aaebd 100644 --- a/tests/src/Functional/DynamicProxyTest.php +++ b/tests/src/Functional/DynamicProxyTest.php @@ -68,6 +68,7 @@ public function testGetterFailsIfBadArgument() { $stub = new Stub(); $proxy = new Proxy($stub); + /** @noinspection ImplicitMagicMethodCallInspection */ $proxy->__get(true); } @@ -125,6 +126,7 @@ public function testSetterFailsIfBadArgument() { $stub = new Stub(); $proxy = new Proxy($stub); + /** @noinspection ImplicitMagicMethodCallInspection */ $proxy->__set([], ''); } @@ -182,6 +184,7 @@ public function testIsserFailsIfBadArgument() { $stub = new Stub(); $proxy = new Proxy($stub); + /** @noinspection ImplicitMagicMethodCallInspection */ $proxy->__isset(1); } @@ -206,8 +209,10 @@ public function testUnsetterPublic() $stub = new Stub(); $proxy = new Proxy($stub); + /** @noinspection UnSafeIsSetOverArrayInspection */ assertTrue(isset($stub->public_var)); unset($proxy->public_var); + /** @noinspection UnSafeIsSetOverArrayInspection */ assertFalse(isset($stub->public_var)); } @@ -241,6 +246,7 @@ public function testUnsetterFailsIfBadArgument() { $stub = new Stub(); $proxy = new Proxy($stub); + /** @noinspection ImplicitMagicMethodCallInspection */ $proxy->__unset(true); } @@ -252,6 +258,7 @@ public function testCaller() $stub = new Stub(); $proxy = new Proxy($stub); + /** @noinspection PhpUndefinedMethodInspection */ assertSame('Private Dynamic Method', $proxy->privateDynamicMethod()); } @@ -263,6 +270,7 @@ public function testCallerPublic() $stub = new Stub(); $proxy = new Proxy($stub); + /** @noinspection PhpUndefinedMethodInspection */ assertSame('Public Dynamic Method', $proxy->publicDynamicMethod()); } @@ -274,6 +282,7 @@ public function testCallerFailsIfBadMethod() { $stub = new Stub(); $proxy = new Proxy($stub); + /** @noinspection PhpUndefinedMethodInspection */ $proxy->meh(); } @@ -285,6 +294,7 @@ public function testCallerFailsIfStaticMethod() { $stub = new Stub(); $proxy = new Proxy($stub); + /** @noinspection PhpUndefinedMethodInspection */ $proxy->publicStaticMethod(); } @@ -296,6 +306,7 @@ public function testCallerFailsIfBadArgument() { $stub = new Stub(); $proxy = new Proxy($stub); + /** @noinspection ImplicitMagicMethodCallInspection */ $proxy->__call([], []); } diff --git a/tests/src/Functional/StaticProxyTest.php b/tests/src/Functional/StaticProxyTest.php index b69f6fc..deb7e16 100644 --- a/tests/src/Functional/StaticProxyTest.php +++ b/tests/src/Functional/StaticProxyTest.php @@ -24,7 +24,7 @@ class StaticProxyTest extends PHPUnit_Framework_TestCase */ public function testGetter() { - $proxy = new StaticProxy('Andrew\Tests\Stub'); + $proxy = new StaticProxy(Stub::class); assertSame('Private Static Var', $proxy->private_static_var); } @@ -34,7 +34,7 @@ public function testGetter() */ public function testGetterPublic() { - $proxy = new StaticProxy('Andrew\Tests\Stub'); + $proxy = new StaticProxy(Stub::class); assertSame('Public Static Var', $proxy->public_static_var); } @@ -45,7 +45,7 @@ public function testGetterPublic() */ public function testGetterFailsIfBadProperty() { - $proxy = new StaticProxy('Andrew\Tests\Stub'); + $proxy = new StaticProxy(Stub::class); $proxy->meh; } @@ -55,7 +55,7 @@ public function testGetterFailsIfBadProperty() */ public function testGetterFailsIfDynamicProperty() { - $proxy = new StaticProxy('Andrew\Tests\Stub'); + $proxy = new StaticProxy(Stub::class); $proxy->public_var; } @@ -65,7 +65,8 @@ public function testGetterFailsIfDynamicProperty() */ public function testGetterFailsIfBadArgument() { - $proxy = new StaticProxy('Andrew\Tests\Stub'); + $proxy = new StaticProxy(Stub::class); + /** @noinspection ImplicitMagicMethodCallInspection */ $proxy->__get(0); } @@ -74,7 +75,7 @@ public function testGetterFailsIfBadArgument() */ public function testSetter() { - $proxy = new StaticProxy('Andrew\Tests\Stub'); + $proxy = new StaticProxy(Stub::class); assertSame('Private Static Var', Stub::staticGet()); $proxy->private_static_var = 'Edited Private Static Var'; @@ -86,7 +87,7 @@ public function testSetter() */ public function testSetterPublic() { - $proxy = new StaticProxy('Andrew\Tests\Stub'); + $proxy = new StaticProxy(Stub::class); assertSame('Public Static Var', Stub::$public_static_var); $proxy->public_static_var = 'Edited Public Static Var'; assertSame('Edited Public Static Var', Stub::$public_static_var); @@ -98,7 +99,7 @@ public function testSetterPublic() */ public function testSetterFailsIfBadVar() { - $proxy = new StaticProxy('Andrew\Tests\Stub'); + $proxy = new StaticProxy(Stub::class); $proxy->meh = 'Meh'; } @@ -108,7 +109,7 @@ public function testSetterFailsIfBadVar() */ public function testSetterFailsIfDynamicVar() { - $proxy = new StaticProxy('Andrew\Tests\Stub'); + $proxy = new StaticProxy(Stub::class); $proxy->public_var = 'Meh'; } @@ -118,7 +119,8 @@ public function testSetterFailsIfDynamicVar() */ public function testSetterFailsIfBadArgument() { - $proxy = new StaticProxy('Andrew\Tests\Stub'); + $proxy = new StaticProxy(Stub::class); + /** @noinspection ImplicitMagicMethodCallInspection */ $proxy->__set(1, []); } @@ -127,7 +129,7 @@ public function testSetterFailsIfBadArgument() */ public function testIsser() { - $proxy = new StaticProxy('Andrew\Tests\Stub'); + $proxy = new StaticProxy(Stub::class); assertTrue(isset($proxy->private_static_var)); } @@ -137,7 +139,7 @@ public function testIsser() */ public function testIsserPublic() { - $proxy = new StaticProxy('Andrew\Tests\Stub'); + $proxy = new StaticProxy(Stub::class); assertTrue(isset($proxy->public_static_var)); } @@ -148,7 +150,7 @@ public function testIsserPublic() */ public function testIsserFailsIfBadVar() { - $proxy = new StaticProxy('Andrew\Tests\Stub'); + $proxy = new StaticProxy(Stub::class); $meh = isset($proxy->meh); } @@ -158,8 +160,9 @@ public function testIsserFailsIfBadVar() */ public function testIsserFailsIfDynamicVar() { - $proxy = new StaticProxy('Andrew\Tests\Stub'); - $meh = isset($proxy->public_var); + $proxy = new StaticProxy(Stub::class); + /** @noinspection PhpExpressionResultUnusedInspection */ + isset($proxy->public_var); } /** @@ -168,7 +171,8 @@ public function testIsserFailsIfDynamicVar() */ public function testIsserFailsIfBadArgument() { - $proxy = new StaticProxy('Andrew\Tests\Stub'); + $proxy = new StaticProxy(Stub::class); + /** @noinspection ImplicitMagicMethodCallInspection */ $proxy->__isset(true); } @@ -178,7 +182,7 @@ public function testIsserFailsIfBadArgument() */ public function testUnsetterFails() { - $proxy = new StaticProxy('Andrew\Tests\Stub'); + $proxy = new StaticProxy(Stub::class); unset($proxy->private_static_var); } @@ -188,7 +192,7 @@ public function testUnsetterFails() */ public function testUnsetterFailsPublic() { - $proxy = new StaticProxy('Andrew\Tests\Stub'); + $proxy = new StaticProxy(Stub::class); unset($proxy->public_static_var); } @@ -197,8 +201,9 @@ public function testUnsetterFailsPublic() */ public function testCaller() { - $proxy = new StaticProxy('Andrew\Tests\Stub'); + $proxy = new StaticProxy(Stub::class); + /** @noinspection PhpUndefinedMethodInspection */ assertSame('Private Static Method', $proxy->privateStaticMethod()); } @@ -207,8 +212,9 @@ public function testCaller() */ public function testCallerPublic() { - $proxy = new StaticProxy('Andrew\Tests\Stub'); + $proxy = new StaticProxy(Stub::class); + /** @noinspection PhpUndefinedMethodInspection */ assertSame('Public Static Method', $proxy->publicStaticMethod()); } @@ -218,7 +224,8 @@ public function testCallerPublic() */ public function testCallerFailsIfBadMethod() { - $proxy = new StaticProxy('Andrew\Tests\Stub'); + $proxy = new StaticProxy(Stub::class); + /** @noinspection PhpUndefinedMethodInspection */ $proxy->meh(); } @@ -228,7 +235,8 @@ public function testCallerFailsIfBadMethod() */ public function testCallerFailsIfDynamicMethod() { - $proxy = new StaticProxy('Andrew\Tests\Stub'); + $proxy = new StaticProxy(Stub::class); + /** @noinspection PhpUndefinedMethodInspection */ $proxy->publicDynamicMethod(); } @@ -238,7 +246,8 @@ public function testCallerFailsIfDynamicMethod() */ public function testCallerFailsIfBadArgument() { - $proxy = new StaticProxy('Andrew\Tests\Stub'); + $proxy = new StaticProxy(Stub::class); + /** @noinspection ImplicitMagicMethodCallInspection */ $proxy->__call([], []); } } diff --git a/tests/src/Stub.php b/tests/src/Stub.php index 0f266d3..ae3a7a3 100644 --- a/tests/src/Stub.php +++ b/tests/src/Stub.php @@ -67,6 +67,7 @@ public static function staticGet() */ public static function staticCheck() { + /** @noinspection UnSafeIsSetOverArrayInspection */ return isset(self::$private_static_var); } @@ -108,6 +109,7 @@ public function get() */ public function check() { + /** @noinspection UnSafeIsSetOverArrayInspection */ return isset($this->private_var); } } diff --git a/tests/src/Unit/CheckerTest.php b/tests/src/Unit/CheckerTest.php index aa63edc..688eb3e 100644 --- a/tests/src/Unit/CheckerTest.php +++ b/tests/src/Unit/CheckerTest.php @@ -30,6 +30,7 @@ private static function stubMethod() public function testAssertObject() { $checker = new Checker(); + /** @noinspection PhpVoidFunctionResultUsedInspection */ assertNull($checker->assertObject($this, '')); } @@ -46,6 +47,7 @@ public function testAssertObjectException() public function testAssertString() { $checker = new Checker(); + /** @noinspection PhpVoidFunctionResultUsedInspection */ assertNull($checker->assertString('ok', '')); } @@ -62,6 +64,7 @@ public function testAssertStringException() public function testAssertClass() { $checker = new Checker(); + /** @noinspection PhpVoidFunctionResultUsedInspection */ assertNull($checker->assertClass(__CLASS__, '')); } @@ -88,6 +91,7 @@ public function testAssertClassExceptionIfNoClass() public function testAssertMethod() { $checker = new Checker(); + /** @noinspection PhpVoidFunctionResultUsedInspection */ assertNull($checker->assertMethod($this, __FUNCTION__, '')); } @@ -134,6 +138,7 @@ public function testAssertMethodExceptionIfStaticMethod() public function testAssertStaticMethod() { $checker = new Checker(); + /** @noinspection PhpVoidFunctionResultUsedInspection */ assertNull($checker->assertStaticMethod(__CLASS__, 'stubMethod', '')); } @@ -180,6 +185,7 @@ public function testAssertMethodExceptionIfDynamicMethod() public function testAssertProperty() { $checker = new Checker(); + /** @noinspection PhpVoidFunctionResultUsedInspection */ assertNull($checker->assertProperty($this, 'var', '')); } @@ -226,6 +232,7 @@ public function testAssertPropertyExceptionIfStaticProperty() public function testAssertStaticProperty() { $checker = new Checker(); + /** @noinspection PhpVoidFunctionResultUsedInspection */ assertNull($checker->assertStaticProperty(__CLASS__, 'staticvar', '')); } diff --git a/tests/src/Unit/DynamicCallbacksTest.php b/tests/src/Unit/DynamicCallbacksTest.php index 3ecd7a4..b2bf4fd 100644 --- a/tests/src/Unit/DynamicCallbacksTest.php +++ b/tests/src/Unit/DynamicCallbacksTest.php @@ -29,6 +29,14 @@ public function testConstructorFailsIfNoObject() new DynamicCallbacks(__CLASS__); } + /** + * @expectedException \Andrew\Exception\ClassException + */ + public function testConstructorFailsIfStdClass() + { + new DynamicCallbacks(new \stdClass()); + } + public function testGetter() { $callbacks = new DynamicCallbacks(new Stub()); diff --git a/tests/src/Unit/ProxyTest.php b/tests/src/Unit/ProxyTest.php index 0a462fa..b539a3e 100644 --- a/tests/src/Unit/ProxyTest.php +++ b/tests/src/Unit/ProxyTest.php @@ -12,6 +12,7 @@ use Andrew\Proxy; use PHPUnit_Framework_TestCase; +use Andrew\Callbacks\CallbacksInterface; /** * @author Giuseppe Mazzapica @@ -20,14 +21,15 @@ */ class ProxyTest extends PHPUnit_Framework_TestCase { + /** - * @param $method - * @param callable $callback - * @return \Andrew\Callbacks\CallbacksInterface + * @param string $method + * @param callable $callback + * @return \Andrew\Callbacks\CallbacksInterface|\PHPUnit_Framework_MockObject_MockObject */ private function getMockedCallbacks($method, callable $callback) { - $callbacks = $this->getMockBuilder('Andrew\Callbacks\CallbacksInterface')->getMock(); + $callbacks = $this->getMockBuilder(CallbacksInterface::class)->getMock(); $callbacks ->expects($this->once()) ->method($method) @@ -45,6 +47,7 @@ public function testGet() $callbacks = $this->getMockedCallbacks('getter', $function); $proxy = new Proxy($this, $callbacks); + /** @noinspection ImplicitMagicMethodCallInspection */ $proxy->__get('foo'); } @@ -58,6 +61,7 @@ public function testSet() $callbacks = $this->getMockedCallbacks('setter', $function); $proxy = new Proxy($this, $callbacks); + /** @noinspection ImplicitMagicMethodCallInspection */ $proxy->__set('foo', 'bar'); } @@ -70,6 +74,7 @@ public function testIsset() $callbacks = $this->getMockedCallbacks('isser', $function); $proxy = new Proxy($this, $callbacks); + /** @noinspection ImplicitMagicMethodCallInspection */ $proxy->__isset('foo'); } @@ -82,6 +87,7 @@ public function testUnset() $callbacks = $this->getMockedCallbacks('unsetter', $function); $proxy = new Proxy($this, $callbacks); + /** @noinspection ImplicitMagicMethodCallInspection */ $proxy->__unset('foo'); } @@ -95,6 +101,7 @@ public function testCall() $callbacks = $this->getMockedCallbacks('caller', $function); $proxy = new Proxy($this, $callbacks); + /** @noinspection ImplicitMagicMethodCallInspection */ $proxy->__call('foo', ['foo', 'bar']); } diff --git a/tests/src/Unit/StaticCallbacksTest.php b/tests/src/Unit/StaticCallbacksTest.php index d4c30ca..d8eb145 100644 --- a/tests/src/Unit/StaticCallbacksTest.php +++ b/tests/src/Unit/StaticCallbacksTest.php @@ -29,9 +29,17 @@ public function testConstructorFailsIfNoClass() new StaticCallbacks('meh'); } + /** + * @expectedException \Andrew\Exception\ClassException + */ + public function testConstructorFailsIfStdClass() + { + new StaticCallbacks(\stdClass::class); + } + public function testGetter() { - $callbacks = new StaticCallbacks('Andrew\Tests\Stub'); + $callbacks = new StaticCallbacks(Stub::class); $getter = $callbacks->getter(); assertInternalType('callable', $getter); assertSame('Private Static Var', $getter('private_static_var')); @@ -39,7 +47,7 @@ public function testGetter() public function testSetter() { - $callbacks = new StaticCallbacks('Andrew\Tests\Stub'); + $callbacks = new StaticCallbacks(Stub::class); $setter = $callbacks->setter(); assertInternalType('callable', $setter); assertSame('Private Static Var', Stub::staticGet()); @@ -49,7 +57,7 @@ public function testSetter() public function testIsser() { - $callbacks = new StaticCallbacks('Andrew\Tests\Stub'); + $callbacks = new StaticCallbacks(Stub::class); $isser = $callbacks->isser(); assertInternalType('callable', $isser); assertTrue($isser('private_static_var')); @@ -60,13 +68,13 @@ public function testIsser() */ public function testUnsetter() { - $callbacks = new StaticCallbacks('Andrew\Tests\Stub'); + $callbacks = new StaticCallbacks(Stub::class); $callbacks->unsetter(); } public function testCaller() { - $callbacks = new StaticCallbacks('Andrew\Tests\Stub'); + $callbacks = new StaticCallbacks(Stub::class); $caller = $callbacks->caller(); assertInternalType('callable', $caller); assertSame('Private Static Method Test!', $caller('privateStaticMethod', [' Test!'])); diff --git a/tests/src/Unit/StaticProxyTest.php b/tests/src/Unit/StaticProxyTest.php index b5a361a..9db5299 100644 --- a/tests/src/Unit/StaticProxyTest.php +++ b/tests/src/Unit/StaticProxyTest.php @@ -12,6 +12,7 @@ use Andrew\StaticProxy; use PHPUnit_Framework_TestCase; +use Andrew\Callbacks\CallbacksInterface; /** * @author Giuseppe Mazzapica @@ -20,14 +21,15 @@ */ class StaticProxyTest extends PHPUnit_Framework_TestCase { + /** - * @param $method - * @param callable $callback - * @return \Andrew\Callbacks\CallbacksInterface + * @param string $method + * @param callable $callback + * @return \Andrew\Callbacks\CallbacksInterface|\PHPUnit_Framework_MockObject_MockObject */ private function getMockedCallbacks($method, callable $callback) { - $callbacks = $this->getMockBuilder('Andrew\Callbacks\CallbacksInterface')->getMock(); + $callbacks = $this->getMockBuilder(CallbacksInterface::class)->getMock(); $callbacks ->expects($this->once()) ->method($method) @@ -45,6 +47,7 @@ public function testGet() $callbacks = $this->getMockedCallbacks('getter', $function); $proxy = new StaticProxy(__CLASS__, $callbacks); + /** @noinspection ImplicitMagicMethodCallInspection */ $proxy->__get('foo'); } @@ -58,6 +61,7 @@ public function testSet() $callbacks = $this->getMockedCallbacks('setter', $function); $proxy = new StaticProxy(__CLASS__, $callbacks); + /** @noinspection ImplicitMagicMethodCallInspection */ $proxy->__set('foo', 'bar'); } @@ -70,6 +74,7 @@ public function testIsset() $callbacks = $this->getMockedCallbacks('isser', $function); $proxy = new StaticProxy(__CLASS__, $callbacks); + /** @noinspection ImplicitMagicMethodCallInspection */ $proxy->__isset('foo'); } @@ -79,8 +84,9 @@ public function testIsset() public function testUnset() { /** @var \Andrew\Callbacks\CallbacksInterface $callbacks */ - $callbacks = $this->getMockBuilder('Andrew\Callbacks\CallbacksInterface')->getMock(); + $callbacks = $this->getMockBuilder(CallbacksInterface::class)->getMock(); $proxy = new StaticProxy(__CLASS__, $callbacks); + /** @noinspection ImplicitMagicMethodCallInspection */ $proxy->__unset('foo'); } @@ -94,6 +100,7 @@ public function testCall() $callbacks = $this->getMockedCallbacks('caller', $function); $proxy = new StaticProxy(__CLASS__, $callbacks); + /** @noinspection ImplicitMagicMethodCallInspection */ $proxy->__call('foo', ['foo', 'bar']); } }