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 {}
Что думаешь?