Станислав Протасевич
Сколько бы мы не использовали 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).  | 
 
   
Ссылки по теме