Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Самоучитель по PHP 4

.pdf
Скачиваний:
82
Добавлен:
02.05.2014
Размер:
4.36 Mб
Скачать

Глава 11. Функции и области видимости

201

for($i=0; $i<$Level*3; $i++) echo " ";

echo "<b>".HtmlSpecialChars($k)."</b> => ", TextDump($v,$Level);

}

}

else echo '"',HtmlSpecialChars($Var),'"'."\n";

}

// Основная функция function Dump(&$Var)

{// Подфункция, выводящая практически окончательный результат if((is_array($Var)||is_object($Var)) && count($Var))

echo "<pre>\n",TextDump($Var),"</pre>\n";

else

echo "<tt>",TextDump($Var),"</tt>\n";

}

В реальной жизни следует использовать функцию Dump(). Функция TextDump() (которая, по правде говоря, и делает всю работу) использует только одну неизвестную нам еще функцию — HtmlSpecialChars(), заменяющую в строке символы типа <, > или " на их HTML-эквиваленты (соответственно, <, > и "). Мы применили дополнительную функцию для того, чтобы вывести сам результат, а главная функция занимается только форматированием этого результата (вставка его в тэги <pre> или <tt> в зависимости от размера вывода).

Несколько советов по использованию функций

Хочется напоследок сказать еще несколько слов о функциях.

Первое — не допускайте, чтобы ваши функции разрастались до гигантских размеров. Дробите их на маленькие, по возможности независимые, части, желательно полезные и сами по себе. Это повысит "читабельность", устойчивость и переносимость ваших программ. В идеале каждая функция не должна занимать больше 20—30 строк, возможно, за редким исключением. Этот совет применим вообще ко всем языкам программирования, а не только к PHP.

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

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

202

Часть III. Основы языка PHP

реализована в ядре PHP. Если это так, то не думайте, что сможете написать ее эффективнее на PHP — ведь часто самый неэффективный Си-код работает быстрее, чем самый изящный на PHP. Возможно, лучше пожертвовать объемом за счет быстродействия — например, при работе с базами данных и сложными файлами лучше применять стандартные функции сериализации, чем писать более эффективно упаковывающие, но свои, потому что стандартные работают очень быстро. Правда, из этого правила существуют и исключения: например, я бы не советовал вам использовать Serialize() для формирования строки, сохраняющейся в Cookies браузера — здесь лучше написать свои функции. Опять же, тут действует принцип: чем меньше в программе собственноручно реализованных функций, тем надежнее она будет работать и тем меньше ее придется тестировать.

ЧАСТЬ IV.

СТАНДАРТНЫЕ ФУНКЦИИ PHP

Глава 12

Строковые функции

Строки в PHP — одни из самых универсальных объектов. Как мы уже видели, любой, сколь угодно сложный объект можно упаковать в строку при помощи функции Serialize() (и обратно через Unserialize()). Строка может содержать абсолютно любые символы с кодами от 0 до 255 включительно. Нет никакого специального маркера "конца строки", как это сделано в Си (там конец строки помечается символом с нулевым кодом). А значит, длина строки во внутреннем представлении PHP хранится где-то отдельно. Для формирования и вставки непечатаемого символа в строку (например, с кодом 1 или 15) используется функция chr(), которую мы рассмотрим ниже.

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

В этой главе я описываю только самые употребительные и удобные функции (около 80%), пропуская все остальные. Какие-то из не вошедших в данную гла- ву функций (например, quotemeta()) мы будем рассматривать в других гла- вах там, где это показалось мне наиболее логичным. Так что, не найдя опи- сание интересующей вас функции здесь, подумайте: возможно, оно лучше подходит для другой темы и его лучше поискать там? И, наконец, последней инстанцией для вас, конечно же, должна являться документация PHP.

Конкатенация строк

Самая, пожалуй, распространенная операция со строками — это их конкатенация, или присоединение к одной строке другой. В ранних версиях PHP для этого, как и для сложения чисел, использовался оператор +, что постоянно приводило к путанице: если к числу прибавляется строка, что должно получиться — число или строка? Если число, то вдруг наша строка содержала на самом деле не число, а какой-то текст? В новой — третьей — версии интерпретатора разработчики отказались от этого механизма и объявили, что + следует применять только для сложения чисел, и никак ина-

