Только что обнаружил, что подсказка типов разрешена в PHP, но не для целых чисел. , строки, логические значения или числа с плавающей запятой.
Почему PHP не разрешает подсказку типа для таких типов, как целое число, строки, ...?
Только что обнаружил, что подсказка типов разрешена в PHP, но не для целых чисел. , строки, логические значения или числа с плавающей запятой.
Почему PHP не разрешает подсказку типа для таких типов, как целое число, строки, ...?
PHP имеет свободную типизацию, где ваши «примитивные» типы автоматически подтасовываются в зависимости от контекста, в котором они используются. Подсказка типа ничего бы не изменила, поскольку строка может использоваться как int или наоборот. Подсказки типов могут быть действительно полезны только для сложных типов, таких как массивы и объекты, которые не могут быть четко обработаны как целые числа, строки или другие примитивы.
Иными словами, поскольку PHP не имеет понятия о конкретных типах, вы не можете требовать int где-то, потому что он не знает, что такое int на самом деле. С другой стороны, объект относится к определенному типу, поскольку MyClass не взаимозаменяем с MyOtherClass.
Просто для справки, вот что происходит, когда вы пытаетесь конвертировать между такими типами (не исчерпывающий список):
Преобразование в объект (ref)
"Если объект преобразуется в объект, он не изменяется. Если значение любого другого типа преобразуется в объект, новый экземпляр stdClass создается встроенный класс. Если значение равно NULL, новый экземпляр будет пустым. Массивы преобразуются в объект со свойствами, названными ключами, и соответствующими значениями. Для любого другого значения используется переменная-член с именем scalar em> будет содержать значение."
Объект для int/float (ссылка)
неопределенное поведение
Объект на логическое значение (ref)
в PHP5 всегда TRUE
Объект в строку (ref)
объекта. __toString()
магический метод будет вызван, если применимо.
Объект в массив (ref)
"Если объект преобразуется в массив, результатом является массив, элементами которого являются свойства объекта. Ключами являются имена переменных-членов, за несколькими заметными исключениями: целочисленные свойства недоступны; Частные переменные имеют имя класса, предшествующее имени переменной; защищенные переменные имеют '*' перед именем переменной. Эти добавленные значения имеют нулевые байты с обеих сторон. Это может привести к неожиданному поведению».
Массив для int/float (ссылка)
неопределенное поведение
Массив в логическое значение (ref)
Если массив пуст (т. е. не содержит элементов), он оценивается как ЛОЖЬ, в противном случае — ИСТИНА.
Массив в строку (ref)
строка "Массив"; используйте print_r()
или var_dump()
для печати содержимого массива
Массив в объект (ref)
"Массивы преобразуются в объект со свойствами, названными ключами и соответствующими значениями."
Начиная с PHP 7.0 есть поддержка bool
, int
, float
и string
. Добавлена поддержка в RFC скалярных типов. Есть два режима: слабый и строгий. Я рекомендую прочитать RFC, чтобы полностью понять различия, но, по сути, преобразования типов происходят только в слабом режиме.
Учитывая этот код:
function mul2(int $x) {
return $x * 2;
}
mul2("1");
В слабом режиме (который является режимом по умолчанию) это преобразует "1"
в 1
.
Чтобы включить строгие типы, добавьте declare(strict_types=1);
в начало файла. В строгом режиме будет выдаваться ошибка:
Неустранимая ошибка: аргумент 1, переданный в mul2(), должен быть целочисленного типа, указанная строка
Неправильно называть это «подсказкой типа». «Подсказка» подразумевает, что это некоторая необязательная типизация, простая подсказка, а не требование, однако типизированные параметры функции вовсе не являются необязательными - если вы укажете неправильный тип, вы получите фатальную ошибку. Называть это «подсказкой типа» было ошибкой.
Теперь о причинах, по которым в PHP нет примитивной типизации параметров функций. PHP не имеет барьера между примитивными типами — т. е. string, integer, float, bool — более-менее взаимозаменяемы, можно иметь $a = "1";
, а затем echo $a+3;
и получить 4
. Все внутренние функции также работают таким образом — если функция ожидает строку, а вы передаете целое число, оно преобразуется в строку, если функция ожидает число с плавающей запятой и получает целое число, оно преобразуется в число с плавающей запятой и т. д. Это отличается от типов объектов — преобразования между, скажем, SimpleXMLElement
и DirectoryIterator
нет, да и быть не может, в этом нет никакого смысла.
Таким образом, если вы введете функцию, которая принимает целое число 1
, а не строку 1
, вы создаете несовместимость между внутренними функциями и пользовательскими функциями и создаете проблемы для любого кода, который предполагает, что они почти одинаковы. Это будет большим изменением в поведении PHP-программ, и это изменение нужно будет распространить на весь код, использующий такие функции, поскольку в противном случае вы рискуете ошибиться при переходе между «строгим» и «нестрогим» кодом. Это подразумевало бы необходимость переменных типов, типизированных свойств, типизированных возвращаемых значений и т. д. - большие изменения. А поскольку PHP не является компилируемым языком, вы не получаете преимуществ статического управления типами с его недостатками - вы получаете только неудобства, но не дополнительную безопасность. По этой причине типизация параметров не допускается в PHP.
Есть еще вариант — принудительная типизация, т.е. поведение, аналогичное тому, что делают внутренние функции — преобразование между типами. К сожалению, это не удовлетворяет сторонников строгой типизации, поэтому консенсуса пока не найдено, а значит, и нет.
С другой стороны, объектные типы никогда не были спорными — понятно, что между ними нет преобразования, никакой код не предполагает их взаимозаменяемость и проверки могут быть только для них строгими, причем как с внутренними, так и с внешними функциями. Таким образом, введение строгих типов объектов не было проблемой.