PHP, как большинство из нас знает, имеет слабую типизацию . Для тех, кто этого не делает, PHP.net говорит:
PHP не требует (или не поддерживает) явного определения типа в объявлении переменной; тип переменной определяется контекстом, в котором используется переменная.
Нравится вам это или нет, PHP на лету перебрасывает переменные. Итак, следующий код действителен:
$var = "10";
$value = 10 + $var;
var_dump($value); // int(20)
PHP также позволяет явно приводить переменную, например так:
$var = "10";
$value = 10 + $var;
$value = (string)$value;
var_dump($value); // string(2) "20"
Это все круто ... но, для моей жизни, я не могу придумать практическую причину для этого.
У меня нет проблем со строгой типизацией на языках, которые ее поддерживают, например на Java. Это хорошо, и я полностью понимаю это. Кроме того, я знаю - и полностью понимаю полезность - хинтинга типов в параметрах функций.
Проблема, связанная с приведением типов, объясняется приведенной выше цитатой. Если PHP может менять типы по своему желанию , он может делать это даже после принудительного приведения типа; и он может делать это на лету, когда вам нужен определенный тип операции. Это делает следующее действительным:
$var = "10";
$value = (int)$var;
$value = $value . ' TaDa!';
var_dump($value); // string(8) "10 TaDa!"
Так какой смысл?
Возьмите этот теоретический пример мира, в котором приведение пользовательских типов имеет смысл в PHP :
- Вы заставляете переменную приведения
$foo
какint
→(int)$foo
. - Вы пытаетесь сохранить строковое значение в переменной
$foo
. - PHP выбрасывает исключение !! ← Это имело бы смысл. Внезапно причина для пользовательского приведения типов существует!
Тот факт, что PHP будет переключать вещи по мере необходимости, делает точку приведения пользовательских типов неопределенной. Например, следующие два примера кода эквивалентны:
// example 1
$foo = 0;
$foo = (string)$foo;
$foo = '# of Reasons for the programmer to type cast $foo as a string: ' . $foo;
// example 2
$foo = 0;
$foo = (int)$foo;
$foo = '# of Reasons for the programmer to type cast $foo as a string: ' . $foo;
Спустя год после того, как первоначально задали этот вопрос, угадайте, кто обнаружил, что использует приведение типов в практической среде? С уважением.
Требовалось отобразить денежные значения на веб-сайте для меню ресторана. Дизайн сайта требовал обрезки концевых нулей, чтобы дисплей выглядел примерно так:
Menu Item 1 .............. $ 4
Menu Item 2 .............. $ 7.5
Menu Item 3 .............. $ 3
Лучший способ сделать это - привести переменную в число с плавающей точкой:
$price = '7.50'; // a string from the database layer.
echo 'Menu Item 2 .............. $ ' . (float)$price;
PHP обрезает конечные нули с плавающей точкой, а затем преобразует число с плавающей точкой в конкатенацию.
(string)
забросы ?$intval.'bar'
бросает исключение, я все еще не согласен. Это не исключение на любом языке. (Все языки, которые я знаю, выполняют либо автоматическое приведение, либо а.toString()
). Если вы говорите, что$intval = $stringval
выбрасывает исключение, то вы говорите о строго типизированном языке. Я не хотел показаться грубым, так что извините, если я сделал. Я просто думаю, что это идет вразрез с тем, к чему привык каждый разработчик, и намного, намного менее удобно.Ответы:
В языке со слабой типизацией существует приведение типов для устранения неоднозначности в типизированных операциях, когда в противном случае компилятор / интерпретатор использовал бы порядок или другие правила, чтобы предположить, какую операцию использовать.
Обычно я бы сказал, что PHP следует этому шаблону, но в случаях, которые я проверял, PHP вел себя нелогично в каждом.
Вот те случаи, использующие JavaScript в качестве языка сравнения.
Конкатенация строк
Очевидно, что это не проблема в PHP, потому что есть отдельные операторы concatenation (
JavaScript.
) и extension (+
).Сравнение строк
Часто в компьютерных системах «5» больше, чем «10», потому что он не интерпретируется как число. Это не так в PHP, который, даже если оба являются строками, понимает, что они являются числами, и устраняет необходимость в приведении):
JavaScript PHPНабор функций подписи
В PHP реализована простая проверка типов для сигнатур функций, но, к сожалению, она настолько несовершенна, что, вероятно, ее редко можно использовать.
Я думал, что могу делать что-то не так, но комментарий к документам подтверждает, что встроенные типы, отличные от массива, не могут использоваться в сигнатурах функций PHP - хотя сообщение об ошибке вводит в заблуждение.
PHPИ в отличие от любого другого языка, который я знаю, даже если вы используете тип, который он понимает, null больше не может быть передан этому аргументу (
must be an instance of array, null given
). Как глупо.Булева интерпретация
[ Редактировать ]: это новый. Я подумал о другом случае, и снова логика полностью противоположна JavaScript.
JavaScript PHPИтак, в заключение, единственный полезный случай, о котором я могу думать, это ... (барабанная дробь)
Тип усечения
Другими словами, когда у вас есть значение одного типа (скажем, строка), и вы хотите интерпретировать его как другой тип (int), и вы хотите, чтобы оно стало одним из допустимых значений в этом типе:
Я не могу понять, что такое апкастинг (для типа, который включает в себя больше значений) действительно когда-либо получит вас.
Поэтому, хотя я не согласен с предложенным вами использованием типизации (вы, по сути, предлагаете статическую типизацию , но с неоднозначностью, заключающейся в том , что только при принудительном приведении к типу это приведет к ошибке - что приведет к путанице), я думаю, что это хорошо вопрос, потому что , видимо , литье имеет очень мало пользы в PHP.
источник
E_NOTICE
тогда? :)E_NOTICE
может быть в порядке, но для меня неоднозначное состояние касается - как бы вы узнали, взглянув на один бит кода, если бы переменная находилась в этом состоянии (будучи приведенной в другом месте)? Также я нашел другое условие и добавил его в свой ответ.echo "010" == 010
иecho "0x10" == 0x10
;-)Вы смешиваете концепции слабого / сильного и динамического / статического типа.
PHP слаб и динамичен, но ваша проблема в концепции динамического типа. Это означает, что переменные не имеют типа, значения имеют.
«Приведение типов» - это выражение, которое создает новое значение оригинала другого типа; он ничего не делает с переменной (если она задействована).
Единственная ситуация, когда я регулярно печатаю приведенные значения, - это числовые параметры SQL. Вы должны очистить / экранировать любое входное значение, которое вы вставляете в операторы SQL, или (намного лучше) использовать параметризованные запросы. Но если вам нужно какое-то значение, которое ДОЛЖНО быть целым числом, гораздо проще просто привести его.
Рассмотреть возможность:
если бы я пропустил первую строку,
$id
был бы простой вектор для инъекции SQL. Приведение гарантирует, что это безвредное целое число; любая попытка вставить некоторый SQL просто приведет к запросуid=0
источник
mysql_real_escape_string($id);
еще не решен?mysql_real_escape_string()
имеет уязвимость, когда ничего не делает со строками типа '0x01ABCDEF' (то есть шестнадцатеричное представление целого числа). В некоторых многобайтовых кодировках (к счастью, не в Юникоде) такая строка может использоваться для разбиения запроса (поскольку MySQL оценивает его как нечто, содержащее кавычку). Вот почему ни,mysql_real_escape_string()
ниis_int()
лучший выбор для работы с целочисленными значениями. Типотипирование есть.Я нашел одно применение для приведения типов в PHP:
я разрабатываю приложение для Android, которое делает http-запросы к PHP-сценариям на сервере для получения данных из базы данных. Сценарий хранит данные в виде объекта PHP (или ассоциативного массива) и возвращается в виде объекта JSON в приложение. Без приведения типов я получил бы что-то вроде этого:
Но, используя приведение типов PHP
(int)
к идентификатору пользователя при сохранении объекта PHP, я получаю это возвращаемое в приложение:Затем, когда объект JSON анализируется в приложении, это избавляет меня от необходимости анализировать идентификатор в целое число!
Видите, очень полезно.
источник
Одним из примеров являются объекты с методом __tostring:
$str = $obj->__toString();
против$str = (string) $obj;
. Во втором набирается гораздо меньше текста, и дополнительными вещами являются знаки препинания, которые набирают больше времени. Я также думаю, что это более читабельно, хотя другие могут не согласиться.Другой делает массив из одного элемента:
array($item);
против(array) $item;
. Это поместит любой скалярный тип (целое число, ресурс и т. Д.) В массив.Альтернативно, если
$item
это объект, его свойства станут ключами к их значениям. Тем не менее, я думаю, что преобразование объекта-> массива немного странно: частные и защищенные свойства являются частью массива и переименовываются. Процитируем документацию PHP : для частных переменных имя класса добавляется перед именем переменной; Защищенные переменные имеют «*» перед именем переменной.Другое использование - преобразование данных GET / POST в соответствующие типы для базы данных. MySQL может справиться с этим сам, но я думаю, что более ANSI-совместимые серверы могут отклонять данные. Причина, по которой я упоминаю только базы данных, заключается в том, что в большинстве других случаев для данных в какой-то момент будет выполняться операция в соответствии с их типом (т. Е. Для int / floats обычно выполняются вычисления и т. Д.).
источник
int
илиfloat
будет происходить при построении запроса).(array) $item
это аккуратно , но полезно?Этот скрипт:
будет работать нормально для,
script.php?tags[]=one
но не удастсяscript.php?tags=one
, потому что_GET['tags']
возвращает массив в первом случае, но не во втором. Поскольку сценарий написан так, чтобы он ожидал массив (и у вас меньше контроля над строкой запроса, отправляемой в сценарий), проблему можно решить путем соответствующего приведения результата из_GET
:источник
Он также может быть использован как быстрый и грязный метод, чтобы гарантировать, что ненадежные данные не собираются что-то сломать, например, при использовании удаленного сервиса, который имеет проверку дерьма и должен принимать только числа.
Очевидно, что это ошибочно и также неявно обрабатывается оператором сравнения в операторе if, но это помогает вам точно знать, что делает ваш код.
источник
$_POST['amount']
содержал строку мусора, php мог бы оценить, что он не больше нуля. Если бы он содержал строку, которая представляла положительное число, это оценило бы true.Я часто вижу, как часто используется «PHP» для преобразования переменных на лету при извлечении данных из внешних источников (пользовательский ввод или база данных). Это позволяет кодировщикам (заметьте, что я не говорил разработчикам) игнорировать (или даже не изучать) различные типы данных, доступные из разных источников.
Один кодер (обратите внимание, что я не сказал «разработчик»), чей код я унаследовал и до сих пор поддерживаю, похоже, не знает, что существует разница между строкой
"20"
, возвращаемой в$_GET
супер-переменной, и операцией с целыми числами,20 + 20
когда она добавляет ее в значение в базе данных. Ей только повезло, что PHP использует.
для конкатенации строк, а не+
как любой другой язык, потому что я видел, как ее код «добавляет» две строки (avarcahr
из MySQL и значение из$_GET
) и получает int.Это практический пример? Только в том смысле, что это позволяет кодировщикам не знать, с какими типами данных они работают. Я лично ненавижу это.
источник