Немножко о типизации и сравнениях в PHP

2 комментария

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

Вот хорошая таблица из официальных доков отображающая нестрогое сравнение (немного урезал):

TRUE FALSE 1 0 NULL array() «txt» «»
TRUE FALSE TRUE FALSE FALSE FALSE TRUE FALSE
FALSE FALSE FALSE TRUE TRUE TRUE FALSE TRUE
1 TRUE FALSE FALSE FALSE FALSE FALSE FALSE
0 FALSE TRUE FALSE TRUE FALSE TRUE TRUE
NULL FALSE TRUE FALSE TRUE TRUE FALSE TRUE
array() FALSE TRUE FALSE FALSE TRUE FALSE FALSE
«txt» TRUE FALSE FALSE TRUE FALSE FALSE FALSE
«» FALSE TRUE FALSE TRUE TRUE FALSE FALSE



Но самое интересное на мой взгляд это то как PHP приводит строки к числу. Вот составил таблицу:

«» «text» «1text» «0text» «1text1» «1.1text»
intval 0 0 1 0 1 1
floatval 0 0 1 0 1 1.1

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

К примеру уязвимый код из одной известной CMS:

if($_GET["module_id"]==2){
  mysql_query("SELECT * FROM modules WHERE id='".$_GET["module_id"]."'");
  //...
}

По замыслу разработчиков $_GET["module_id"] должно быть равна числу 2. Но они забыли что любая строка приводится к числу. А это привело к возможности провести атаку типа SQL injection:
http://host/path/script.php?module_id=2' -- d

Вообщем все это я к чему пишу то. При разработке любых скриптов надо давать себе отчет в том зачем в одном месте вы используете строгое сравнение (===) а в другом месте нестрогое сравнение (==). И необходимо постоянно держать в памяти тот факт, что в PHP используется нестрогая типизация (особенно это сложно тем кто перешел на PHP с других языков программирования).

  1. Роберт

    Всё понятн и логично.
    Единстенное, чего никогда не понимал — Где логика, почему "txt" == 0
    Может тут кто пояснит?

    1. Дмитрий Амиров Автор

      Потому что при сравнении строка приводится к числу, к примеру:

      var_dump((int)"bla"); //выведет "int 0"
      var_dump((int)"0bla"); //выведет "int 0"
      var_dump((int)"99bla"); //выведет "int 99"
      var_dump((int)"99bla123"); //выведет "int 99"
      var_dump((float)"9.9bla"); //выведет "float 9.9"
      

      Т.е. грубо говоря из строки берутся начальные символы до первого «не числового» символа. Естественно если числовых символов в начале строки нет, то такая строка приведется к «int 0».

      Ну и дальше все верно «int 0==int 0»

      Надеюсь я смог пояснить)

Добавить комментарий

Прочли запись? Понравилась? Не стесняйтесь, оставьте, пожалуйста, свой комментарий. Мне очень интересно, что вы думаете об этом. Кстати в комментарии вы можете задать мне любой вопрос. Я обязательно отвечу.

Вы можете оставить коментарий анонимно, для этого можно не указывать Имя и email. Все комментарии проходят модерацию, поэтому ваш комментарий появится не сразу.