PHP 8.2: true, false и null как самостоятельные типы
true, false и null как самостоятельные типы
Еще в PHP 8.0 была добавлена поддержка Union Types, что позволило объявить тип как объединение двух или более типов. Он разрешал false, true и null, как один из возможных типов для объединенных типов, но запрещал их использование в качестве самостоятельных типов.
До версии PHP 8.2 можно было использовать null и только false только как части Union Types:
function foo(): string|null {}
function strpos(): int|false {}
Попытка использовать null, false, true типы как самостоятельные типы (т.е. не являющиеся частью объединенных типов) приводила к фатальной ошибке компиляции в версиях PHP PHP 8.0 и PHP 8.1:
Fatal error: Null can not be used as a standalone type in ... on line ...
Fatal error: False can not be used as a standalone type in ... on line ...И приходилось использовать PhpDoc для предоставления более точной информации о возвращаемом типе:
class User extends Model
{
/**
* @return false
*/
public function isAdmin(): bool
{
return false;
}
}Начиная с PHP 8.2 можно писать так и не будет ошибок:
class User extends Model
{
public function isAdmin(): false
{
return false;
}
}false, true, null можно использовать как самостоятельный тип везде, где PHP принимает тип:
class Foo {
private true $processed;
private false $focused;
public function process(string|int|true $value): true {}
public function focus(int|false $value): false {}
}Это делает систему типов PHP более выразительной и полной, чтобы иметь возможность точнее объявлять типы возврата, аргумента и свойства.
Различие между void и null
Обратите внимание, что функции, объявленные с возвращаемым типом null, должны явно возвращать return null, иначе вызов функции приведет к исключению TypeError. Функции, которые не возвращают значение явно, либо из-за отсутствия оператора return, либо из-за отсутствия возвращаемого значения (return;), могут продолжать использовать тип void в качестве возвращаемого типа.
В следующем примере выдастся исключение TypeError, так как он должен был быть объявлен с void типом, а не null возвращаемым типом.
function foo(): null {}
foo();
TypeError: foo(): Return value must be of type null, none returned in ...:...Если возвращаемый тип не является null, то объявление функции с возвращаемым типом void или never является более подходящим подходом.
Обнуляемость в null типе
Если тип объявлен null, он не может быть помечен как «nullable» с помощью синтаксиса ?null, так как это приводит к избыточному объявлению типа. PHP выдает ошибку во время компиляции:
function doNotMakeSense(): ?null {}
Fatal error: null cannot be marked as nullable in ... on line ...true тип не принуждает
Когда аргумент, свойство или возвращаемый тип объявлены как true, PHP не преобразует принудительно любой другой тип в true. Это имеет место быть, даже если в коде отключены строгие типы (strict_types) и даже для значений, которые в противном случае принудительно выполняются, как true в нестрогих сравнениях.
Например, следующий вызов функции не приводит целочисленное значение 1 к true, и в результате получается TypeError:
function foo(true $value) {}
foo(1);
TypeError: foo(): Argument #1 ($value) must be of type true, int given, called in ... on line ... and defined in ...:...Использование true в объединенных типах
true тип может использоваться как часть Union Types, если true тип не является избыточным, или использоваться вместе с типом false.
Ниже приведен пример объявления типа объединения, в котором используется true тип:
function sendEmail(true|string): true {
return true;
}
sendEmail(true);Тип PHP bool по сути является объединенным типом true|false. Однако во избежание двусмысленности применяются два из следующих ограничений.
Проверка избыточности с bool типом
true тип нельзя использовать в сочетании с bool типом, потому что bool тип уже включает в себя true тип. Попытка объявить тип объединения bool приводит к фатальной ошибке компиляции:
function foo(true|bool $value) {}
Fatal error: Duplicate type true is redundant in ... on line ...Не допускается союз true|false
Поскольку bool тип по сути такой же, как true|false, использование true|false в качестве типа объединения не допускается:
function foo(true|false $value) {}
Fatal error: Type contains both true and false, bool should be used instead in ... on line ...Использование true в типах пересечений
true тип вообще нельзя использовать в типах пересечений . Тип пересечения с true типом приводит к ошибке компиляции:
function foo(true&false $value) {}
Fatal error: Type true cannot be part of an intersection type in ... on line ...true тип в ковариантности и контравариантности
Тип true считается подтипом bool типа, и PHP также следует стандартным правилам ковариантности и контравариантности по отношению к true типу.
Пример ковариации bool, в котором возвращаемый тип заменяется true типом, а тип объединения сужается в подклассе.
class Foo {
public function test(): bool {}
public function test2(): string|true {}
}
class FooBar extends Foo {
public function test(): false {}
public function test2(): true {}
}Пример контравариантности true, когда типизированный параметр в test() расширяется до bool типа, а тип объединения в test2() расширяется:
class Foo {
public function test(true $value): void {}
public function test2(true|string $value): void {}
}
class FooBar extends Foo {
public function test(bool $value): void {}
public function test2(true|string|int $value): void {}
}Влияние обратной совместимости
До PHP 8.2 нельзя было использовать true, false и null как отдельные типы. PHP 8.2 и более поздние версии позволяют использовать их как самостоятельные типы, приложения с PHP ниже версии PHP 8.2, которым необходимо объявлять true, false и null типы, могут использовать комментарии PHPDoc для дополнительной точности и прибегать к использованию bool типа для совместимости со старыми версиями PHP:
/**
* @param true $value
* @return false
*/
function foo(bool $value): bool {}

Что думаешь?