dep: package update

This commit is contained in:
2021-11-08 16:10:01 +09:00
parent 38208750e7
commit 2c533d2ab3
783 changed files with 4581 additions and 20980 deletions
+1
View File
@@ -27,6 +27,7 @@ class Mapper extends \IteratorIterator
}
#[\ReturnTypeWillChange]
public function current()
{
return ($this->callback)(parent::current(), parent::key());
+1 -1
View File
@@ -24,4 +24,4 @@ interface Translator
}
interface_exists(Nette\Localization\ITranslator::class);
interface_exists(ITranslator::class);
+6 -2
View File
@@ -14,11 +14,13 @@ use Nette;
/**
* Provides objects to work as array.
* @template T
*/
class ArrayHash extends \stdClass implements \ArrayAccess, \Countable, \IteratorAggregate
{
/**
* Transforms array to ArrayHash.
* @param array<T> $array
* @return static
*/
public static function from(array $array, bool $recursive = true)
@@ -35,6 +37,7 @@ class ArrayHash extends \stdClass implements \ArrayAccess, \Countable, \Iterator
/**
* Returns an iterator over all items.
* @return \RecursiveArrayIterator<array-key, T>
*/
public function getIterator(): \RecursiveArrayIterator
{
@@ -54,7 +57,7 @@ class ArrayHash extends \stdClass implements \ArrayAccess, \Countable, \Iterator
/**
* Replaces or appends a item.
* @param string|int $key
* @param mixed $value
* @param T $value
*/
public function offsetSet($key, $value): void
{
@@ -68,8 +71,9 @@ class ArrayHash extends \stdClass implements \ArrayAccess, \Countable, \Iterator
/**
* Returns a item.
* @param string|int $key
* @return mixed
* @return T
*/
#[\ReturnTypeWillChange]
public function offsetGet($key)
{
return $this->$key;
+22 -3
View File
@@ -14,6 +14,7 @@ use Nette;
/**
* Provides the base class for a generic list (items can be accessed by index).
* @template T
*/
class ArrayList implements \ArrayAccess, \Countable, \IteratorAggregate
{
@@ -23,8 +24,25 @@ class ArrayList implements \ArrayAccess, \Countable, \IteratorAggregate
private $list = [];
/**
* Transforms array to ArrayList.
* @param array<T> $array
* @return static
*/
public static function from(array $array)
{
if (!Arrays::isList($array)) {
throw new Nette\InvalidArgumentException('Array is not valid list.');
}
$obj = new static;
$obj->list = $array;
return $obj;
}
/**
* Returns an iterator over all items.
* @return \ArrayIterator<int, T>
*/
public function getIterator(): \ArrayIterator
{
@@ -44,7 +62,7 @@ class ArrayList implements \ArrayAccess, \Countable, \IteratorAggregate
/**
* 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,9 +82,10 @@ class ArrayList implements \ArrayAccess, \Countable, \IteratorAggregate
/**
* Returns a item.
* @param int $index
* @return mixed
* @return T
* @throws Nette\OutOfRangeException
*/
#[\ReturnTypeWillChange]
public function offsetGet($index)
{
if (!is_int($index) || $index < 0 || $index >= count($this->list)) {
@@ -102,7 +121,7 @@ class ArrayList implements \ArrayAccess, \Countable, \IteratorAggregate
/**
* Prepends a item.
* @param mixed $value
* @param T $value
*/
public function prepend($value): void
{
+37 -19
View File
@@ -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<T> $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 @@ class Arrays
/**
* 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<T> $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 @@ class Arrays
* 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<T1> $array1
* @param array<T2> $array2
* @return array<T1|T2>
*/
public static function mergeTree(array $array1, array $array2): array
{
@@ -81,7 +90,7 @@ class Arrays
/**
* 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 getKeyOffset(array $array, $key): ?int
@@ -111,7 +120,9 @@ class Arrays
/**
* Returns the first item from the array or null if array is empty.
* @return mixed
* @template T
* @param array<T> $array
* @return ?T
*/
public static function first(array $array)
{
@@ -121,7 +132,9 @@ class Arrays
/**
* Returns the last item from the array or null if array is empty.
* @return mixed
* @template T
* @param array<T> $array
* @return ?T
*/
public static function last(array $array)
{
@@ -132,7 +145,7 @@ class Arrays
/**
* 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
{
@@ -146,7 +159,7 @@ class Arrays
/**
* 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
{
@@ -161,8 +174,8 @@ class Arrays
/**
* 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
{
@@ -181,7 +194,8 @@ class Arrays
/**
* 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
{
@@ -286,9 +300,11 @@ class Arrays
/**
* 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<T> $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)
@@ -381,8 +397,9 @@ class Arrays
/**
* 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(iterable $array, $object)
{
@@ -396,7 +413,7 @@ class Arrays
/**
* Converts value to array key.
* @param mixed $value
* @return int|string
* @return array-key
*/
public static function toKey($value)
{
@@ -407,6 +424,7 @@ class Arrays
/**
* Returns copy of the $array where every item is converted to string
* and prefixed by $prefix and suffixed by $suffix.
* @param string[] $array
* @return string[]
*/
public static function wrap(array $array, string $prefix = '', string $suffix = ''): array
+1
View File
@@ -97,6 +97,7 @@ class DateTime extends \DateTime implements \JsonSerializable
* @param string|\DateTimeZone $timezone (default timezone is used if null is passed)
* @return static|false
*/
#[\ReturnTypeWillChange]
public static function createFromFormat($format, $time, $timezone = null)
{
if ($timezone === null) {
+23
View File
@@ -148,6 +148,29 @@ final class FileSystem
}
/**
* Fixes permissions to a specific file or directory. Directories can be fixed recursively.
* @throws Nette\IOException on error occurred
*/
public static function makeWritable(string $path, int $dirMode = 0777, int $fileMode = 0666): void
{
if (is_file($path)) {
if (!@chmod($path, $fileMode)) { // @ is escalated to exception
throw new Nette\IOException("Unable to chmod file '$path' to mode " . decoct($fileMode) . '. ' . Helpers::getLastError());
}
} elseif (is_dir($path)) {
foreach (new \FilesystemIterator($path) as $item) {
static::makeWritable($item->getPathname(), $dirMode, $fileMode);
}
if (!@chmod($path, $dirMode)) { // @ is escalated to exception
throw new Nette\IOException("Unable to chmod directory '$path' to mode " . decoct($dirMode) . '. ' . Helpers::getLastError());
}
} else {
throw new Nette\IOException("File or directory '$path' not found.");
}
}
/**
* Determines if the path is absolute.
*/
+4 -2
View File
@@ -248,7 +248,7 @@ class Html implements \ArrayAccess, \Countable, \IteratorAggregate, HtmlStringab
'isindex' => 1, 'wbr' => 1, 'command' => 1, 'track' => 1,
];
/** @var array<int, Html|string> nodes */
/** @var array<int, HtmlStringable|string> nodes */
protected $children = [];
/** @var string element's name */
@@ -662,8 +662,9 @@ class Html implements \ArrayAccess, \Countable, \IteratorAggregate, HtmlStringab
/**
* Returns child node (\ArrayAccess implementation).
* @param int $index
* @return static|string
* @return HtmlStringable|string
*/
#[\ReturnTypeWillChange]
final public function offsetGet($index)
{
return $this->children[$index];
@@ -712,6 +713,7 @@ class Html implements \ArrayAccess, \Countable, \IteratorAggregate, HtmlStringab
/**
* Iterates over elements.
* @return \ArrayIterator<int, HtmlStringable|string>
*/
final public function getIterator(): \ArrayIterator
{
+45 -13
View File
@@ -47,27 +47,59 @@ final class ObjectHelpers
/** @throws MemberAccessException */
public static function strictCall(string $class, string $method, array $additionalMethods = []): void
{
$hint = self::getSuggestion(array_merge(
get_class_methods($class),
self::parseFullDoc(new \ReflectionClass($class), '~^[ \t*]*@method[ \t]+(?:\S+[ \t]+)??(\w+)\(~m'),
$additionalMethods
), $method);
$trace = debug_backtrace(0, 3); // suppose this method is called from __call()
$context = ($trace[1]['function'] ?? null) === '__call'
? ($trace[2]['class'] ?? null)
: null;
if (method_exists($class, $method)) { // called parent::$method()
$class = 'parent';
if ($context && is_a($class, $context, true) && method_exists($context, $method)) { // called parent::$method()
$class = get_parent_class($context);
}
if (method_exists($class, $method)) { // insufficient visibility
$rm = new \ReflectionMethod($class, $method);
$visibility = $rm->isPrivate()
? 'private '
: ($rm->isProtected() ? 'protected ' : '');
throw new MemberAccessException("Call to {$visibility}method $class::$method() from " . ($context ? "scope $context." : 'global scope.'));
} else {
$hint = self::getSuggestion(array_merge(
get_class_methods($class),
self::parseFullDoc(new \ReflectionClass($class), '~^[ \t*]*@method[ \t]+(?:\S+[ \t]+)??(\w+)\(~m'),
$additionalMethods
), $method);
throw new MemberAccessException("Call to undefined method $class::$method()" . ($hint ? ", did you mean $hint()?" : '.'));
}
throw new MemberAccessException("Call to undefined method $class::$method()" . ($hint ? ", did you mean $hint()?" : '.'));
}
/** @throws MemberAccessException */
public static function strictStaticCall(string $class, string $method): void
{
$hint = self::getSuggestion(
array_filter((new \ReflectionClass($class))->getMethods(\ReflectionMethod::IS_PUBLIC), function ($m) { return $m->isStatic(); }),
$method
);
throw new MemberAccessException("Call to undefined static method $class::$method()" . ($hint ? ", did you mean $hint()?" : '.'));
$trace = debug_backtrace(0, 3); // suppose this method is called from __callStatic()
$context = ($trace[1]['function'] ?? null) === '__callStatic'
? ($trace[2]['class'] ?? null)
: null;
if ($context && is_a($class, $context, true) && method_exists($context, $method)) { // called parent::$method()
$class = get_parent_class($context);
}
if (method_exists($class, $method)) { // insufficient visibility
$rm = new \ReflectionMethod($class, $method);
$visibility = $rm->isPrivate()
? 'private '
: ($rm->isProtected() ? 'protected ' : '');
throw new MemberAccessException("Call to {$visibility}method $class::$method() from " . ($context ? "scope $context." : 'global scope.'));
} else {
$hint = self::getSuggestion(
array_filter((new \ReflectionClass($class))->getMethods(\ReflectionMethod::IS_PUBLIC), function ($m) { return $m->isStatic(); }),
$method
);
throw new MemberAccessException("Call to undefined static method $class::$method()" . ($hint ? ", did you mean $hint()?" : '.'));
}
}
+22
View File
@@ -18,6 +18,8 @@ use Nette;
* @property int $page
* @property-read int $firstPage
* @property-read int|null $lastPage
* @property-read int $firstItemOnPage
* @property-read int $lastItemOnPage
* @property int $base
* @property-read bool $first
* @property-read bool $last
@@ -85,6 +87,26 @@ class Paginator
}
/**
* Returns the sequence number of the first element on the page
*/
public function getFirstItemOnPage(): int
{
return $this->itemCount !== 0
? $this->offset + 1
: 0;
}
/**
* Returns the sequence number of the last element on the page
*/
public function getLastItemOnPage(): int
{
return $this->offset + $this->length;
}
/**
* Sets first page (base) number.
* @return static
+24 -48
View File
@@ -22,6 +22,7 @@ final class Reflection
private const BUILTIN_TYPES = [
'string' => 1, 'int' => 1, 'float' => 1, 'bool' => 1, 'array' => 1, 'object' => 1,
'callable' => 1, 'iterable' => 1, 'void' => 1, 'null' => 1, 'mixed' => 1, 'false' => 1,
'never' => 1,
];
@@ -37,27 +38,29 @@ final class Reflection
/**
* Returns the type of return value of given function or method and normalizes `self`, `static`, and `parent` to actual class names.
* If the function does not have a return type, it returns null.
* If the function has union type, it throws Nette\InvalidStateException.
* If the function has union or intersection type, it throws Nette\InvalidStateException.
*/
public static function getReturnType(\ReflectionFunctionAbstract $func): ?string
{
return self::getType($func, $func->getReturnType());
$type = $func->getReturnType() ?? (PHP_VERSION_ID >= 80100 && $func instanceof \ReflectionMethod ? $func->getTentativeReturnType() : null);
return self::getType($func, $type);
}
/**
* 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
{
return self::getType($func, $func->getReturnType(), true);
$type = Type::fromReflection($func);
return $type ? $type->getNames() : [];
}
/**
* Returns the type of given parameter and normalizes `self` and `parent` to the actual class names.
* If the parameter does not have a type, it returns null.
* If the parameter has union type, it throws Nette\InvalidStateException.
* If the parameter has union or intersection type, it throws Nette\InvalidStateException.
*/
public static function getParameterType(\ReflectionParameter $param): ?string
{
@@ -66,18 +69,19 @@ final class Reflection
/**
* Returns the types of given parameter and normalizes `self` and `parent` to the actual class names.
* @deprecated
*/
public static function getParameterTypes(\ReflectionParameter $param): array
{
return self::getType($param, $param->getType(), true);
$type = Type::fromReflection($param);
return $type ? $type->getNames() : [];
}
/**
* Returns the type of given property and normalizes `self` and `parent` to the actual class names.
* If the property does not have a type, it returns null.
* If the property has union type, it throws Nette\InvalidStateException.
* If the property has union or intersection type, it throws Nette\InvalidStateException.
*/
public static function getPropertyType(\ReflectionProperty $prop): ?string
{
@@ -86,41 +90,28 @@ final class Reflection
/**
* Returns the types of given property and normalizes `self` and `parent` to the actual class names.
* @deprecated
*/
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.');
} elseif ($type instanceof \ReflectionUnionType || $type instanceof \ReflectionIntersectionType) {
throw new Nette\InvalidStateException('The ' . self::toString($reflection) . ' is not expected to have a union or intersection type.');
} else {
throw new Nette\InvalidStateException('Unexpected type of ' . self::toString($reflection));
@@ -128,24 +119,6 @@ final class Reflection
}
/**
* @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 +130,7 @@ final class Reflection
$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) {
@@ -343,6 +316,9 @@ final class Reflection
case T_CLASS:
case T_INTERFACE:
case T_TRAIT:
case PHP_VERSION_ID < 80100
? T_CLASS
: T_ENUM:
if ($name = self::fetch($tokens, T_STRING)) {
$class = $namespace . $name;
$classLevel = $level + 1;
+2 -2
View File
@@ -425,7 +425,7 @@ class Strings
/**
* Returns position in bytes of $nth occurence of $needle in $haystack or null if the $needle was not found.
* Returns position in characters of $nth occurence of $needle in $haystack or null if the $needle was not found.
* Negative value of `$nth` means searching from the end.
*/
public static function indexOf(string $haystack, string $needle, int $nth = 1): ?int
@@ -438,7 +438,7 @@ class Strings
/**
* Returns position in bytes of $nth occurence of $needle in $haystack or null if the needle was not found.
* Returns position in characters of $nth occurence of $needle in $haystack or null if the needle was not found.
*/
private static function pos(string $haystack, string $needle, int $nth = 1): ?int
{
+240
View File
@@ -0,0 +1,240 @@
<?php
/**
* This file is part of the Nette Framework (https://nette.org)
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
*/
declare(strict_types=1);
namespace Nette\Utils;
use Nette;
/**
* PHP type reflection.
*/
final class Type
{
/** @var array */
private $types;
/** @var bool */
private $single;
/** @var string |, & */
private $kind;
/**
* Creates a Type object based on reflection. Resolves self, static and parent to the actual class name.
* If the subject has no type, it returns null.
* @param \ReflectionFunctionAbstract|\ReflectionParameter|\ReflectionProperty $reflection
*/
public static function fromReflection($reflection): ?self
{
if ($reflection instanceof \ReflectionProperty && PHP_VERSION_ID < 70400) {
return null;
} elseif ($reflection instanceof \ReflectionMethod) {
$type = $reflection->getReturnType() ?? (PHP_VERSION_ID >= 80100 ? $reflection->getTentativeReturnType() : null);
} else {
$type = $reflection instanceof \ReflectionFunctionAbstract
? $reflection->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 || $type instanceof \ReflectionIntersectionType) {
return new self(
array_map(
function ($t) use ($reflection) { return self::resolve($t->getName(), $reflection); },
$type->getTypes()
),
$type instanceof \ReflectionUnionType ? '|' : '&'
);
} else {
throw new Nette\InvalidStateException('Unexpected type of ' . Reflection::toString($reflection));
}
}
/**
* Creates the Type object according to the text notation.
*/
public static function fromString(string $type): self
{
if (!preg_match('#(?:
\?([\w\\\\]+)|
[\w\\\\]+ (?: (&[\w\\\\]+)* | (\|[\w\\\\]+)* )
)()$#xAD', $type, $m)) {
throw new Nette\InvalidArgumentException("Invalid type '$type'.");
}
[, $nType, $iType] = $m;
if ($nType) {
return new self([$nType, 'null']);
} elseif ($iType) {
return new self(explode('&', $type), '&');
} else {
return new self(explode('|', $type));
}
}
/**
* 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, string $kind = '|')
{
if ($types[0] === 'null') { // null as last
array_push($types, array_shift($types));
}
$this->types = $types;
$this->single = ($types[1] ?? 'null') === 'null';
$this->kind = count($types) > 1 ? $kind : '';
}
public function __toString(): string
{
return $this->single
? (count($this->types) > 1 ? '?' : '') . $this->types[0]
: implode($this->kind, $this->types);
}
/**
* Returns the array of subtypes that make up the compound type as strings.
* @return string[]
*/
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 $this->kind === '|';
}
/**
* Returns true whether it is an intersection type.
*/
public function isIntersection(): bool
{
return $this->kind === '&';
}
/**
* 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]);
}
/**
* 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;
}
$type = self::fromString($type);
if ($this->isIntersection()) {
if (!$type->isIntersection()) {
return false;
}
return Arrays::every($this->types, function ($currentType) use ($type) {
$builtin = Reflection::isBuiltinType($currentType);
return Arrays::some($type->types, function ($testedType) use ($currentType, $builtin) {
return $builtin
? strcasecmp($currentType, $testedType) === 0
: is_a($testedType, $currentType, true);
});
});
}
$method = $type->isIntersection() ? 'some' : 'every';
return Arrays::$method($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);
});
});
}
}