САМОУЧИТЕЛЬ PHP 4

О сравнении строк и инструкции if-else


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

и !=

(или любые другие, которые могут потребовать перевода строки в число) с операндами-строками, то результат, вопреки ожиданиям, не всегда оказывается верным. Чаще всего это проявляется как раз в инструкции if. Вот примеры (листинг 12.1):

Листинг 12.1. Внимание! Опасное место!

$one=1   // ÷èñëî îäèí

$zero=0  // присваиваем ÷èñëî íоëü

if($one=="") echo 1    // î÷åâèäíî, íå ðàâíî— íå âûâîäèò 1

if($zero=="") echo 3   // Âíèìàíèå! Âîïðåêè îæèäàíèÿì ïå÷àòàåò 3!

if(""==$zero) echo 4   // È ýòî òîæå íå ïîìîæåò!..

if("$zero"=="") echo 5 // Не работает в некоторых версиях PHP 3

if(strval($zero)=="") echo 6; // Âîò òåïåðü ïðàâèëüíî — íå âûâîäèò 6

if($zero==="") echo 7  // Самый лучший способ, но не действует в PHP 3

Получается, что в операциях сравнения пустая строка "" прежде всего



трактуется как 0 (ноль) и уж затем — как "пусто"? Это звучит довольно парадоксально, но это действительно так. Операнды сравниваются как строки только в том случае, если они оба — строки, в противном случае идет числовое сравнение. При этом пустая строка воспринимается как 0, впрочем, как и любая другая, которую интерпретатору не удалось перевести в число.




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

Итак, если вы хотите сравнить две переменные-строки, нужно быть абсолютно уверенными, что их типы именно строковые, а не числовые.

Впрочем, это не распространяется на новый оператор PHP версии 4 === (тройное равенство, или оператор эквивалентности). Его использование заставляет интерпретатор всегда сравнивать величины и по значению, и по их типу. Итак, с точки зрения PHP 0=="", но 0!==="". Если вы не собираетесь программировать на PHP версии, ниже третьей, рекомендую всегда использовать === вместо strval(), как это было сделано в листинге 12.1.

Существует одна стандартная ошибка, которую делают многие. Вот в чем она состоит. Есть такая функция — strpos($str,$what), которая возвращает позицию подстроки $what в строке $str или false, если подстрока не найдена. Пусть нам нужно проверить, встречается ли в некоторой строке $str подстрока <? (и напечатать "это PHP-программа", если встречается). Как мы знаем, вариант

if(strpos($str,"<?")!=false)

  echo "ýòî PHP-ïðîãðàììà";

не годится,

если <? находится[E51]  в самом начале строки (в этом случае не будет выдано наше сообщение, хотя подстрока в действительности найдена, и функция возвратила 0, а не false).

Если вы еще собираетесь работать с PHP версии 3, указанную проблему можно решить так:

if(strval(strpos($str,"<?"))!="")

  echo "ýòî PHP-ïðîãðàììà";

Конечно, выглядит это немного "накручено", зато действительно работает. Приятно отметить, что в PHP версии 4 проблема решается гораздо более изящным образом:

if(strpos($str,"<?")!===false)

  echo "ýòî PHP-ïðîãðàììà";

Рекомендую всегда применять последний способ.



Обратите внимание, что мы используем оператор !=== именно с константой false, а не с пустой строкой "". Дело в том, что для этого оператора false!==="", в то время как, разумеется, false=="".


Содержание раздела