- What is mixed in php
- Определение типа
- Типизация параметров функции
- Типизация возвращаемого значения
- Типизация свойств
- Тип Union
- What is mixed in php
- Base types
- Composite types
- Intersection types
- Union types
- Type aliases
- PHP 8.0: New mixed pseudo type
- mixed is a pseudo type
- mixed in union with other types
- mixed is assumed when no type is declared
- Type variance
- Contravariance: mixed parameters types
- Covariance: mixed return types
- Invariance: mixed property types
- Usage with void
- Nullable mixed types
- Practical Usage
- Backwards compatibility
- Polyfill
- Related Changes
What is mixed in php
В отличие от ряда языков программирования в PHP при определении переменных или параметров функций можно не указывать тип данных. Однако в принципе PHP в ряде ситуаций — при определении свойств классов, параметров или возвращаемого значения функций — позволяет указать тип данных. Установка типа данных позволит избежать ситуаций, когда в программу будут переданы данные не тех типов, которые ожидалась разработчиком.
function isPositive($number) < return $number >0; > $result = isPositive("-Youdontknowwhoiam"); if($result) echo "положительное"; else echo "отрицательное или равно нулю";
В данном случае функция isPositive() очевидно ожидает, что в качестве параметра будет передано число, чтобы установить, больше оно нуля или нет. Тем не менее при вызове функции мы можем передать в нее произвольное значение. Чтобы оградиться от подобным ситуаций необходимо явным образом указать, что функция может принимать только число, то есть типизировать параметр функции.
Определение типа
Какие определения типов могут использоваться при типизации:
- bool : допустимые значения true и false
- float : значение должно число с плавающей точкой
- int : значение должно представлять целое число
- string : значение должно представлять строку
- mixed : любое значение
- callable : значение должно представлять функцию
- array : значение должно представлять массив
- iterable : значение должно представлять массив или класс, который реализует интерфейс Traversable . Применяется при переборе в цикле foreach
- Имя класса: объект должен представлять данный класс или его производные классы
- Имя интерфейса: объект должен представлять класс, который реализует данный интерфейс
- Self : объект должен представлять тот же класс или его производный класс. Может использоваться только внутри класса.
- parent : объект должен представлять родительский класс данного класса. Может использоваться только внутри класса.
Типизация параметров функции
При типизации параметров тип указывается перед названием параметра:
function isPositive(int $number) < return $number >0; > $result1 = isPositive(25); // норм - 25 число $result2 = isPositive("25"); // норм - PHP может преобразовать значение в число $result3 = isPositive("-Youdontknowwhoiam"); // Ошибка TypeError
В данном случае параметр $number должен представлять тип int , то есть целое число. Поэтому при вызове функции мы должны передать в функцию целочисленное значение. Если будет передано значение другого типа, то PHP попытается преобразовать значение. В некоторых случаях такое преобразование можно завершится успешно:
В других случаях прееобразование может завершится неудачно, и программа завершит выполнение с ошибкой TypeError :
$result3 = isPositive("-Youdontknowwhoiam");
function sum(array $numbers, callable $condition) < $result = 0; foreach($numbers as $number)< if($condition($number)) < $result += $number; >> return $result; > $isPositive = function($n) < return $n >0;>; $myNumbers = [-2, -1, 0, 1, 2, 3, 4, 5]; $positiveSum = sum($myNumbers, $isPositive); echo $positiveSum; // 15
В данном случае параметры функции должный представлять массив и другую функцию (тип callable ). В качестве функции можно передать анонимную функцию.
Типизация возвращаемого значения
Для установки типа возвращаемого из функции значения после списка параметров указывается двоеточие : и после него тип данных:
function isPositive (int $number) : bool < return $number >0; > $result = isPositive(34);
В данном случае функция isPositive должна возвращать значение типа bool , то есть true или false .
Другой пример — возвращение функции:
function select($n): callable< switch($n)< case 1: return function($a, $b) ; case 2: return function($a, $b) ; case 3: return function($a, $b) ; default: return function($a, $b) ; > > $selection = select(2); echo $selection(4,5); // -1
Особо стоит отметить ключевое слово static , добавленное в PHP 8, которое применяется, если надо возвратить из метода класса объект этого же класса:
class Node < function generate() : static< return new Node(); >> $node1 = new Node(); $node2 = $node1->generate();
Типизация свойств
В качестве типа свойств может применяться любой тип кроме callable :
class Person < public $name; public int $age; >$tom = new Person(); $tom->name = "Tom"; $tom->age = 36; // корректное значение echo $tom->age; // 36 $tom->age = "36"; // корректное значение, так как PHP может преобразовать в число echo $tom->age; // 36 $tom->age = "thirty-eight"; // некорректное значение, возникнет ошибка TypeError echo $tom->age;
В данном случае явным образом определено, что свойство $age представляет именно тип int , то есть целое число. Соответственно этому свойству мы сможем присвоить только целое число.
Стоит учитывать, что свойство, для которого не указан тип данных, по умолчанию имеет значение null . Тогда как свойство, для которого указан тип, неинициализировано, то есть не имеет никакого конкретного значения.
Соответственно если нетипизированное свойство мы сможем использовать, то при попытке обратиться к типизированному, но неинициализиованному свойству программа завершит выполнение ошибкой:
$tom = new Person(); echo $tom->name; // норм - null echo $tom->age; // ошибка - свойство неинициализировано
Тип Union
В PHP 8 был добавлен тип union или объединение, который по сути представляет объединение типов, разделенных вертикальной чертой | . Например, мы хотим написать функцию сложения чисел, и чтобы в функцию можно было передавать только числа. Однако числа в PHP предствлены двумя типами — int и float . Чтобы не создавать по функции для каждого типа, применим объединения:
function sum(int|float $n1, int|float $n2,): int|float < return $n1 + $n2; >echo sum(4, 5); // 9 echo "
"; echo sum(2.5, 3.7); // 6.2
В данном случае мы говорим, что параметры $n1 и $n2 могут представлять как тип int , так и тип float . Аналогично возвращаемое значение также может представлять либо int , либо float .
What is mixed in php
PHP uses a nominal type system with a strong behavioral subtyping relation. The subtyping relation is checked at compile time whereas the verification of types is dynamically checked at run time.
PHP’s type system supports various base types that can be composed together to create more complex types. Some of these types can be written as type declarations.
Base types
Some base types are built-in types which are tightly integrated with the language and cannot be reproduced with user defined types.
- Built-in types
- null type
- Scalar types:
- bool type
- int type
- float type
- string type
- false
- true
- Interfaces
- Classes
- Enumerations
Composite types
It is possible to combine simple types into composite types. PHP allows types to be combined in the following ways:
Intersection types
An intersection type accepts values which satisfies multiple class-type declarations, rather than a single one. Individual types which form the intersection type are joined by the & symbol. Therefore, an intersection type comprised of the types T , U , and V will be written as T&U&V .
Union types
A union type accepts values of multiple different types, rather than a single one. Individual types which form the union type are joined by the | symbol. Therefore, a union type comprised of the types T , U , and V will be written as T|U|V . If one of the types is an intersection type, it needs to be bracketed with parenthesis for it to written in DNF : T|(X&Y) .
Type aliases
PHP supports two type aliases: mixed and iterable which corresponds to the union type of object|resource|array|string|float|int|bool|null and Traversable|array respectively.
Note: PHP does not support user-defined type aliases.
PHP 8.0: New mixed pseudo type
mixed is a pseudo type added in PHP 8 that conveys the type of the parameter/return/property can be of any type. mixed type includes all scalar types in PHP, null , all class objects, callable , and even resource .
mixed is equivalent to a Union Type of:
string|int|float|bool|null|array|object|callable|resource
With mixed , it is now possible to declare mixed as the type when the parameters, returns, and class properties can be of any type.
mixed is a pseudo type
mixed represents any type PHP can handle, and thus you cannot cast a variable to mixed because it simply doesn’t make sense.
Further, there is no is_mixed() function for the same reasons.
gettype() and get_debug_type() functions will never return mixed as the type of a variable either.
mixed in union with other types
Because mixed represents all types, mixed cannot be used in union with other types:
function (mixed|FooClass $bar): int|mixed <>
Both union types above are not allowed, and will result in a fatal error:
Fatal error: Type mixed can only be used as a standalone type in . on line .
mixed is assumed when no type is declared
When a function parameter or a class property has no explicit type declared, the type is now assumed to be mixed .
Be mindful when you add mixed type to all your existing code; PHP 8 has Union Types that might be a better fit because Union Types allow you to be more specific.
For return types, lack of an explicit return type is equal to mixed|void .
However, note that you cannot declare mixed|void as a return type because mixed is not allowed in a Union Type.
Type variance
When a class method, return type, or a property type is overridden by a sub-class, Liskov Substitution Principle is respected.
Contravariance: mixed parameters types
Function parameter types can be «widened» at a child class or an interface implementation because the widened type still fulfills the contract of the interface/parent class. This means child class parameters can declare a type with a Union Type that includes more types, or a class name that is a parent of the current class.
When a parameter type is declared as mixed , this practically prevents further contravariance because mixed includes all types PHP works with. If possible, always opt for more specific types because once you mark a parameter type as mixed in a public API, all child classes must be capable to deal with mixed types.
Covariance: mixed return types
If a parent class method has declared a return type other than mixed , child classes will not be allowed to declare mixed because it widens the return type scope, thus breaking LSP.
class A < public function foo(): mixed <>> class B extends A < public function foo(): void <>>
The above will result in a fatal error:
Fatal error: Declaration of B::foo(): void must be compatible with A::foo(): mixed
This is because mixed does not include void type. If a return type is not explicitly declared, it is assumed to be mixed|void .
All following declarations are allowed:
class A < public function foo() <>public function bar() <> public function baz(): mixed <> > class B extends A < public function foo(): mixed <>public function bar(): void <> public function baz(): string <> >
- B::foo : Allowed: Narrows down the assumed mixed|void return type of A::foo .
- B::bar : Allowed: Narrows down the assumed mixed|void return type of A::bar .
- B::baz : Allowed: Narrows down the declared mixed type.
Invariance: mixed property types
If a property type is declared as mixed , this type cannot be omitted or changed at all.
Usage with void
PHP supports void pseudo return type to indicate that the function will not return anything. This is equivalent to lack of a return statement, or return; expression without setting an explicit value.
void type and mixed cannot be in a union. Further mixed does not include void .
Nullable mixed types
It is not allowed to declare mixed type as nullable because mixed includes null .
All of the following declarations are not allowed:
function foo(mixed|null $foo) <> function foo(?mixed $foo) <> function foo($foo): mixed|null <> function foo($foo): ?mixed <>
All declarations above will raise a fatal error:
Fatal error: Type mixed can only be used as a standalone type in . on line .
Practical Usage
Many PHP internal functions accept various types, which can now be declared with the mixed type. However, for user-land functions, it is often better to use a specific type or a Union Type.
Functions such var_dump or get_debug_type() can declare its parameters as mixed because these functions accept any type by definition.
If you declare a parameter/return type/class property as mixed type, be mindful that mixed includes types such resource and callable , which are not easily stored, serialized, sanitized, or displayed.
Most user-land functions that need to «accept anything», such as logging functions are better off with a Union Type such as string|int|float|bool|null|object|array .
Backwards compatibility
mixed is soft-reserved since PHP 7. Until PHP 8, it is technically possible to declare a class with name mixed , and it will not raise any errors, warnings, or notices. PHPDoc standard widely used mixed as a type declaration, so it is highly unlikely that even the wildest code base out there declares a class with name mixed .
Attempting to declare a class with name mixed in PHP 8 results the following error:
Fatal error: Cannot use 'mixed' as class name as it is reserved in . on line .
Polyfill
It is not possible to polyfill this functionality because it’s an internal type. If you use mixed type anywhere in your code, be sure that it will always run on a PHP 8+ platform.
Related Changes