Самоучитель по PHP 4
.pdfГлава 13. Работа с массивами |
231 |
array_count_values() подсчитывает частоту появления значений в списке $List. Вот пример:
$List=array(1, "hello", 1, "world", "hello"); array_count_values($array);
// возвращает array(1=>2, "hello"=>2, "world"=>1)
Комплексная замена в строке
В предыдущей главе мы рассматривали функцию strtr(), которая заменяла в строке одни буквы на другие, и функцию str_replace(), осуществляющую контекстный поиск и замену. В свете ассоциативных массивов эти две функции объединяются в одну, также называющуюся strtr(), но несущую в себе возможности str_replace().
string strtr(string $st, array $Substitutes)
Эта функция (заметьте — с двумя параметрами, а не с тремя, как обычная strtr()!) берет строку $st и проводит в ней контекстный поиск и замену: ищутся подстроки — ключи в массиве $Substitutes — и замещаются на соответствующие им значения. Таким образом, теперь мы можем выполнить несколько замен сразу, не используя str_replace() в цикле:
$Subs=array(
"<name>" => "Larry", "<time>" => date("d.m.Y")
);
$st="Привет, <name>! Сейчас <time>"; echo strtr($st,$Subs);
А вот как можно "отменить" действие функции HtmlSpecialChars():
$Trans=array_flip(get_html_translation_table()); $st=strtr($st, $Trans);
В результате мы из строки, в которой все спецсимволы заменены на их HTMLэквиваленты, получим исходную строку во всей ее первозданной красе. Функции get_html_translation_table() не уделено много внимания в этой книге. Она возвращает таблицу преобразований, которая применяется при вызове
HtmlSpecialChars().
Функция strtr() начинает поиск с самой длинной подстроки и не проходит по одному и тому же ключу дважды.
232 |
Часть IV. Стандартные функции PHP |
Слияние массивов
array array_merge(array $A1, array $A2, ...)
Функция array_merge() призвана устранить все недостатки, присущие оператору + для слияния массивов. А именно, она сливает массивы, перечисленные в ее аргументах, в один большой массив и возвращает результат. Если в массивах встречаются одинаковые ключи, в результат помещается пара ключ=>значение из того массива, который расположен правее в списке аргументов. Однако это не затрагивает числовые ключи: элементы с такими ключами помещаются в конец результирующего массива в любом случае.
Таким образом, с помощью array_merge() мы можем избавиться от всех недостатков оператора + для массивов. Вот пример, сливающий два списка в один:
$L1=array(10,20,30); $L2=array(100,200,300); $L=array_merge($L1,$L2);
// теперь $L===array(10,20,30,100,200,300);
Всегда используйте эту функцию, если вам нужно работать именно со списками, а не с обычными ассоциативными массивами.
Получение части массива
array array_slice(array $Arr, int $offset [, int $len])
Эта функция возвращает часть массива ассоциативного массива, начиная с пары ключ=>значения со смещением (номером) $offset от начала и длиной $len (если последний параметр не задан, до конца массива).
Параметры $offset и $len задаются по точно таким же правилам, как и аналогичные параметры в функции substr(). А именно, они могут быть отрицательными (в этом случае отсчет осуществляется от конца массива), и т. д. Вот несколько примеров из документации PHP:
$input = array ("a", "b", "c", "d", "e");
$output = array_slice ($input, 2); |
// "c", "d", "e" |
$output = array_slice ($input, 2, -1); |
// "c", "d" |
$output = array_slice ($input, -2, 1); |
// "d" |
$output = array_slice ($input, 0, 3); |
// "a", "b", "c" |
Вставка/удаление элементов
Мы уже знаем несколько операторов, которые отвечают за вставку и удаление элементов. Например, оператор [] (пустые квадратные скобки) добавляет элемент в ко-
Глава 13. Работа с массивами |
233 |
нец массива, присваивая ему числовой ключ, а оператор Unset() вместе с извлечением по ключу удаляет нужный элемент. Язык PHP версии 4 поддерживает и многие другие функции, которые иногда бывает удобно использовать.
int array_push(alist &$Arr, mixed $var1 [, mixed $var2, …])
Эта функция добавляет к списку $Arr элементы $var1, $var2 и т. д. Она присваивает им числовые индексы — точно так же, как это происходит для стандарных []. Если вам нужно добавить всего один элемент, наверное, проще и будет воспользоваться этим оператором:
array_push($Arr,1000); |
// |
вызываем функцию… |
$Arr[]=100; |
// |
то же самое, но короче |
Обратите внимание, что функция array_push() воспринимает массив, как стек, и добавляет элементы всегда в его конец. Она возвращает новое число элементов в массиве.
mixed array_pop(list &$Arr)
Функция array_pop(), а противоположность array_push(), снимает элемент с "вершины" стека (то есть берет последний элемент списка) и возвращает его, удалив после этого его из $Arr. С помощью этой функции мы можем строить конструкции, напоминающие стек. Если список $Arr был пуст, функция возвращает пустую строку.
int array_unshift(list &$Arr, mixed $var1 [, mixed $var2, …])
Функция очень похожа на array_push(), но добавляет перечисленные элементы не в конец, а в начало массива. При этом порядок следования $var1, $var2 и т. д. остается тем же, т. е. элементы как бы "вдвигаются" в список слева. Новым элементам списка, как обычно, назначаются числовые индексы, начиная с 0; при этом все ключи старых элементов массива, которые также были числовыми, изменяются (чаще всего они увеличиваются на число вставляемых значений). Функция возвращает новый размер массива. Вот пример ее применения:
$A=array(10,"a"=>20,30); array_unshift($A,"!","?");
// теперь $A===array(0=>"!", 1=>"?", 2=>10, a=>20, 3=>30)
mixed array_shift(list &$Arr)
Эта функция извлекает первый элемент массива $Arr и возвращает его. Она сильно напоминает array_pop(), но только получает начальный, а не конечный элемент, а также производит довольно сильную "встряску" всего массива: ведь при извлечении первого элемента приходится корректировать все числовые индексы у всех оставшихся элементов…
array array_unique(array $Arr)
234 |
Часть IV. Стандартные функции PHP |
Функция array_unique() возвращает массив, составленный из всех уникальных значений массива $Arr вместе с их ключами. В результирующий массив помещаются первые встретившиеся пары ключ=>значение:
$input=array("a" => "green", "red", "b" => "green", "blue", "red"); $result=array_unique($input);
// теперь $result===array("a"=>"green", "red", "blue");
array array_splice(array &$Arr, int $offset [, int $len] [, int $Repl])
Эта функция, также как и array_slice(), возвращает подмассив $Arr, начиная с индекса $offset максимальной длины $len, но, вместе с тем, она делает и другое полезное действие. А именно, она заменяет только что указанные элементы на то, что находится в массиве $Repl (или просто удаляет, если $Repl не указан). Параметры $offset и $len задаются так же, как и в функции substr() — а именно, они могут быть и отрицательными, в этом случае отсчет начинается от конца массива. За детальными разъяснениями обращайтесь к описанию функции substr(), рассмотренной в предыдущей главе.
Приведу несколько примеров:
$input=array("red", "green", "blue", "yellow"); array_splice($input,2);
//Теперь $input===array("red", "green") array_splice($input,1,-1);
//Теперь $input===array("red", "yellow")
array_splice($input, -1, 1, array("black", "maroon"));
//Теперь $input===array("red", "green", "blue", "black", "maroon") array_splice($input, 1, count($input), "orange");
//Теперь $input===array("red", "orange")
Последний пример показывает, что в качестве параметра $Repl мы можем указать и обычное, строковое значение, а не массив из одного элемента.
Переменные и массивы
array compact(mixed $vn1 [, mixed $vn2, …])
Функция compact(), впервые появившаяся в PHP версии 4, упаковывает в массив переменные из текущего контекста (глобального или контекста функции), заданные своими именами в $vn1, $vn2 и т. д. При этом в массиве образуются пары с ключами, равными содержимому $vnN, и значениями соответствующих переменных. Вот пример использования этой функции:
$a="Test string";
Глава 13. Работа с массивами |
235 |
$b="Some text"; $A=compact("a","b");
// теперь $A===array("a"=>"Test string", "b"=>"Some text")
Почему же тогда параметры функции обозначены как mixed? Дело в том, что они могут быть не только строками, но и списками строк. В этом случае функция последовательно перебирает все элементы этого списка, и упаковывает те переменные из текущего контекста, имена которых она встретила. Более того — эти списки могут, в свою очередь, также содержать списки строк, и т. д. Правда, последнее используется сравнительно редко, но все же вот пример:
$a="Test"; $b="Text"; $c="CCC"; $d="DDD";
$Lst=array("b",array("c","d")); $A=compact("a",$Lst);
// теперь $A===array("a"=>"Test", "b"=>"Text", "c"=>"CCC", "d"=>"DDD")
void extract(array $Arr [, int $type] [, string $prefix])
Эта функция производит действия, прямо противоположные compact(). А именно, она получает в параметрах массив $Arr и превращает каждую его пару ключ=>значение в переменную текущего контекста.
Параметр $type предписывает, что делать, если в текущем контексте уже существует переменная с таким же именем, как очередной ключ в $Arr. Он может быть равен одной из констант, перечисленных в табл. 13.1
Таблица 13.1. Поведение функции extract в случае совпадения переменных
Константа |
Действие |
|
|
EXTR_OVERWRITE |
Переписывать существующую переменную (по умолчанию) |
EXTR_SKIP |
Не перезаписывать переменную, если она уже существует |
EXTR_PREFIX_SAME |
В случае совпадения имен создавать переменную с име- |
|
нем, предваренным префиксом из $prefix. Надо сказать, |
|
что на практике этот режим должен быть совершенно бес- |
|
полезен |
EXTR_PREFIX_ALL |
Всегда предварять имена создаваемых переменных пре- |
|
фиксом $prefix |
По умолчанию подразумевается EXTR_OVERWRITE, т. е. переменные перезаписываются. Вот пара примеров применения этой функции:
// Сделать все переменные окружения глобальными
236 |
Часть IV. Стандартные функции PHP |
extract($HTTP_ENV_VARS);
// То же самое, но с префиксом E_ extract($HTTP_ENV_VARS, EXTR_PREFIX_ALL, "E_");
echo $E_COMSPEC; // выводит переменную окружения COMSPEC
Параметр $prefix имеет смысл указывать только тогда, когда вы применяете режимы EXTR_PREFIX_SAME или EXTR_PREFIX_ALL.
Вообще говоря, использование extract() и compact() может быть оправдано лишь для небольших массивов, да и то только в шаблонах, а в остальных случаях считается признаком дурного тона. Впрочем, если ваш дизайнер никак не может понять, зачем же ему в шаблонах страниц гостевой книги указывать все эти ужасные квадратные скобки и апострофы, можете пойти ему навстречу так:
<table width=100%>
<?foreach($Book as $Entry) { extract($Entry)?> <tr>
<td>Имя: <?=$name?></td> <!-- вместо $Entry['name'] --> <td>Адрес: <?=$url?></td> <!-- вместо $Entry['url'] -->
</tr>
<tr><td colspan=3><?=$text?></td></tr> <tr><td colspan=3><hr></td></tr>
<?}?>
</table>
Здесь вы должны загодя позаботиться, чтобы ключи $Entry ненароком не затерли нужные переменные. Этого можно добиться, например, назвав все важные переменные с прописной буквы (например, $Book и $Entry), а все ключи — с маленькой, как и было сделано немного выше.
Создание списка – диапазона чисел
list range(int $low, int $high)
Эта функция очень простая. Она создает список, заполненный целыми числами от $low до $high включительно. Ее удобно применять, если мы хотим быстро сгенерировать массив для последующего прохождения по нему циклом foreach:
<table>
<?foreach(range(1,100) as $i) {?> <tr>
<td><?=$i?></td>
Глава 13. Работа с массивами |
237 |
<td>Это строка номер <?=$i?></td> </tr>
<?}?>
</table>
С точки зрения дизайнеров (не знакомых с PHP, но которым придется модифицировать внешний вид вашего сценария) представленный подход выглядит явно лучше, чем следующий фрагмент:
<table>
<?for($i=1; $i<=100; $i++) {?> <tr>
<td><?=$i?></td>
<td>Это строка номер <?=$i?></td> </tr>
<?}?>
</table>
Глава 14
Математические
функции
В PHP представлен полный набор математических функций, которые присутствуют в большинстве других языков программирования. Правда, здесь они используются несколько реже, потому что в сценаиях вообще редко приходится иметь дело со сложными вычислениями.
Встроенные константы
PHP версии 4 предлагает нам несколько предопределенных констант, которые обозначают различные математические постоянные с максимальной машинной точностью. Соответствующие этим константам ключевые слова и значения приводятся в табл. 14.1.
|
Таблица 14.1. Математические константы. |
|
|
|
|
Константа |
Величина |
Пояснение |
|
|
|
M_PI |
3,14159265358979323846 |
Число π |
M_E |
2,7182818284590452354 |
e |
M_LOG2E |
1,4426950408889634074 |
Log2(e) |
M_LOG10E |
0,43429448190325182765 |
Lg(e) |
M_LN2 |
0,69314718055994530942 |
Ln(2) |
M_LN10 |
2,30258509299404568402 |
Ln(10) |
M_PI_2 |
1,57079632679489661923 |
π /2 |
M_PI_4 |
0,78539816339744830962 |
π /4 |
M_1_PI |
0,31830988618379067154 |
1/ π |
M_2_PI |
0,63661977236758134308 |
2/ π |
M_SQRTPI |
1,77245385090551602729 |
sqrt(π) |
M_2_SQRTPI |
1,12837916709551257390 |
2/sqrt(π) |
|
Глава 14. Математические функции |
239 |
||
|
M_SQRT2 |
1,41421356237309504880 |
sqrt(2) |
|
|
|
|
Таблица 14.1 (окончание) |
|
|
|
|
|
|
|
Константа |
Величина |
Пояснение |
|
|
|
|
|
|
|
M_SQRT3 |
1,73205080756887729352 |
sqrt(3) |
|
|
M_SQRT1_2 |
0,70710678118654752440 |
1/sqrt(2) |
|
|
M_LNPI |
1,14472988584940017414 |
Ln(π) |
|
|
M_EULER |
0,57721566490153286061 |
Постоянная Эйлера |
Надо заметить, разработчики PHP что-то слишком разошлись, когда вводили стандартные константы. Например, я не могу даже и представить, зачем в Webпрограммировании может потребоваться, например, константа Эйлера. Что же, это их право….
Функции округления
mixed abs(mixed $number)
Возвращает модуль числа. Тип параметра $number может быть float или int, а тип возвращаемого значения всегда совпадает с типом этого параметра.
double round(double $val)
Округляет $val до ближайшего целого и возвращает результат, например: $foo = round(3.4); // $foo == 3.0
$foo = round(3.5); // $foo == 4.0 $foo = round(3.6); // $foo == 4.0
int ceil(float $number)
Возвращает наименьшее целое число, не меньшее $number. Разумеется, передавать в $number целое число бессмысленно.
int floor(float $number)
Возвращает максимальное целое число, не превосходящее $number.
Случайные числа
Следующие три функции предназначены для генерации случайных чисел. Пожалуй, в Web-программировании самое распространенное применение они находят в сценариях показа баннеров.
240 |
Часть IV. Стандартные функции PHP |
Я намеренно не рассматриваю функции rand() и srand(), потому что каче- ство случайных чисел, которые они выдают, никуда не годится. Настоятельно рекомендую вместо них использовать описанные ниже функции, а про rand() вообще забыть.
int mt_rand(int $min=0, int $max=RAND_MAX)
Функция возвращает случайное число, достаточно равномерно даже для того, чтобы использовать ее в криптографии. Подробнее о том алгоритме, который она использует, можно прочитать в Интернете по адресу http://www.math.keio.ac.jp/~matumoto/emt.html, а исходные тексты найти по адресу http://www.scp.syr.edu/~marc/hawk/twister.html. Если вы хотите генерировать числа не от 0 до RAND_MAX (эта константа задает максимально допустимое случайное число, и ее можно получить при помощи вызова mt_getrandmax()), задайте соответствующий интервал в параметрах $min и $max.
Не забудьте только перед первым вызовом этой функции запустить mt_srand().
Давайте теперь рассмотрим один из случаев применения функции mt_rand(). Речь пойдет об извлечении строки со случайным номером из текстового файла (работу с файлами мы рассмотрим чуть позже, а пока скажу лишь, что функция fget() читает очередную строку из файла, дескриптор которого указан ей в первом параметре, а второй параметр задает максимально возможную длину этой строки, для нас это — очень большое число). Поступим так:
for($i=0; mt_rand(0,$i)<1; $i++) $s=fgets($OurFile,10000);
echo "Случайная строка: $s";
Этот способ работает в строгом соответствии с теорией вероятностей: для первой строки вероятность ее извлечения будет 100%, для второй — 50% (она перепишется поверх первой), для третьей — 33%, и т. д. Например, если файл состоит всего из трех строк, то вероятность извлечения третьей строки, как мы уже заметили, будет равна 33%, а значит, первой или второй — соответственно, 66%. Но вероятность извлечения второй строки после первой равна 50%, а 50% от 66% будет также 33%, т. е. вероятность извлечения каждой строки одинакова. Мы видим, что для файла из трех строк алгоритм работает правильно. Не вдаваясь в математические подробности, скажу, что он работает верно и для любого количества строк.
Безусловно, мы могли бы загрузить весь файл в память и выбрать из него нужную строку и при помощи одного-единственного вызова mt_rand(), но если файл содержит очень много данных, это может быть довольно не экономично с точки зрения расхода памяти. Наоборот, для случая коротких файлов способ единовременной загрузки предпочтительнее. Насколько коротких? Думаю, это легче всего определить опытным путем. Рассмотренный нами способ решает проблему с большими файлами.