From 74071061ebc0fe6263700258506ae780d779939a Mon Sep 17 00:00:00 2001 From: David Grudl Date: Thu, 3 Dec 2020 17:07:28 +0100 Subject: [PATCH 01/11] Strings::replace: default replacement is empty string [Closes #241] --- src/Utils/Strings.php | 4 ++-- tests/Utils/Strings.replace().phpt | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Utils/Strings.php b/src/Utils/Strings.php index 0b37d64e2..317f72d32 100644 --- a/src/Utils/Strings.php +++ b/src/Utils/Strings.php @@ -509,7 +509,7 @@ public static function matchAll(string $subject, string $pattern, int $flags = 0 * @param string|array $pattern * @param string|callable $replacement */ - public static function replace(string $subject, $pattern, $replacement = null, int $limit = -1): string + public static function replace(string $subject, $pattern, $replacement = '', int $limit = -1): string { if (is_object($replacement) || is_array($replacement)) { if (!is_callable($replacement, false, $textual)) { @@ -517,7 +517,7 @@ public static function replace(string $subject, $pattern, $replacement = null, i } return self::pcre('preg_replace_callback', [$pattern, $replacement, $subject, $limit]); - } elseif ($replacement === null && is_array($pattern)) { + } elseif (is_array($pattern) && is_string(key($pattern))) { $replacement = array_values($pattern); $pattern = array_keys($pattern); } diff --git a/tests/Utils/Strings.replace().phpt b/tests/Utils/Strings.replace().phpt index 999d12ba9..c1b94b504 100644 --- a/tests/Utils/Strings.replace().phpt +++ b/tests/Utils/Strings.replace().phpt @@ -32,3 +32,5 @@ Assert::same('#@ @@@#d!', Strings::replace('hello world!', [ '#([e-l])+#' => '#', '#[o-w]#' => '@', ])); +Assert::same(' !', Strings::replace('hello world!', '#\w#')); +Assert::same(' !', Strings::replace('hello world!', ['#\w#'])); From 02bb1f89e3e41a429b0cd6cf90f381697a1c9291 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Jac=C3=ADk?= Date: 2021年1月10日 16:03:15 +0100 Subject: [PATCH 02/11] typo (#247) --- src/Utils/Arrays.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Utils/Arrays.php b/src/Utils/Arrays.php index c4e956c74..21d407580 100644 --- a/src/Utils/Arrays.php +++ b/src/Utils/Arrays.php @@ -92,7 +92,7 @@ public static function searchKey(array $array, $key): ?int /** * Inserts the contents of the $inserted array into the $array immediately after the $key. - * If $key is null (or does not exist), it is inserted at the end. + * If $key is null (or does not exist), it is inserted at the beginning. * @param string|int|null $key */ public static function insertBefore(array &$array, $key, array $inserted): void @@ -106,7 +106,7 @@ public static function insertBefore(array &$array, $key, array $inserted): void /** * Inserts the contents of the $inserted array into the $array before the $key. - * If $key is null (or does not exist), it is inserted at the beginning. + * If $key is null (or does not exist), it is inserted at the end. * @param string|int|null $key */ public static function insertAfter(array &$array, $key, array $inserted): void From 2520402eedef9f396b8e76855fd028fd50ecf3c2 Mon Sep 17 00:00:00 2001 From: David Grudl Date: 2021年1月25日 00:56:59 +0100 Subject: [PATCH 03/11] updated workflows --- .github/workflows/tests.yml | 6 ++++-- tests/.coveralls.yml | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 6901532cd..70b855906 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -42,6 +42,8 @@ jobs: coverage: none - run: composer install --no-progress --prefer-dist - - run: wget https://github.com/satooshi/php-coveralls/releases/download/v1.0.1/coveralls.phar - run: vendor/bin/tester -p phpdbg tests -s -C --coverage ./coverage.xml --coverage-src ./src - - run: php coveralls.phar --verbose --config tests/.coveralls.yml + - run: wget https://github.com/php-coveralls/php-coveralls/releases/download/v2.4.3/php-coveralls.phar + - env: + COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: php php-coveralls.phar --verbose --config tests/.coveralls.yml diff --git a/tests/.coveralls.yml b/tests/.coveralls.yml index 82764a3f5..845038250 100644 --- a/tests/.coveralls.yml +++ b/tests/.coveralls.yml @@ -1,4 +1,4 @@ # for php-coveralls -service_name: travis-ci +service_name: github-actions coverage_clover: coverage.xml json_path: coverage.json From 3753a290d9be87e60305573a6fc6a658ef589375 Mon Sep 17 00:00:00 2001 From: David Grudl Date: 2021年1月25日 21:39:24 +0100 Subject: [PATCH 04/11] readme: removed badges --- readme.md | 7 ------- 1 file changed, 7 deletions(-) diff --git a/readme.md b/readme.md index 880a83f08..6713dc356 100644 --- a/readme.md +++ b/readme.md @@ -1,13 +1,6 @@ Nette Utility Classes ===================== -[![Downloads this Month](https://img.shields.io/packagist/dm/nette/utils.svg)](https://packagist.org/packages/nette/utils) -[![Build Status](https://travis-ci.org/nette/utils.svg?branch=master)](https://travis-ci.org/nette/utils) -[![Coverage Status](https://coveralls.io/repos/github/nette/utils/badge.svg?branch=master)](https://coveralls.io/github/nette/utils?branch=master) -[![Latest Stable Version](https://poser.pugx.org/nette/utils/v/stable)](https://github.com/nette/utils/releases) -[![License](https://img.shields.io/badge/license-New%20BSD-blue.svg)](https://github.com/nette/utils/blob/master/license.md) - - Introduction ------------ From 61dfd184a284affa0c7fed44708a171c5c4bb1fc Mon Sep 17 00:00:00 2001 From: David Grudl Date: 2021年9月13日 12:48:53 +0200 Subject: [PATCH 05/11] updated ecs.php --- ecs.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ecs.php b/ecs.php index 2e6fcf398..601ed753d 100644 --- a/ecs.php +++ b/ecs.php @@ -14,6 +14,8 @@ $parameters = $containerConfigurator->parameters(); $parameters->set('skip', [ + 'fixtures*/*', + // RemoteStream extends streamWrapper PHP_CodeSniffer\Standards\PSR1\Sniffs\Methods\CamelCapsMethodNameSniff::class => [ 'tests/Utils/FileSystem.phpt', @@ -34,5 +36,10 @@ 'src/Utils/Html.php', 'src/Utils/Strings.php', ], + + // bug in SlevomatCodingStandard + 'SlevomatCodingStandard\Sniffs\Operators\RequireCombinedAssignmentOperatorSniff.RequiredCombinedAssigmentOperator' => [ + 'src/Utils/Html.php', + ], ]); }; From 6dc5f604a7cee49daaf0276c31565d30581e3503 Mon Sep 17 00:00:00 2001 From: David Grudl Date: 2021年9月12日 19:55:13 +0200 Subject: [PATCH 06/11] tests: refactoring --- .../Utils/Reflection.getParameterType.80.phpt | 2 +- .../Utils/Reflection.getPropertyType.74.phpt | 46 ++++++ tests/Utils/Reflection.getPropertyType.phpt | 25 +-- tests/Utils/Reflection.getReturnType.80.phpt | 153 +++++++++--------- tests/Utils/Reflection.getReturnType.phpt | 101 ++++++------ 5 files changed, 170 insertions(+), 157 deletions(-) create mode 100644 tests/Utils/Reflection.getPropertyType.74.phpt diff --git a/tests/Utils/Reflection.getParameterType.80.phpt b/tests/Utils/Reflection.getParameterType.80.phpt index 37e3e1418..7651ddda3 100644 --- a/tests/Utils/Reflection.getParameterType.80.phpt +++ b/tests/Utils/Reflection.getParameterType.80.phpt @@ -27,7 +27,7 @@ class A ?B $nullable, mixed $mixed, array|self $union, - array|self|null $nullableUnion + array|self|null $nullableUnion, ) { } } diff --git a/tests/Utils/Reflection.getPropertyType.74.phpt b/tests/Utils/Reflection.getPropertyType.74.phpt new file mode 100644 index 000000000..b822be995 --- /dev/null +++ b/tests/Utils/Reflection.getPropertyType.74.phpt @@ -0,0 +1,46 @@ +getProperties(); + +Assert::same('Undeclared', Reflection::getPropertyType($props[0])); +Assert::same('Test\B', Reflection::getPropertyType($props[1])); +Assert::same('array', Reflection::getPropertyType($props[2])); +Assert::same('A', Reflection::getPropertyType($props[3])); +Assert::null(Reflection::getPropertyType($props[4])); +Assert::same('Test\B', Reflection::getPropertyType($props[5])); + +$class = new ReflectionClass('AExt'); +$props = $class->getProperties(); + +Assert::same('A', Reflection::getPropertyType($props[0])); diff --git a/tests/Utils/Reflection.getPropertyType.phpt b/tests/Utils/Reflection.getPropertyType.phpt index b822be995..8b15eb85e 100644 --- a/tests/Utils/Reflection.getPropertyType.phpt +++ b/tests/Utils/Reflection.getPropertyType.phpt @@ -2,13 +2,11 @@ /** * Test: Nette\Utils\Reflection::getPropertyType - * @phpversion 7.4 */ declare(strict_types=1); use Nette\Utils\Reflection; -use Test\B; // for testing purposes use Tester\Assert; @@ -17,30 +15,11 @@ require __DIR__ . '/../bootstrap.php'; class A { - public Undeclared $undeclared; - public B $b; - public array $array; - public self $self; public $none; - public ?B $nullable; -} - -class AExt extends A -{ - public parent $parent; } $class = new ReflectionClass('A'); $props = $class->getProperties(); -Assert::same('Undeclared', Reflection::getPropertyType($props[0])); -Assert::same('Test\B', Reflection::getPropertyType($props[1])); -Assert::same('array', Reflection::getPropertyType($props[2])); -Assert::same('A', Reflection::getPropertyType($props[3])); -Assert::null(Reflection::getPropertyType($props[4])); -Assert::same('Test\B', Reflection::getPropertyType($props[5])); - -$class = new ReflectionClass('AExt'); -$props = $class->getProperties(); - -Assert::same('A', Reflection::getPropertyType($props[0])); +Assert::null(Reflection::getPropertyType($props[0])); +Assert::same([], Reflection::getPropertyTypes($props[0])); diff --git a/tests/Utils/Reflection.getReturnType.80.phpt b/tests/Utils/Reflection.getReturnType.80.phpt index 637a78433..240bb6e78 100644 --- a/tests/Utils/Reflection.getReturnType.80.phpt +++ b/tests/Utils/Reflection.getReturnType.80.phpt @@ -7,137 +7,132 @@ declare(strict_types=1); -namespace NS -{ - use Test\B; - - class A - { - public function noType() - { - } - - - public function classType(): B - { - } +use Nette\Utils\Reflection; +use Test\B; +use Tester\Assert; // for testing purposes +require __DIR__ . '/../bootstrap.php'; - public function nativeType(): String - { - } - - public function selfType(): self - { - } - - - public function staticType(): static - { - } +class A +{ + public function noType() + { + } - public function nullableClassType(): ?B - { - } + public function classType(): B + { + } - public function nullableNativeType(): ?string - { - } + public function nativeType(): String + { + } - public function nullableSelfType(): ?self - { - } + public function selfType(): self + { + } - public function unionType(): array|self - { - } + public function staticType(): static + { + } - public function nullableUnionType(): array|self|null - { - } + public function nullableClassType(): ?B + { } - class AExt extends A + + public function nullableNativeType(): ?string { - public function parentTypeExt(): parent - { - } } - function noType() + public function nullableSelfType(): ?self { } - function classType(): B + public function unionType(): array|self { } - function nativeType(): String + public function nullableUnionType(): array|self|null { } +} - - function unionType(): array|A +class AExt extends A +{ + public function parentTypeExt(): parent { } } -namespace + +function noType() { - use Nette\Utils\Reflection; - use Tester\Assert; +} - require __DIR__ . '/../bootstrap.php'; +function classType(): B +{ +} - Assert::null(Reflection::getReturnType(new \ReflectionMethod(NS\A::class, 'noType'))); - Assert::same('Test\B', Reflection::getReturnType(new \ReflectionMethod(NS\A::class, 'classType'))); +function nativeType(): String +{ +} - Assert::same('string', Reflection::getReturnType(new \ReflectionMethod(NS\A::class, 'nativeType'))); - Assert::same('NS\A', Reflection::getReturnType(new \ReflectionMethod(NS\A::class, 'selfType'))); +function unionType(): array|A +{ +} - Assert::same('NS\A', Reflection::getReturnType(new \ReflectionMethod(NS\A::class, 'staticType'))); - Assert::same('Test\B', Reflection::getReturnType(new \ReflectionMethod(NS\A::class, 'nullableClassType'))); - Assert::same('string', Reflection::getReturnType(new \ReflectionMethod(NS\A::class, 'nullableNativeType'))); +Assert::null(Reflection::getReturnType(new \ReflectionMethod(A::class, 'noType'))); - Assert::same('NS\A', Reflection::getReturnType(new \ReflectionMethod(NS\A::class, 'nullableSelfType'))); +Assert::same('Test\B', Reflection::getReturnType(new \ReflectionMethod(A::class, 'classType'))); - Assert::same(['NS\A', 'array'], Reflection::getReturnTypes(new \ReflectionMethod(NS\A::class, 'unionType'))); +Assert::same('string', Reflection::getReturnType(new \ReflectionMethod(A::class, 'nativeType'))); - Assert::same(['NS\A', 'array', 'null'], Reflection::getReturnTypes(new \ReflectionMethod(NS\A::class, 'nullableUnionType'))); +Assert::same('A', Reflection::getReturnType(new \ReflectionMethod(A::class, 'selfType'))); - Assert::exception(function () { - Reflection::getReturnType(new \ReflectionMethod(NS\A::class, 'unionType')); - }, Nette\InvalidStateException::class, 'The NS\A::unionType is not expected to have a union type.'); +Assert::same('A', Reflection::getReturnType(new \ReflectionMethod(A::class, 'staticType'))); - Assert::exception(function () { - Reflection::getReturnType(new \ReflectionMethod(NS\A::class, 'nullableUnionType')); - }, Nette\InvalidStateException::class, 'The NS\A::nullableUnionType is not expected to have a union type.'); +Assert::same('Test\B', Reflection::getReturnType(new \ReflectionMethod(A::class, 'nullableClassType'))); - Assert::same('NS\A', Reflection::getReturnType(new \ReflectionMethod(NS\AExt::class, 'parentTypeExt'))); +Assert::same('string', Reflection::getReturnType(new \ReflectionMethod(A::class, 'nullableNativeType'))); - Assert::null(Reflection::getReturnType(new \ReflectionFunction('NS\noType'))); +Assert::same('A', Reflection::getReturnType(new \ReflectionMethod(A::class, 'nullableSelfType'))); - Assert::same('Test\B', Reflection::getReturnType(new \ReflectionFunction('NS\classType'))); +Assert::same(['A', 'array'], Reflection::getReturnTypes(new \ReflectionMethod(A::class, 'unionType'))); - Assert::same('string', Reflection::getReturnType(new \ReflectionFunction('NS\nativeType'))); +Assert::same(['A', 'array', 'null'], Reflection::getReturnTypes(new \ReflectionMethod(A::class, 'nullableUnionType'))); - Assert::same(['NS\A', 'array'], Reflection::getReturnTypes(new \ReflectionFunction('NS\unionType'))); +Assert::exception(function () { + Reflection::getReturnType(new \ReflectionMethod(A::class, 'unionType')); +}, Nette\InvalidStateException::class, 'The A::unionType is not expected to have a union type.'); - Assert::exception(function () { - Reflection::getReturnType(new \ReflectionFunction('NS\unionType')); - }, Nette\InvalidStateException::class, 'The NS\unionType is not expected to have a union type.'); -} +Assert::exception(function () { + Reflection::getReturnType(new \ReflectionMethod(A::class, 'nullableUnionType')); +}, Nette\InvalidStateException::class, 'The A::nullableUnionType is not expected to have a union type.'); + +Assert::same('A', Reflection::getReturnType(new \ReflectionMethod(AExt::class, 'parentTypeExt'))); + +Assert::null(Reflection::getReturnType(new \ReflectionFunction('noType'))); + +Assert::same('Test\B', Reflection::getReturnType(new \ReflectionFunction('classType'))); + +Assert::same('string', Reflection::getReturnType(new \ReflectionFunction('nativeType'))); + +Assert::same(['A', 'array'], Reflection::getReturnTypes(new \ReflectionFunction('unionType'))); + +Assert::exception(function () { + Reflection::getReturnType(new \ReflectionFunction('unionType')); +}, Nette\InvalidStateException::class, 'The unionType is not expected to have a union type.'); diff --git a/tests/Utils/Reflection.getReturnType.phpt b/tests/Utils/Reflection.getReturnType.phpt index 90052c92e..eb29bb4ee 100644 --- a/tests/Utils/Reflection.getReturnType.phpt +++ b/tests/Utils/Reflection.getReturnType.phpt @@ -6,98 +6,91 @@ declare(strict_types=1); -namespace NS -{ - use Test\B; - - class A - { - public function noType() - { - } - +use Nette\Utils\Reflection; +use Test\B; +use Tester\Assert; // for testing purposes - public function classType(): B - { - } +require __DIR__ . '/../bootstrap.php'; - public function nativeType(): String - { - } - - - public function selfType(): self - { - } +class A +{ + public function noType() + { + } - public function nullableClassType(): ?B - { - } + public function classType(): B + { + } - public function nullableNativeType(): ?string - { - } + public function nativeType(): String + { + } - public function nullableSelfType(): ?self - { - } + public function selfType(): self + { } - class AExt extends A + + public function nullableClassType(): ?B { - public function parentTypeExt(): parent - { - } } - function noType() + public function nullableNativeType(): ?string { } - function classType(): B + public function nullableSelfType(): ?self { } +} - - function nativeType(): String +class AExt extends A +{ + public function parentTypeExt(): parent { } } -namespace + +function noType() { - use Nette\Utils\Reflection; - use Tester\Assert; +} - require __DIR__ . '/../bootstrap.php'; +function classType(): B +{ +} + + +function nativeType(): String +{ +} - Assert::null(Reflection::getReturnType(new \ReflectionMethod(NS\A::class, 'noType'))); - Assert::same('Test\B', Reflection::getReturnType(new \ReflectionMethod(NS\A::class, 'classType'))); +Assert::null(Reflection::getReturnType(new \ReflectionMethod(A::class, 'noType'))); - Assert::same('string', Reflection::getReturnType(new \ReflectionMethod(NS\A::class, 'nativeType'))); +Assert::same('Test\B', Reflection::getReturnType(new \ReflectionMethod(A::class, 'classType'))); - Assert::same('NS\A', Reflection::getReturnType(new \ReflectionMethod(NS\A::class, 'selfType'))); +Assert::same('string', Reflection::getReturnType(new \ReflectionMethod(A::class, 'nativeType'))); - Assert::same('Test\B', Reflection::getReturnType(new \ReflectionMethod(NS\A::class, 'nullableClassType'))); +Assert::same('A', Reflection::getReturnType(new \ReflectionMethod(A::class, 'selfType'))); - Assert::same('string', Reflection::getReturnType(new \ReflectionMethod(NS\A::class, 'nullableNativeType'))); +Assert::same('Test\B', Reflection::getReturnType(new \ReflectionMethod(A::class, 'nullableClassType'))); - Assert::same('NS\A', Reflection::getReturnType(new \ReflectionMethod(NS\A::class, 'nullableSelfType'))); +Assert::same('string', Reflection::getReturnType(new \ReflectionMethod(A::class, 'nullableNativeType'))); - Assert::same('NS\A', Reflection::getReturnType(new \ReflectionMethod(NS\AExt::class, 'parentTypeExt'))); +Assert::same('A', Reflection::getReturnType(new \ReflectionMethod(A::class, 'nullableSelfType'))); - Assert::null(Reflection::getReturnType(new \ReflectionFunction('NS\noType'))); +Assert::same('A', Reflection::getReturnType(new \ReflectionMethod(AExt::class, 'parentTypeExt'))); - Assert::same('Test\B', Reflection::getReturnType(new \ReflectionFunction('NS\classType'))); +Assert::null(Reflection::getReturnType(new \ReflectionFunction('noType'))); - Assert::same('string', Reflection::getReturnType(new \ReflectionFunction('NS\nativeType'))); +Assert::same('Test\B', Reflection::getReturnType(new \ReflectionFunction('classType'))); -} +Assert::same('string', Reflection::getReturnType(new \ReflectionFunction('nativeType'))); From 3e15c26b694bec676fe678da558d51e1adfdcb8e Mon Sep 17 00:00:00 2001 From: David Grudl Date: 2021年9月12日 20:18:59 +0200 Subject: [PATCH 07/11] improved phpDoc, used generics --- src/Utils/ArrayHash.php | 7 ++++-- src/Utils/ArrayList.php | 8 ++++--- src/Utils/Arrays.php | 47 ++++++++++++++++++++++++++--------------- src/Utils/Html.php | 5 +++-- 4 files changed, 43 insertions(+), 24 deletions(-) diff --git a/src/Utils/ArrayHash.php b/src/Utils/ArrayHash.php index b2aeb4cbc..495d99054 100644 --- a/src/Utils/ArrayHash.php +++ b/src/Utils/ArrayHash.php @@ -14,11 +14,13 @@ /** * Provides objects to work as array. + * @template T */ class ArrayHash extends \stdClass implements \ArrayAccess, \Countable, \IteratorAggregate { /** * Transforms array to ArrayHash. + * @param array $array * @return static */ public static function from(array $array, bool $recursive = true) @@ -35,6 +37,7 @@ public static function from(array $array, bool $recursive = true) /** * Returns an iterator over all items. + * @return \RecursiveArrayIterator */ public function getIterator(): \RecursiveArrayIterator { @@ -54,7 +57,7 @@ public function count(): int /** * Replaces or appends a item. * @param string|int $key - * @param mixed $value + * @param T $value */ public function offsetSet($key, $value): void { @@ -68,7 +71,7 @@ public function offsetSet($key, $value): void /** * Returns a item. * @param string|int $key - * @return mixed + * @return T */ public function offsetGet($key) { diff --git a/src/Utils/ArrayList.php b/src/Utils/ArrayList.php index dd009036e..166d1a836 100644 --- a/src/Utils/ArrayList.php +++ b/src/Utils/ArrayList.php @@ -14,6 +14,7 @@ /** * Provides the base class for a generic list (items can be accessed by index). + * @template T */ class ArrayList implements \ArrayAccess, \Countable, \IteratorAggregate { @@ -25,6 +26,7 @@ class ArrayList implements \ArrayAccess, \Countable, \IteratorAggregate /** * Returns an iterator over all items. + * @return \ArrayIterator */ public function getIterator(): \ArrayIterator { @@ -44,7 +46,7 @@ public function count(): int /** * Replaces or appends a item. * @param int|null $index - * @param mixed $value + * @param T $value * @throws Nette\OutOfRangeException */ public function offsetSet($index, $value): void @@ -64,7 +66,7 @@ public function offsetSet($index, $value): void /** * Returns a item. * @param int $index - * @return mixed + * @return T * @throws Nette\OutOfRangeException */ public function offsetGet($index) @@ -102,7 +104,7 @@ public function offsetUnset($index): void /** * Prepends a item. - * @param mixed $value + * @param T $value */ public function prepend($value): void { diff --git a/src/Utils/Arrays.php b/src/Utils/Arrays.php index 21d407580..440f80f1a 100644 --- a/src/Utils/Arrays.php +++ b/src/Utils/Arrays.php @@ -22,9 +22,11 @@ class Arrays /** * Returns item from array. If it does not exist, it throws an exception, unless a default value is set. - * @param string|int|array $key one or more keys - * @param mixed $default - * @return mixed + * @template T + * @param array $array + * @param array-key|array-key[] $key + * @param ?T $default + * @return ?T * @throws Nette\InvalidArgumentException if item does not exist and default value is not provided */ public static function get(array $array, $key, $default = null) @@ -45,8 +47,10 @@ public static function get(array $array, $key, $default = null) /** * Returns reference to array item. If the index does not exist, new one is created with value null. - * @param string|int|array $key one or more keys - * @return mixed + * @template T + * @param array $array + * @param array-key|array-key[] $key + * @return ?T * @throws Nette\InvalidArgumentException if traversed item is not an array */ public static function &getRef(array &$array, $key) @@ -66,6 +70,11 @@ public static function &getRef(array &$array, $key) * Recursively merges two fields. It is useful, for example, for merging tree structures. It behaves as * the + operator for array, ie. it adds a key/value pair from the second array to the first one and retains * the value from the first array in the case of a key collision. + * @template T1 + * @template T2 + * @param array $array1 + * @param array $array2 + * @return array */ public static function mergeTree(array $array1, array $array2): array { @@ -81,7 +90,7 @@ public static function mergeTree(array $array1, array $array2): array /** * Returns zero-indexed position of given array key. Returns null if key is not found. - * @param string|int $key + * @param array-key $key * @return int|null offset if it is found, null otherwise */ public static function searchKey(array $array, $key): ?int @@ -93,7 +102,7 @@ public static function searchKey(array $array, $key): ?int /** * Inserts the contents of the $inserted array into the $array immediately after the $key. * If $key is null (or does not exist), it is inserted at the beginning. - * @param string|int|null $key + * @param array-key|null $key */ public static function insertBefore(array &$array, $key, array $inserted): void { @@ -107,7 +116,7 @@ public static function insertBefore(array &$array, $key, array $inserted): void /** * Inserts the contents of the $inserted array into the $array before the $key. * If $key is null (or does not exist), it is inserted at the end. - * @param string|int|null $key + * @param array-key|null $key */ public static function insertAfter(array &$array, $key, array $inserted): void { @@ -121,8 +130,8 @@ public static function insertAfter(array &$array, $key, array $inserted): void /** * Renames key in array. - * @param string|int $oldKey - * @param string|int $newKey + * @param array-key $oldKey + * @param array-key $newKey */ public static function renameKey(array &$array, $oldKey, $newKey): bool { @@ -141,7 +150,8 @@ public static function renameKey(array &$array, $oldKey, $newKey): bool /** * Returns only those array items, which matches a regular expression $pattern. - * @throws Nette\RegexpException on compilation or runtime error + * @param string[] $array + * @return string[] */ public static function grep(array $array, string $pattern, int $flags = 0): array { @@ -246,9 +256,11 @@ public static function normalize(array $array, $filling = null): array /** * Returns and removes the value of an item from an array. If it does not exist, it throws an exception, * or returns $default, if provided. - * @param string|int $key - * @param mixed $default - * @return mixed + * @template T + * @param array $array + * @param array-key $key + * @param ?T $default + * @return ?T * @throws Nette\InvalidArgumentException if item does not exist and default value is not provided */ public static function pick(array &$array, $key, $default = null) @@ -313,8 +325,9 @@ public static function map(array $array, callable $callback): array /** * Copies the elements of the $array array to the $object object and then returns it. - * @param object $object - * @return object + * @template T of object + * @param T $object + * @return T */ public static function toObject(array $array, $object) { @@ -328,7 +341,7 @@ public static function toObject(array $array, $object) /** * Converts value to array key. * @param mixed $value - * @return int|string + * @return array-key */ public static function toKey($value) { diff --git a/src/Utils/Html.php b/src/Utils/Html.php index b92e73977..7a2279a7c 100644 --- a/src/Utils/Html.php +++ b/src/Utils/Html.php @@ -247,7 +247,7 @@ class Html implements \ArrayAccess, \Countable, \IteratorAggregate, IHtmlString 'isindex' => 1, 'wbr' => 1, 'command' => 1, 'track' => 1, ]; - /** @var array nodes */ + /** @var array nodes */ protected $children = []; /** @var string element's name */ @@ -661,7 +661,7 @@ final public function offsetSet($index, $child): void /** * Returns child node (\ArrayAccess implementation). * @param int $index - * @return static|string + * @return HtmlStringable|string */ final public function offsetGet($index) { @@ -711,6 +711,7 @@ public function removeChildren(): void /** * Iterates over elements. + * @return \ArrayIterator */ final public function getIterator(): \ArrayIterator { From 09890e63771b4c0d4e2106814fd49b3bc6bbc187 Mon Sep 17 00:00:00 2001 From: David Grudl Date: 2021年9月13日 01:57:12 +0200 Subject: [PATCH 08/11] Reflection: getReturnTypes(), getParameterTypes(), getPropertyTypes() are deprecated --- src/Utils/Reflection.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Utils/Reflection.php b/src/Utils/Reflection.php index c0e607982..b6fbaef2c 100644 --- a/src/Utils/Reflection.php +++ b/src/Utils/Reflection.php @@ -46,7 +46,7 @@ public static function getReturnType(\ReflectionFunctionAbstract $func): ?string /** - * Returns the types of return value of given function or method and normalizes `self`, `static`, and `parent` to actual class names. + * @deprecated */ public static function getReturnTypes(\ReflectionFunctionAbstract $func): array { @@ -66,7 +66,7 @@ public static function getParameterType(\ReflectionParameter $param): ?string /** - * Returns the types of given parameter and normalizes `self` and `parent` to the actual class names. + * @deprecated */ public static function getParameterTypes(\ReflectionParameter $param): array { @@ -86,7 +86,7 @@ public static function getPropertyType(\ReflectionProperty $prop): ?string /** - * Returns the types of given property and normalizes `self` and `parent` to the actual class names. + * @deprecated */ public static function getPropertyTypes(\ReflectionProperty $prop): array { From aa66d71a796d6a49feaf7ee9e57767e45f6d6536 Mon Sep 17 00:00:00 2001 From: David Grudl Date: 2021年9月13日 01:58:54 +0200 Subject: [PATCH 09/11] added Type --- readme.md | 1 + src/Utils/Reflection.php | 49 ++------ src/Utils/Type.php | 107 ++++++++++++++++++ .../Type.fromReflection.function.80.phpt | 42 +++++++ tests/Utils/Type.fromReflection.function.phpt | 26 +++++ tests/Utils/Type.fromReflection.method.phpt | 39 +++++++ .../Utils/Type.fromReflection.parameter.phpt | 26 +++++ .../Type.fromReflection.property.74.phpt | 36 ++++++ tests/Utils/Type.fromReflection.property.phpt | 14 +++ 9 files changed, 301 insertions(+), 39 deletions(-) create mode 100644 src/Utils/Type.php create mode 100644 tests/Utils/Type.fromReflection.function.80.phpt create mode 100644 tests/Utils/Type.fromReflection.function.phpt create mode 100644 tests/Utils/Type.fromReflection.method.phpt create mode 100644 tests/Utils/Type.fromReflection.parameter.phpt create mode 100644 tests/Utils/Type.fromReflection.property.74.phpt create mode 100644 tests/Utils/Type.fromReflection.property.phpt diff --git a/readme.md b/readme.md index 6713dc356..69c6bb70a 100644 --- a/readme.md +++ b/readme.md @@ -20,6 +20,7 @@ In package nette/utils you will find a set of [useful classes](https://doc.nette - [Strings](https://doc.nette.org/strings) - useful text functions - [SmartObject](https://doc.nette.org/smartobject) - PHP object enhancements - [Validation](https://doc.nette.org/validators) - validate inputs +- [Type](https://doc.nette.org/type) - PHP data type Installation diff --git a/src/Utils/Reflection.php b/src/Utils/Reflection.php index b6fbaef2c..5eb0fbd39 100644 --- a/src/Utils/Reflection.php +++ b/src/Utils/Reflection.php @@ -50,7 +50,8 @@ public static function getReturnType(\ReflectionFunctionAbstract $func): ?string */ public static function getReturnTypes(\ReflectionFunctionAbstract $func): array { - return self::getType($func, $func->getReturnType(), true); + $type = Type::fromReflection($func); + return $type ? $type->getNames() : []; } @@ -70,7 +71,8 @@ public static function getParameterType(\ReflectionParameter $param): ?string */ public static function getParameterTypes(\ReflectionParameter $param): array { - return self::getType($param, $param->getType(), true); + $type = Type::fromReflection($param); + return $type ? $type->getNames() : []; } @@ -90,36 +92,23 @@ public static function getPropertyType(\ReflectionProperty $prop): ?string */ public static function getPropertyTypes(\ReflectionProperty $prop): array { - return self::getType($prop, PHP_VERSION_ID>= 70400 ? $prop->getType() : null, true); + $type = Type::fromReflection($prop); + return $type ? $type->getNames() : []; } /** * @param \ReflectionFunction|\ReflectionMethod|\ReflectionParameter|\ReflectionProperty $reflection - * @return string|array|null */ - private static function getType($reflection, ?\ReflectionType $type, bool $asArray = false) + private static function getType($reflection, ?\ReflectionType $type): ?string { if ($type === null) { - return $asArray ? [] : null; + return null; } elseif ($type instanceof \ReflectionNamedType) { - $name = self::normalizeType($type->getName(), $reflection); - if ($asArray) { - return $type->allowsNull() && $type->getName() !== 'mixed' - ? [$name, 'null'] - : [$name]; - } - return $name; + return Type::resolve($type->getName(), $reflection); } elseif ($type instanceof \ReflectionUnionType) { - if ($asArray) { - $types = []; - foreach ($type->getTypes() as $type) { - $types[] = self::normalizeType($type->getName(), $reflection); - } - return $types; - } throw new Nette\InvalidStateException('The ' . self::toString($reflection) . ' is not expected to have a union type.'); } else { @@ -128,24 +117,6 @@ private static function getType($reflection, ?\ReflectionType $type, bool $asArr } - /** - * @param \ReflectionFunction|\ReflectionMethod|\ReflectionParameter|\ReflectionProperty $reflection - */ - private static function normalizeType(string $type, $reflection): string - { - $lower = strtolower($type); - if ($reflection instanceof \ReflectionFunction) { - return $type; - } elseif ($lower === 'self' || $lower === 'static') { - return $reflection->getDeclaringClass()->name; - } elseif ($lower === 'parent' && $reflection->getDeclaringClass()->getParentClass()) { - return $reflection->getDeclaringClass()->getParentClass()->name; - } else { - return $type; - } - } - - /** * Returns the default value of parameter. If it is a constant, it returns its value. * @return mixed @@ -157,7 +128,7 @@ public static function getParameterDefaultValue(\ReflectionParameter $param) $const = $orig = $param->getDefaultValueConstantName(); $pair = explode('::', $const); if (isset($pair[1])) { - $pair[0] = self::normalizeType($pair[0], $param); + $pair[0] = Type::resolve($pair[0], $param); try { $rcc = new \ReflectionClassConstant($pair[0], $pair[1]); } catch (\ReflectionException $e) { diff --git a/src/Utils/Type.php b/src/Utils/Type.php new file mode 100644 index 000000000..2c481d622 --- /dev/null +++ b/src/Utils/Type.php @@ -0,0 +1,107 @@ +getReturnType() + : $reflection->getType(); + + if ($type === null) { + return null; + + } elseif ($type instanceof \ReflectionNamedType) { + $name = self::resolve($type->getName(), $reflection); + return new self($type->allowsNull() && $type->getName() !== 'mixed' ? [$name, 'null'] : [$name]); + + } elseif ($type instanceof \ReflectionUnionType) { + return new self( + array_map( + function ($t) use ($reflection) { return self::resolve($t->getName(), $reflection); }, + $type->getTypes() + ) + ); + + } else { + throw new Nette\InvalidStateException('Unexpected type of ' . Reflection::toString($reflection)); + } + } + + + /** + * Resolves 'self', 'static' and 'parent' to the actual class name. + * @param \ReflectionFunctionAbstract|\ReflectionParameter|\ReflectionProperty $reflection + */ + public static function resolve(string $type, $reflection): string + { + $lower = strtolower($type); + if ($reflection instanceof \ReflectionFunction) { + return $type; + } elseif ($lower === 'self' || $lower === 'static') { + return $reflection->getDeclaringClass()->name; + } elseif ($lower === 'parent' && $reflection->getDeclaringClass()->getParentClass()) { + return $reflection->getDeclaringClass()->getParentClass()->name; + } else { + return $type; + } + } + + + private function __construct(array $types) + { + if ($types[0] === 'null') { // null as last + array_push($types, array_shift($types)); + } + $this->types = $types; + $this->single = ($types[1] ?? 'null') === 'null'; + } + + + public function __toString(): string + { + return $this->single + ? (count($this->types)> 1 ? '?' : '') . $this->types[0] + : implode('|', $this->types); + } + + + /** + * Returns the array of subtypes that make up the compound type as strings. + * @return string[] + */ + public function getNames(): array + { + return $this->types; + } +} diff --git a/tests/Utils/Type.fromReflection.function.80.phpt b/tests/Utils/Type.fromReflection.function.80.phpt new file mode 100644 index 000000000..7a4d35dfd --- /dev/null +++ b/tests/Utils/Type.fromReflection.function.80.phpt @@ -0,0 +1,42 @@ +getNames()); +Assert::same('string', (string) $type); + + +$type = Type::fromReflection(new ReflectionFunction(function (): ?string {})); + +Assert::same(['string', 'null'], $type->getNames()); +Assert::same('?string', (string) $type); + + +$type = Type::fromReflection(new ReflectionFunction(function (): Foo {})); + +Assert::same(['Foo'], $type->getNames()); +Assert::same('Foo', (string) $type); + + +$type = Type::fromReflection(new ReflectionFunction(function (): Foo|string {})); + +Assert::same(['Foo', 'string'], $type->getNames()); +Assert::same('Foo|string', (string) $type); + + +$type = Type::fromReflection(new ReflectionFunction(function (): mixed {})); + +Assert::same(['mixed'], $type->getNames()); +Assert::same('mixed', (string) $type); diff --git a/tests/Utils/Type.fromReflection.function.phpt b/tests/Utils/Type.fromReflection.function.phpt new file mode 100644 index 000000000..b179fab54 --- /dev/null +++ b/tests/Utils/Type.fromReflection.function.phpt @@ -0,0 +1,26 @@ +getNames()); +Assert::same('string', (string) $type); + + +$type = Type::fromReflection(new ReflectionFunction(function (): ?string {})); + +Assert::same(['string', 'null'], $type->getNames()); +Assert::same('?string', (string) $type); + + +$type = Type::fromReflection(new ReflectionFunction(function (): Foo {})); + +Assert::same(['Foo'], $type->getNames()); +Assert::same('Foo', (string) $type); diff --git a/tests/Utils/Type.fromReflection.method.phpt b/tests/Utils/Type.fromReflection.method.phpt new file mode 100644 index 000000000..4d665a2f6 --- /dev/null +++ b/tests/Utils/Type.fromReflection.method.phpt @@ -0,0 +1,39 @@ +getMethod('foo')); + +Assert::same(['string'], $type->getNames()); +Assert::same('string', (string) $type); + + +$type = Type::fromReflection((new ReflectionObject(new class { + public function foo(): ?string + { + } +}))->getMethod('foo')); + +Assert::same(['string', 'null'], $type->getNames()); +Assert::same('?string', (string) $type); + + +$class = new class { + public function foo(): self + { + } +}; +$type = Type::fromReflection((new ReflectionObject($class))->getMethod('foo')); + +Assert::same([get_class($class)], $type->getNames()); +Assert::same(get_class($class), (string) $type); diff --git a/tests/Utils/Type.fromReflection.parameter.phpt b/tests/Utils/Type.fromReflection.parameter.phpt new file mode 100644 index 000000000..ec35291b5 --- /dev/null +++ b/tests/Utils/Type.fromReflection.parameter.phpt @@ -0,0 +1,26 @@ +getParameters()[0]); + +Assert::same(['string'], $type->getNames()); +Assert::same('string', (string) $type); + + +$type = Type::fromReflection((new ReflectionFunction(function (?string $a) {}))->getParameters()[0]); + +Assert::same(['string', 'null'], $type->getNames()); +Assert::same('?string', (string) $type); + + +$type = Type::fromReflection((new ReflectionFunction(function (Foo $a) {}))->getParameters()[0]); + +Assert::same(['Foo'], $type->getNames()); +Assert::same('Foo', (string) $type); diff --git a/tests/Utils/Type.fromReflection.property.74.phpt b/tests/Utils/Type.fromReflection.property.74.phpt new file mode 100644 index 000000000..2563c4ef2 --- /dev/null +++ b/tests/Utils/Type.fromReflection.property.74.phpt @@ -0,0 +1,36 @@ +getProperty('foo')); + +Assert::same(['string'], $type->getNames()); +Assert::same('string', (string) $type); + + +$type = Type::fromReflection((new ReflectionObject(new class { + public ?string $foo; +}))->getProperty('foo')); + +Assert::same(['string', 'null'], $type->getNames()); +Assert::same('?string', (string) $type); + + +$type = Type::fromReflection((new ReflectionObject(new class { + public Foo $foo; +}))->getProperty('foo')); + +Assert::same(['Foo'], $type->getNames()); +Assert::same('Foo', (string) $type); diff --git a/tests/Utils/Type.fromReflection.property.phpt b/tests/Utils/Type.fromReflection.property.phpt new file mode 100644 index 000000000..d287d2238 --- /dev/null +++ b/tests/Utils/Type.fromReflection.property.phpt @@ -0,0 +1,14 @@ +getProperty('foo')); +Assert::null($type); From 35c366045fb91b0dbd1d7dd957a6688fba0c00ee Mon Sep 17 00:00:00 2001 From: David Grudl Date: 2021年9月19日 18:48:47 +0200 Subject: [PATCH 10/11] Type: added basic API --- src/Utils/Type.php | 73 +++++++++++++++++++++ tests/Utils/Type.fromString.phpt | 108 +++++++++++++++++++++++++++++++ 2 files changed, 181 insertions(+) create mode 100644 tests/Utils/Type.fromString.phpt diff --git a/src/Utils/Type.php b/src/Utils/Type.php index 2c481d622..2debc7117 100644 --- a/src/Utils/Type.php +++ b/src/Utils/Type.php @@ -59,6 +59,22 @@ function ($t) use ($reflection) { return self::resolve($t->getName(), $reflectio } + /** + * Creates the Type object according to the text notation. + */ + public static function fromString(string $type): self + { + if (!preg_match('#(?:\?([\w\\\\]+)|[\w\\\\]+(?:\|[\w\\\\]+)*)$#AD', $type, $m)) { + throw new Nette\InvalidArgumentException("Invalid type '$type'."); + } + if (isset($m[1])) { + return new self([$m[1], 'null']); + } else { + return new self(explode('|', $type)); + } + } + + /** * Resolves 'self', 'static' and 'parent' to the actual class name. * @param \ReflectionFunctionAbstract|\ReflectionParameter|\ReflectionProperty $reflection @@ -104,4 +120,61 @@ public function getNames(): array { return $this->types; } + + + /** + * Returns the array of subtypes that make up the compound type as Type objects: + * @return self[] + */ + public function getTypes(): array + { + return array_map(function ($name) { return self::fromString($name); }, $this->types); + } + + + /** + * Returns the type name for single types, otherwise null. + */ + public function getSingleName(): ?string + { + return $this->single + ? $this->types[0] + : null; + } + + + /** + * Returns true whether it is a union type. + */ + public function isUnion(): bool + { + return count($this->types)> 1; + } + + + /** + * Returns true whether it is a single type. Simple nullable types are also considered to be single types. + */ + public function isSingle(): bool + { + return $this->single; + } + + + /** + * Returns true whether the type is both a single and a PHP built-in type. + */ + public function isBuiltin(): bool + { + return $this->single && Reflection::isBuiltinType($this->types[0]); + } + + + /** + * Returns true whether the type is both a single and a class name. + */ + public function isClass(): bool + { + return $this->single && !Reflection::isBuiltinType($this->types[0]); + } } diff --git a/tests/Utils/Type.fromString.phpt b/tests/Utils/Type.fromString.phpt new file mode 100644 index 000000000..cbae02253 --- /dev/null +++ b/tests/Utils/Type.fromString.phpt @@ -0,0 +1,108 @@ +getNames()); +Assert::equal([Type::fromString('string')], $type->getTypes()); +Assert::same('string', (string) $type); +Assert::same('string', $type->getSingleName()); +Assert::false($type->isClass()); +Assert::false($type->isUnion()); +Assert::true($type->isSingle()); +Assert::true($type->isBuiltin()); + + +$type = Type::fromString('string|null'); + +Assert::same(['string', 'null'], $type->getNames()); +Assert::equal([Type::fromString('string'), Type::fromString('null')], $type->getTypes()); +Assert::same('?string', (string) $type); +Assert::same('string', $type->getSingleName()); +Assert::false($type->isClass()); +Assert::true($type->isUnion()); +Assert::true($type->isSingle()); +Assert::true($type->isBuiltin()); + + +$type = Type::fromString('null|string'); + +Assert::same(['string', 'null'], $type->getNames()); +Assert::equal([Type::fromString('string'), Type::fromString('null')], $type->getTypes()); +Assert::same('?string', (string) $type); +Assert::same('string', $type->getSingleName()); +Assert::false($type->isClass()); +Assert::true($type->isUnion()); +Assert::true($type->isSingle()); +Assert::true($type->isBuiltin()); + + +$type = Type::fromString('?string'); + +Assert::same(['string', 'null'], $type->getNames()); +Assert::equal([Type::fromString('string'), Type::fromString('null')], $type->getTypes()); +Assert::same('?string', (string) $type); +Assert::same('string', $type->getSingleName()); +Assert::false($type->isClass()); +Assert::true($type->isUnion()); +Assert::true($type->isSingle()); +Assert::true($type->isBuiltin()); + + +$type = Type::fromString('NS\Foo'); + +Assert::same(['NS\Foo'], $type->getNames()); +Assert::equal([Type::fromString('NS\Foo')], $type->getTypes()); +Assert::same('NS\Foo', (string) $type); +Assert::same('NS\Foo', $type->getSingleName()); +Assert::true($type->isClass()); +Assert::false($type->isUnion()); +Assert::true($type->isSingle()); +Assert::false($type->isBuiltin()); + + +$type = Type::fromString('string|Foo'); + +Assert::same(['string', 'Foo'], $type->getNames()); +Assert::equal([Type::fromString('string'), Type::fromString('Foo')], $type->getTypes()); +Assert::same('string|Foo', (string) $type); +Assert::null($type->getSingleName()); +Assert::false($type->isClass()); +Assert::true($type->isUnion()); +Assert::false($type->isSingle()); +Assert::false($type->isBuiltin()); + + +$type = Type::fromString('mixed'); + +Assert::same(['mixed'], $type->getNames()); +Assert::equal([Type::fromString('mixed')], $type->getTypes()); +Assert::same('mixed', (string) $type); +Assert::same('mixed', $type->getSingleName()); +Assert::false($type->isClass()); +Assert::false($type->isUnion()); +Assert::true($type->isSingle()); +Assert::true($type->isBuiltin()); + + +$type = Type::fromString('null'); // invalid type + +Assert::same(['null'], $type->getNames()); +Assert::equal([Type::fromString('null')], $type->getTypes()); +Assert::same('null', (string) $type); +Assert::same('null', $type->getSingleName()); +Assert::false($type->isClass()); +Assert::false($type->isUnion()); +Assert::true($type->isSingle()); +Assert::true($type->isBuiltin()); From 2c8d1628317fddc692d90fd7732e3dd98327dbf0 Mon Sep 17 00:00:00 2001 From: David Grudl Date: 2021年9月14日 10:48:55 +0200 Subject: [PATCH 11/11] Type: added allows() --- src/Utils/Type.php | 19 ++++++++++++ tests/Utils/Type.allows.phpt | 57 ++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 tests/Utils/Type.allows.phpt diff --git a/src/Utils/Type.php b/src/Utils/Type.php index 2debc7117..279f1bdc0 100644 --- a/src/Utils/Type.php +++ b/src/Utils/Type.php @@ -177,4 +177,23 @@ public function isClass(): bool { return $this->single && !Reflection::isBuiltinType($this->types[0]); } + + + /** + * Verifies type compatibility. For example, it checks if a value of a certain type could be passed as a parameter. + */ + public function allows(string $type): bool + { + if ($this->types === ['mixed']) { + return true; + } + return Arrays::every((self::fromString($type))->types, function ($testedType) { + $builtin = Reflection::isBuiltinType($testedType); + return Arrays::some($this->types, function ($currentType) use ($testedType, $builtin) { + return $builtin + ? strcasecmp($currentType, $testedType) === 0 + : is_a($testedType, $currentType, true); + }); + }); + } } diff --git a/tests/Utils/Type.allows.phpt b/tests/Utils/Type.allows.phpt new file mode 100644 index 000000000..e3fbf5a1a --- /dev/null +++ b/tests/Utils/Type.allows.phpt @@ -0,0 +1,57 @@ +allows('string')); +Assert::false($type->allows('null')); +Assert::false($type->allows('string|null')); +Assert::false($type->allows('Foo')); +Assert::false($type->allows('FooChild')); +Assert::false($type->allows('Foo|FooChild')); + + +$type = Type::fromString('string|null'); +Assert::true($type->allows('string')); +Assert::true($type->allows('null')); +Assert::true($type->allows('string|null')); +Assert::false($type->allows('Foo')); +Assert::false($type->allows('FooChild')); +Assert::false($type->allows('Foo|FooChild')); + + +$type = Type::fromString('string|Foo'); +Assert::true($type->allows('string')); +Assert::false($type->allows('null')); +Assert::false($type->allows('string|null')); +Assert::true($type->allows('Foo')); +Assert::true($type->allows('FooChild')); +Assert::true($type->allows('Foo|FooChild')); + + +$type = Type::fromString('mixed'); +Assert::true($type->allows('string')); +Assert::true($type->allows('null')); +Assert::true($type->allows('string|null')); +Assert::true($type->allows('Foo')); +Assert::true($type->allows('FooChild')); +Assert::true($type->allows('Foo|FooChild'));

AltStyle によって変換されたページ (->オリジナル) /