diff --git a/README.md b/README.md index 766099c..be445fe 100644 --- a/README.md +++ b/README.md @@ -207,9 +207,11 @@ Method | Description ### Function Assertions -Method | Description -------------------------------------------- | ----------------------------------------------------------------------------------------------------- -`throws($closure, $class, $message = '')` | Check that a function throws a certain exception. Subclasses of the exception class will be accepted. +Method | Description +------------------------------------------| ----------------------------------------------------------------------------------------------------- +`throws($closure, $class, $message = '')` | Check that a function throws a certain exception. Subclasses of the exception class will be accepted. +`isStatic($closure, $message = '')` | Check that a function is static. +`isNotStatic($closure, $message = '')` | Check that a function is not static. ### Collection Assertions diff --git a/src/Assert.php b/src/Assert.php index f02b8c9..6018317 100644 --- a/src/Assert.php +++ b/src/Assert.php @@ -18,6 +18,7 @@ use DateTime; use DateTimeImmutable; use Exception; +use ReflectionFunction; use ResourceBundle; use SimpleXMLElement; use Throwable; @@ -1940,6 +1941,41 @@ public static function isMap($array, $message = '') } } + /** + * @param Closure $closure + * @param string $message + * @return void + * @throws InvalidArgumentException + */ + public static function isStatic(Closure $closure, $message = '') + { + $reflection = new ReflectionFunction($closure); + + if (!$reflection->isStatic()) { + static::reportInvalidArgument( + $message ?: 'Closure is not static.' + ); + } + } + + /** + * @param Closure $closure + * @param string $message + * @return void + * @throws InvalidArgumentException + */ + public static function isNotStatic(Closure $closure, $message = '') + { + Assert::isCallable($closure); + $reflection = new ReflectionFunction($closure); + + if ($reflection->isStatic()) { + static::reportInvalidArgument( + $message ?: 'Closure is not static.' + ); + } + } + /** * @psalm-pure * diff --git a/src/Mixin.php b/src/Mixin.php index fad0d47..9f05eda 100644 --- a/src/Mixin.php +++ b/src/Mixin.php @@ -5035,6 +5035,106 @@ public static function allNullOrIsMap($array, $message = '') } } + /** + * @param Closure|null $closure + * @param string $message + * + * @return void + * @return void + * + * @throws InvalidArgumentException + */ + public static function nullOrIsStatic($closure, $message = '') + { + null === $closure || static::isStatic($closure, $message); + } + + /** + * @param iterable $closure + * @param string $message + * + * @return void + * @return void + * + * @throws InvalidArgumentException + */ + public static function allIsStatic($closure, $message = '') + { + static::isIterable($closure); + + foreach ($closure as $entry) { + static::isStatic($entry, $message); + } + } + + /** + * @param iterable $closure + * @param string $message + * + * @return void + * @return void + * + * @throws InvalidArgumentException + */ + public static function allNullOrIsStatic($closure, $message = '') + { + static::isIterable($closure); + + foreach ($closure as $entry) { + null === $entry || static::isStatic($entry, $message); + } + } + + /** + * @param Closure|null $closure + * @param string $message + * + * @return void + * @return void + * + * @throws InvalidArgumentException + */ + public static function nullOrIsNotStatic($closure, $message = '') + { + null === $closure || static::isNotStatic($closure, $message); + } + + /** + * @param iterable $closure + * @param string $message + * + * @return void + * @return void + * + * @throws InvalidArgumentException + */ + public static function allIsNotStatic($closure, $message = '') + { + static::isIterable($closure); + + foreach ($closure as $entry) { + static::isNotStatic($entry, $message); + } + } + + /** + * @param iterable $closure + * @param string $message + * + * @return void + * @return void + * + * @throws InvalidArgumentException + */ + public static function allNullOrIsNotStatic($closure, $message = '') + { + static::isIterable($closure); + + foreach ($closure as $entry) { + null === $entry || static::isNotStatic($entry, $message); + } + } + /** * @psalm-pure * diff --git a/tests/AssertTest.php b/tests/AssertTest.php index 87a1bb1..903c950 100644 --- a/tests/AssertTest.php +++ b/tests/AssertTest.php @@ -548,6 +548,10 @@ public function getTests() array('throws', array(function () { trigger_error('test'); }, 'Throwable'), true, false, 70000), array('throws', array(function () { trigger_error('test'); }, 'Unthrowable'), false, false, 70000), array('throws', array(function () { throw new Error(); }, 'Throwable'), true, true, 70000), + array('isStatic', array(static function () {}), true), + array('isStatic', array(function () {}), false), + array('isNotStatic', array(static function () {}), false), + array('isNotStatic', array(function () {}), true), array('ip', array('192.168.0.1'), true), array('ip', array(new ToStringClass('192.168.0.1')), true), array('ip', array('255.255.255.255'), true), diff --git a/tests/static-analysis/assert-isStatic.php b/tests/static-analysis/assert-isStatic.php new file mode 100644 index 0000000..2de93a5 --- /dev/null +++ b/tests/static-analysis/assert-isStatic.php @@ -0,0 +1,20 @@ +