Почему традиционные подсказки типов не разрешены в PHP?

Только что обнаружил, что подсказка типов разрешена в PHP, но не для целых чисел. , строки, логические значения или числа с плавающей запятой.

Почему PHP не разрешает подсказку типа для таких типов, как целое число, строки, ...?


person mpen    schedule 21.01.2011    source источник
comment
@close-because-its-subjective: я бы отметил, что это вики, но больше не могу. Предположим, это субъективное слово, конечно, но разработчики PHP сделали это по определенной причине, если кто-то знает, что это такое, можно дать окончательный ответ.   -  person mpen    schedule 21.01.2011
comment
Связано с этим: stackoverflow.com/q/29169252/3933332   -  person Rizier123    schedule 30.03.2015


Ответы (3)


PHP имеет свободную типизацию, где ваши «примитивные» типы автоматически подтасовываются в зависимости от контекста, в котором они используются. Подсказка типа ничего бы не изменила, поскольку строка может использоваться как int или наоборот. Подсказки типов могут быть действительно полезны только для сложных типов, таких как массивы и объекты, которые не могут быть четко обработаны как целые числа, строки или другие примитивы.

Иными словами, поскольку PHP не имеет понятия о конкретных типах, вы не можете требовать int где-то, потому что он не знает, что такое int на самом деле. С другой стороны, объект относится к определенному типу, поскольку MyClass не взаимозаменяем с MyOtherClass.


Просто для справки, вот что происходит, когда вы пытаетесь конвертировать между такими типами (не исчерпывающий список):

Преобразование в объект (ref)
"Если объект преобразуется в объект, он не изменяется. Если значение любого другого типа преобразуется в объект, новый экземпляр stdClass создается встроенный класс. Если значение равно NULL, новый экземпляр будет пустым. Массивы преобразуются в объект со свойствами, названными ключами, и соответствующими значениями. Для любого другого значения используется переменная-член с именем scalar будет содержать значение."

Объект для int/float (ссылка)
неопределенное поведение

Объект на логическое значение (ref)
в PHP5 всегда TRUE

Объект в строку (ref)
объекта. __toString() магический метод будет вызван, если применимо.

Объект в массив (ref)
"Если объект преобразуется в массив, результатом является массив, элементами которого являются свойства объекта. Ключами являются имена переменных-членов, за несколькими заметными исключениями: целочисленные свойства недоступны; Частные переменные имеют имя класса, предшествующее имени переменной; защищенные переменные имеют '*' перед именем переменной. Эти добавленные значения имеют нулевые байты с обеих сторон. Это может привести к неожиданному поведению».

Массив для int/float (ссылка)
неопределенное поведение

Массив в логическое значение (ref)
Если массив пуст (т. е. не содержит элементов), он оценивается как ЛОЖЬ, в противном случае — ИСТИНА.

Массив в строку (ref)
строка "Массив"; используйте print_r() или var_dump() для печати содержимого массива

Массив в объект (ref)
"Массивы преобразуются в объект со свойствами, названными ключами и соответствующими значениями."

person Wiseguy    schedule 21.01.2011
comment
Хорошо, но разве это не аргумент в пользу примитивных подсказок типов? Если объекты нельзя жонглировать целыми числами, не должны ли мы хотя бы иметь подсказку типа для не-объекта? - person mpen; 21.01.2011
comment
Ну, я не могу возразить против этого. Никто не говорил, что система PHP идеальна. :-) Я, например, обычно предпочитаю строго типизированный язык. - person Wiseguy; 21.01.2011
comment
Я тоже... но иногда приходится писать на PHP ;) - person mpen; 21.01.2011

Начиная с 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(), должен быть целочисленного типа, указанная строка

person Levi Morrison    schedule 12.05.2015
comment
Я думал, что этот RFC был отклонен по какой-то причине. Рад видеть, что это удалось! - person mpen; 12.05.2015

Неправильно называть это «подсказкой типа». «Подсказка» подразумевает, что это некоторая необязательная типизация, простая подсказка, а не требование, однако типизированные параметры функции вовсе не являются необязательными - если вы укажете неправильный тип, вы получите фатальную ошибку. Называть это «подсказкой типа» было ошибкой.

Теперь о причинах, по которым в PHP нет примитивной типизации параметров функций. PHP не имеет барьера между примитивными типами — т. е. string, integer, float, bool — более-менее взаимозаменяемы, можно иметь $a = "1";, а затем echo $a+3; и получить 4. Все внутренние функции также работают таким образом — если функция ожидает строку, а вы передаете целое число, оно преобразуется в строку, если функция ожидает число с плавающей запятой и получает целое число, оно преобразуется в число с плавающей запятой и т. д. Это отличается от типов объектов — преобразования между, скажем, SimpleXMLElement и DirectoryIterator нет, да и быть не может, в этом нет никакого смысла.

Таким образом, если вы введете функцию, которая принимает целое число 1, а не строку 1, вы создаете несовместимость между внутренними функциями и пользовательскими функциями и создаете проблемы для любого кода, который предполагает, что они почти одинаковы. Это будет большим изменением в поведении PHP-программ, и это изменение нужно будет распространить на весь код, использующий такие функции, поскольку в противном случае вы рискуете ошибиться при переходе между «строгим» и «нестрогим» кодом. Это подразумевало бы необходимость переменных типов, типизированных свойств, типизированных возвращаемых значений и т. д. - большие изменения. А поскольку PHP не является компилируемым языком, вы не получаете преимуществ статического управления типами с его недостатками - вы получаете только неудобства, но не дополнительную безопасность. По этой причине типизация параметров не допускается в PHP.

Есть еще вариант — принудительная типизация, т.е. поведение, аналогичное тому, что делают внутренние функции — преобразование между типами. К сожалению, это не удовлетворяет сторонников строгой типизации, поэтому консенсуса пока не найдено, а значит, и нет.

С другой стороны, объектные типы никогда не были спорными — понятно, что между ними нет преобразования, никакой код не предполагает их взаимозаменяемость и проверки могут быть только для них строгими, причем как с внутренними, так и с внешними функциями. Таким образом, введение строгих типов объектов не было проблемой.

person StasM    schedule 21.01.2011