Почему «традиционная» подсказка типов не разрешена в PHP? - PullRequest
8 голосов
/ 21 января 2011

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

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

Ответы [ 3 ]

10 голосов
/ 12 мая 2015

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

9 голосов
/ 21 января 2011

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

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


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

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

Объект в int / float ( ref )
неопределенное поведение

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

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

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

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

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

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

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

1 голос
/ 21 января 2011

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

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

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

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

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

...