Глава 12. Строковые функции

207

че. Что же касается конкатенации строк, то для нее ввели специальный оператор "." (точка).

Оператор "." всегда воспринимает свои операнды как строки и возвращает строку. В случае, если один из операндов не может быть переведен в строковое представление, т. е. если это массив или объект, то он воспринимается как строки array и object соответственно. Вообще говоря, это правило применимо и не только при сцеплении строк, но и при передаче такого операнда в какую-нибудь стандартную функцию, которой требуется строка. Например, следующие команды выведут слово array:

$a=array(10,20,30);

echo $a // Внимание! Неожиданный результат!

Есть и другой, более специализированный, способ конкатенации строк. Он обычно используется, когда значения строковых или числовых переменных перемежаются с обычными словами. Если, к примеру, у нас в $day хранится текущее число, в $month — название месяца и в $year — год, то вывести строку вида "Сегодня 8 мая 2000 года" можно так:

echo "Сегодня $day $month $year года";

При этом в строку, вырабатываемую инструкцией echo, автоматически в нужных местах вставятся значения наших переменных. Это позволяет констатировать тот факт, что в PHP все переменные начинаются с $.

О сравнении строк и инструкции 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

208

Часть IV. Стандартные функции PHP

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-программа";

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

0, а не false).

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

if(strval(strpos($str,"<?"))!="") echo "это PHP-программа";

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

if(strpos($str,"<?")!===false) echo "это PHP-программа";

Глава 12. Строковые функции

209

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

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

Функции для работы с одиночными символами

string chr(int $code)

Возвращает строку из одного символа с кодом $code. Эта функция полезна для вставки каких-либо непечатаемых символов в строку — например, кода нуля или символа прогона страницы, а также при работе с бинарными файлами. Пример из листинга 12.2 позволяет вам просмотреть, какие коды соответствуют всем символам, которые можно отобразить в браузере. Иногда эта программа оказывается очень полезной.

Листинг 12.2. Программа: печать всей таблицы символов

<?

//Сначала создаем массив того, что мы собираемся выводить,

//не заботясь о форматировании (дизайне) информации

for($i=0,$x=0; $x<16; $x++) { for($y=0; $y<16; $y++) {

$Chars[$x][$y]=array($i,chr($i)); $i++;

}

}

//Теперь выводим накопленную информацию, используя идеологию

//вставки участков кода в HTML-документ

?>

<table border=1 cellpadding=1 cellspacing=0> <?for($y=0; $y<16; $y++) {?>

<tr>

<?for($x=0; $x<16; $x++) { ?> <td>

<?=$Chars[$x][$y][0]?>:

210

Часть IV. Стандартные функции PHP

<b><tt><?=$Chars[$x][$y][1]?></tt></b> </td>

<?}?>

</tr>

<?}?>

</table>

?>

int ord(char $ch)

Эта функция, наоборот, возвращает код символа в $ch. Например, ord(chr($n)) всегда равно $n — конечно, если $n заключено между нулем и числом 255.

int strrpos(string $where, char $what)

Данная функция, хотя и похожа внешне на strpos() (см. ниже), несет несколько иную нагрузку. Она ищет в строке $where последнюю позицию, в которой встречается символ $what (если $what — строка из нескольких символов, то выявляется только первый из них, остальные не играют никакой роли — обратите на это особое внимание!). В случае, если искомый символ не найден, возвращается false (см. замечание по этому поводу для strpos()). Вообще, могу сказать, что функция strrpos() применяется очень редко. Слишком уж она не универсальна.

Функции отрезания пробелов

По поводу философии написания программ, которые интенсивно обрабатывают данные, вводимые пользователем (а именно такими программами является большинство сценариев) есть очень правильное изречение: ваша программа должна быть максимально строга к формату выходных данных и максимально лояльна по отношению ко входным данным. Это означает, что, прежде чем передавать полученные от пользователя строки куда-то дальше, — например, другим функциям, — нужно над ними немного поработать. Самое простое, что можно сделать — это отрезать начальные и концевые пробелы.

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