Типы PHP
Nette\Utils\Type представляет тип данных PHP. Он служит для анализа, сравнения и работы с типами, полученными как из строки, так и из рефлексии.
Сегодня у PHP очень богатая система типов: от скалярных типов
(int, string) через объекты и интерфейсы до сложных типов
(объединение A|B, пересечение A&B или дизъюнктивная
нормальная форма (A&B)|D). Кроме того, есть особые типы вроде
void, never, mixed и относительные типы self и
static.
Работать с этими типами напрямую, особенно через ReflectionType,
часто громоздко, потому что приходится рекурсивно различать
ReflectionNamedType, ReflectionUnionType и другие объекты. Класс
Nette\Utils\Type всё это скрывает и предоставляет единообразный и
интуитивный API для работы с любым типом, который поддерживает PHP.
Например, он позволяет легко проверить, принимает ли один тип другой (совместимость), расширить типы или преобразовать рефлексию в читаемую запись.
Установка:
composer require nette/utils
Во всех примерах предполагается, что определён такой псевдоним класса:
use Nette\Utils\Type;
fromReflection ($reflection): ?Type
Этот статический метод создаёт объект Type на основе рефлексии.
Параметром может быть объект ReflectionMethod или ReflectionFunction
(возвращается тип возвращаемого значения) либо объект
ReflectionParameter или ReflectionProperty. Он разрешает self,
static и parent в настоящее имя класса. Если у предмета нет
типа, возвращает null.
class DemoClass
{
public self $foo;
}
$prop = new ReflectionProperty(DemoClass::class, 'foo');
echo Type::fromReflection($prop); // 'DemoClass'
fromString (string $type): Type
Этот статический метод создаёт объект Type из его строкового
представления.
$type = Type::fromString('Foo|Bar');
echo $type; // 'Foo|Bar'
fromValue (mixed $value): Type
Статический метод, создающий объект Type на основе типа переданного значения.
$type = Type::fromValue('hello'); // 'string'
$type = Type::fromValue(123); // 'int'
$type = Type::fromValue(new stdClass); // 'stdClass'
Для ресурсов он возвращает mixed, потому что PHP не поддерживает
тип resource. Для анонимных классов он возвращает имя ближайшего
предка или object.
$obj = new class extends Foo { };
$type = Type::fromValue($obj); // 'Foo'
getNames (): (string|array)[]
Возвращает массив строк, представляющих подтипы, из которых состоит составной тип. Для типов-пересечений возвращает массив массивов.
$type = Type::fromString('string|null'); // или '?string'
$type->getNames(); // ['string', 'null']
$type = Type::fromString('(Foo&Bar)|string');
$type->getNames(); // [['Foo', 'Bar'], 'string']
getTypes(): Type[]
Возвращает массив объектов Type, представляющих подтипы, из
которых состоит составной тип:
$type = Type::fromString('string|null'); // или '?string'
$type->getTypes(); // [Type::fromString('string'), Type::fromString('null')]
$type = Type::fromString('(Foo&Bar)|string');
$type->getTypes(); // [Type::fromString('Foo&Bar'), Type::fromString('string')]
$type = Type::fromString('Foo&Bar');
$type->getTypes(); // [Type::fromString('Foo'), Type::fromString('Bar')]
getSingleName(): ?string
Для простых типов (включая простые nullable-типы вроде ?string)
возвращает имя типа. Иначе возвращает null.
$type = Type::fromString('string|null');
echo $type; // '?string'
echo $type->getSingleName(); // 'string'
$type = Type::fromString('?Foo');
echo $type; // '?Foo'
echo $type->getSingleName(); // 'Foo'
$type = Type::fromString('Foo|Bar');
echo $type; // 'Foo|Bar'
echo $type->getSingleName(); // null (это тип-объединение)
isSimple(): bool
Возвращает, является ли тип простым. К простым типам относятся и
простые nullable-типы (например, ?string, ?Foo):
$type = Type::fromString('string');
$type->isSimple(); // true
$type->isUnion(); // false
$type = Type::fromString('?Foo'); // или 'Foo|null'
$type->isSimple(); // true
$type->isUnion(); // true (потому что содержит null)
isUnion(): bool
Возвращает, является ли тип объединением (содержит |).
$type = Type::fromString('Foo&Bar');
$type->isUnion(); // true
isIntersection(): bool
Возвращает, является ли тип пересечением (содержит &).
$type = Type::fromString('Foo&Bar');
$type->isIntersection(); // true
isBuiltin(): bool
Возвращает, является ли тип простым и при этом встроенным типом PHP
(таким как string, int, array, callable и так далее).
$type = Type::fromString('string');
$type->isBuiltin(); // true
$type = Type::fromString('string|int');
$type->isBuiltin(); // false
$type = Type::fromString('Foo');
$type->isBuiltin(); // false
isClass(): bool
Возвращает, является ли тип простым и при этом именем класса (а не
встроенным типом вроде string или int).
$type = Type::fromString('string');
$type->isClass(); // false
$type = Type::fromString('Foo|null');
$type->isClass(); // true
$type = Type::fromString('Foo|Bar');
$type->isClass(); // false
isClassKeyword(): bool
Возвращает, является ли тип одним из внутренних ключевых слов
self, parent или static.
$type = Type::fromString('self');
$type->isClassKeyword(); // true
$type = Type::fromString('Foo');
$type->isClassKeyword(); // false
allows (string|Type $type): bool
Метод allows() проверяет совместимость типов. Например, он может
определить, можно ли передать значение определённого типа как
параметр функции, ожидающей этот тип.
$type = Type::fromString('string|null');
$type->allows('string'); // true
$type->allows('null'); // true
$type->allows('Foo'); // false
$type = Type::fromString('mixed');
$type->allows('null'); // true
with (string|Type $type): Type
Возвращает объект Type, принимающий и исходный тип, и добавляемый. Тем самым создаётся так называемый тип-объединение.
Метод устроен разумно и не дублирует типы без нужды. Если вы добавите
тип, который уже есть или является надмножеством текущего (например,
добавите mixed к string), результат упростится.
$type = Type::fromString('string');
// Расширяем до nullable string
echo $type->with('null'); // '?string'
// Создаём тип-объединение
echo $type->with('int'); // 'string|int'
// Добавляем тип, который перекрывает всё
echo $type->with('mixed'); // 'mixed'