Станислав Протасевич
Сколько бы мы не использовали PHP, всё равно всплывают некоторые функции, о которых мы даже не слышали. Некоторые из них были бы нам очень полезны. Я создал небольшой список полезных функций, которые должны быть в арсенале каждого PHP программиста.
1. Создание функций с переменным числом аргументов
Скорее всего, вы уже знаете, что PHP позволяет нам создавать функции с необязательными аргументами. Сейчас я покажу функцию, в которой число аргументов может меняться от случая к случаю.
Но для начала, вспомним как мы создаём функции обычным образом:
01 |
// функция с двумя необязательными параметрами |
02 |
function foo( $arg1 = '' , $arg2 = '' ) { |
Теперь посмотрим на то, как можно написать функцию с неограниченным количеством аргументов. Для этого будет использовать метод func_get_args():
01 |
// не указываем аргументы |
04 |
// возвращает массив, переданных аргументов |
05 |
$args = func_get_args(); |
07 |
foreach ( $args as $k => $v ) { |
08 |
echo "arg" .( $k +1). ": $v\n" ; |
14 |
/* ничего не выведет */ |
21 |
foo( 'hello' , 'world' , 'again' ); |
2. Используем Glob() для поиска файлов
Часто названия функций говорят сами за себя. Такого нельзя сказать о функции glob().
Если не вдаваться в подробности, её функциональность схожа с методом scandir(). Она позволяет найти необходимый файл по шаблону:
01 |
// найти все php файлы |
02 |
$files = glob ( '*.php' ); |
10 |
[2] => post_output.php |
Для нахождения файлов нескольких типов надо писать так:
01 |
// найти все php и txt файлы |
02 |
$files = glob ( '*.{php,txt}' , GLOB_BRACE); |
10 |
[2] => post_output.php |
Так же можно в шаблоне указать путь:
01 |
$files = glob ( '../images/a*.jpg' ); |
07 |
[0] => ../images/apple.jpg |
08 |
[1] => ../images/art.jpg |
Для того чтобы получить полный путь к документу используйте метод realpath():
01 |
$files = glob ( '../images/a*.jpg' ); |
03 |
// Применить функцию 'realpath' к каждому элементу массива |
04 |
$files = array_map ( 'realpath' , $files ); |
10 |
[0] => C:\wamp\www\images\apple.jpg |
11 |
[1] => C:\wamp\www\images\art.jpg |
3. Информация об используемой памяти
Если вы будете отслеживать количество памяти, которое съедается на работу ваших скриптов то, наверное, чаще будете их оптимизировать.
В PHP существует мощный инструмент отслеживания используемой памяти. В разных частях скрипта нагрузки могут быть разные. Для того чтобы получить значение используемой памяти в данный момент, нам следует использовать метод memory_get_usage(). Для фиксации максимального количества используемой памяти используем memory_get_peak_usage()
01 |
echo "Initial: " .memory_get_usage(). " bytes \n" ; |
06 |
// дадим небольшую нагрузку |
07 |
for ( $i = 0; $i < 100000; $i ++) { |
12 |
for ( $i = 0; $i < 100000; $i ++) { |
16 |
echo "Final: " .memory_get_usage(). " bytes \n" ; |
21 |
echo "Peak: " .memory_get_peak_usage(). " bytes \n" ; |
4. Информация о процессоре
Для этого необходимо использовать метод getrusage(). Но учтите, что на Windows эта функция работать не будет.
18 |
[ru_utime.tv_usec] => 0 |
19 |
[ru_utime.tv_sec] => 0 |
20 |
[ru_stime.tv_usec] => 6269 |
21 |
[ru_stime.tv_sec] => 0 |
Картина, изложенная выше, будет понятно тем, у кого есть опыт в системном администрировании. Для всех остальных предлагаем расшифровку:
- ru_oublock: количество операций блочной записи
- ru_inblock: количество операций блочного чтения
- ru_msgsnd: количество отправленных сообщений
- ru_msgrcv: количество принятых сообщений
- ru_maxrss: максимальный размер невыгружаемого набора
- ru_ixrss: общий объем разделяемой памяти
- ru_idrss: общий объем неразделяемых данных
- ru_minflt: количество используемых страниц памяти
- ru_majflt: количество ошибок отсутствия страниц
- ru_nsignals: количество принятых сигналов
- ru_nvcsw: количество переключений контекста процессом
- ru_nivcsw: количество принудительных переключений контекста
- ru_nswap: количество обращений к диску при подкачке страниц
- ru_utime.tv_usec: время работы в пользовательском режиме (микросекунды)
- ru_utime.tv_sec: время работы в пользовательском режиме (секунды)
- ru_stime.tv_usec: время работы в привилегированном режиме (микросекунды)
- ru_stime.tv_sec: время работы в привилегированном режиме (секунды)
Для того чтобы узнать какие ресурсы вашего процессора используются скриптом, вам необходимо значение "user time" (время работы в пользовательском режиме) и "system time" (время работы в привилегированном режиме). Вы можете получить результат как в секундах, так и в микросекундах. Для того чтобы превратить общее количество секунд в десятичное число, вам необходимо разделить значение микросекунд на 1 миллион и добавить к значению секунд.
Запутанно как-то. Вот пример:
06 |
( $data [ 'ru_utime.tv_sec' ] + |
07 |
$data [ 'ru_utime.tv_usec' ] / 1000000); |
09 |
( $data [ 'ru_stime.tv_sec' ] + |
10 |
$data [ 'ru_stime.tv_usec' ] / 1000000); |
Хотя выполнение скрипта заняло около 3х секунд, процессор не было сильно нагружен. Дело в том, что при вызове (sleep) скрипт практически не потребляет ресурсов процессора. Вообще существует множество задач, которые занимают значительное время, но при этом не используют процессор. К примеру, ожидание операций связанных с диском. Так что вы не всегда используете процессорное время в своих скриптах.
Вот ещё пример:
01 |
// пройтись 10 миллионов раз |
02 |
for ( $i =0; $i <10000000; $i ++) { |
08 |
( $data [ 'ru_utime.tv_sec' ] + |
09 |
$data [ 'ru_utime.tv_usec' ] / 1000000); |
11 |
( $data [ 'ru_stime.tv_sec' ] + |
12 |
$data [ 'ru_stime.tv_usec' ] / 1000000); |
Работа скрипта заняла 1.4 секунды процессорного времени. В данном случае, время системных вызова вообще низко.
Время работы в привилегированном режиме (System Time) - это время, которое процессор затрачивает на выполнение системных запросов к ядру от имени программы. Пример:
01 |
$start = microtime(true); |
02 |
// вызываем microtime каждые 3 секунды |
03 |
while (microtime(true) - $start < 3) { |
09 |
( $data [ 'ru_utime.tv_sec' ] + |
10 |
$data [ 'ru_utime.tv_usec' ] / 1000000); |
12 |
( $data [ 'ru_stime.tv_sec' ] + |
13 |
$data [ 'ru_stime.tv_usec' ] / 1000000); |
Теперь системного времени затратилось намного больше, чем в прошлом примере. Всё благодаря методу microtime(), который использует ресурсы системы.
Однако следует отметить, что выведенное время может быть не точным, т.к. в данный момент времени ресурсы процессора используются и другими программами, что в результате может дать небольшую погрешность.
5. Магические константы
В PHP существует множество магических констант, таких как номер текущей строки (__LINE__), путь к файлу (__FILE__), путь к каталогу (__DIR__), имя функции (__FUNCTION__), имя класса (__CLASS__), имя метода (__METHOD__) и пространства имён (__NAMESPACE__).
Все мы их рассматривать не будем. Посмотрим только лишь парочку:
1 |
// этот скрипт зависит от текущего расположения файла и |
2 |
// может вызвать проблемы, если его использовать из разных дирректорий |
3 |
require_once ( 'config/database.php' ); |
5 |
// этот скрипт не вызовет проблем |
6 |
require_once (dirname( __FILE__ ) . '/config/database.php' ); |
Используйте __LINE__ при отладке скриптов:
03 |
my_debug( "some debug message" , __LINE__ ); |
05 |
Line 4: some debug message |
10 |
my_debug( "another debug message" , __LINE__ ); |
12 |
Line 11: another debug message |
15 |
function my_debug( $msg , $line ) { |
16 |
echo "Line $line: $msg\n" ; |
6. Генерирование уникальных ID
Бывают такие моменты, когда вам надо сгенерировать уникальную строку. Множество раз я видел, что для решения этой задачи используют функцию md5():
1 |
// генерируем случайную строку |
2 |
echo md5(time() . mt_rand(1,1000000)); |
Но на самом деле для этих целей в PHP есть специальная функция uniqid()
01 |
// генерируем случайную строку |
Невооружённым взглядом можно заметить, что первые символы мягко говоря схожи… Так происходит из-за того, что данный метод использует время сервера для генерации символов. Это даже полезно, т.к. все сгенерированные значения получаются в алфавитном порядке, что даёт возможность быстро их сортировать.
Для того чтобы уменьшить шансы получения дубликата, мы можем добавить префикс или использовать второй параметр (увеличит количество символов):
07 |
// со вторым параметром |
10 |
4bd67d6cd8b926.12135106 |
14 |
echo uniqid( 'bar_' ,true); |
16 |
bar_4bd67da367b650.43684647 |
Этот метод генерирует строки размером меньше, чем md5, тем самым вы сможете сэкономить место.
7. Сериализация
Вам когда-нибудь приходилось хранить комплексные данные в базе или в файле? Для того чтобы сконвертировать объект в строку в PHP предусмотрена специальная функция.
Вообще говоря, этих методов 2: serialize() и unserialize()
09 |
// конвертируем в строку |
10 |
$string = serialize( $myvar ); |
14 |
a:4:{i:0;s:5:"hello";i:1;i:42;i:2;a:2:{i:0;i:1;i:1;s:3:"two";}i:3;s:5:"apple";} |
17 |
// получаем исходное значение |
18 |
$newvar = unserialize( $string ); |
Вот так вот работают эти функции. Однако из-за бурного роста популярности JSON, в PHP 5.2 были добавлены 2 метода json_encode() и json_decode(). Их работа схожа с serialize():
09 |
// конвертируем в строку |
10 |
$string = json_encode( $myvar ); |
14 |
["hello",42,[1,"two"],"apple"] |
17 |
// восстанавливаем исходное значение |
18 |
$newvar = json_decode( $string ); |
Этот вариант более компактный и совместимый с другими языками, такими как JavaScript. Однако при работе с очень навороченными объектами может возникнуть потеря данных.
8. Сжатие строк
Кода мы говорим о сжатии, то на ум сразу же приходят архивные файлы в формате ZIP. PHP предоставляет возможность сжатия длинных строк без всяких файлов.
В следующем примере продемонстрируем работу функций gzcompress() и gzuncompress():
02 |
"Lorem ipsum dolor sit amet, consectetur |
03 |
adipiscing elit. Nunc ut elit id mi ultricies |
04 |
adipiscing. Nulla facilisi. Praesent pulvinar, |
05 |
sapien vel feugiat vestibulum, nulla dui pretium orci, |
06 |
non ultricies elit lacus quis ante. Lorem ipsum dolor |
07 |
sit amet, consectetur adipiscing elit. Aliquam |
08 |
pretium ullamcorper urna quis iaculis. Etiam ac massa |
09 |
sed turpis tempor luctus. Curabitur sed nibh eu elit |
10 |
mollis congue. Praesent ipsum diam, consectetur vitae |
11 |
ornare a, aliquam a nunc. In id magna pellentesque |
12 |
tellus posuere adipiscing. Sed non mi metus, at lacinia |
13 |
augue. Sed magna nisi, ornare in mollis in, mollis |
14 |
sed nunc. Etiam at justo in leo congue mollis. |
15 |
Nullam in neque eget metus hendrerit scelerisque |
16 |
eu non enim. Ut malesuada lacus eu nulla bibendum |
17 |
id euismod urna sodales. "; |
19 |
$compressed = gzcompress( $string ); |
21 |
echo "Original size: " . strlen ( $string ). "\n" ; |
26 |
echo "Compressed size: " . strlen ( $compressed ). "\n" ; |
32 |
$original = gzuncompress( $compressed ); |
В наших силах уменьшить объём текста на 50%. В этих же целях можно использовать методы gzencode() и gzdecode(), которые используют другой алгоритм сжатия.
9. Выполнить перед завершением
В PHP существует функция register_shutdown_function(), которая позволит вам выполнить какой-то код перед завершением работы скрипта.
Допустим, вы хотите узнать какую-то информацию… Время работы скрипта:
01 |
// получаем время начала |
02 |
$start_time = microtime(true); |
07 |
// выводим время работы |
08 |
echo "execution took: " . |
09 |
(microtime(true) - $start_time ). |
На первый взгляд это может показаться тривиальной задачей. Для этих целей, вы можете поместить код в конце файла. Однако если перед этим где-то сработает функция exit(), этот код никогда не сработает. Так же, он не сработает если на странице будет ошибка или пользователь прервёт загрузку страницы (нажав на соответствующую кнопку в своём браузере);
При использовании метода register_shutdown_function() код выполнится в любом случае:
01 |
$start_time = microtime(true); |
03 |
register_shutdown_function( 'my_shutdown' ); |
05 |
function my_shutdown() { |
08 |
echo "execution took: " . |
09 |
(microtime(true) - $start_time ). |