Дважды в месяц мы возвращаемся к любимым постам наших читателей на протяжении всей истории Nettuts +.
Даже после использования PHP в течение многих лет мы натыкаемся на функции и возможности, о которых мы не знали. Некоторые из них могут быть весьма полезными, но недостаточно использованы. Имея это в виду, я составил список из девяти невероятно полезных функций и функций PHP, с которыми вы должны быть знакомы.
1. Функции с произвольным числом аргументов
Возможно, вы уже знаете, что PHP позволяет вам определять функции с необязательными аргументами. Но есть также метод, позволяющий разрешить совершенно произвольное количество аргументов функции.
Во-первых, вот пример с необязательными аргументами:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
// function with 2 optional arguments
function foo($arg1 = », $arg2 = ») {
echo «arg1: $arg1\n»;
echo «arg2: $arg2\n»;
}
foo(‘hello’,’world’);
/* prints:
arg1: hello
arg2: world
*/
foo();
/* prints:
arg1:
arg2:
*/
|
Теперь давайте посмотрим, как мы можем построить функцию, которая принимает любое количество аргументов. На этот раз мы будем использовать func_get_args () :
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
// yes, the argument list can be empty
function foo() {
// returns an array of all passed arguments
$args = func_get_args();
foreach ($args as $k => $v) {
echo «arg».($k+1).»: $v\n»;
}
}
foo();
/* prints nothing */
foo(‘hello’);
/* prints
arg1: hello
*/
foo(‘hello’, ‘world’, ‘again’);
/* prints
arg1: hello
arg2: world
arg3: again
*/
|
2. Использование Glob () для поиска файлов
Многие функции PHP имеют длинные и описательные имена. Однако может быть трудно сказать, что делает функция с именем glob () , если вы уже не знакомы с этим термином из других источников.
Думайте об этом как о более функциональной версии функции scandir () . Это может позволить вам искать файлы с помощью шаблонов.
01
02
03
04
05
06
07
08
09
10
11
12
13
|
// get all php files
$files = glob(‘*.php’);
print_r($files);
/* output looks like:
Array
(
[0] => phptest.php
[1] => pi.php
[2] => post_output.php
[3] => test.php
)
*/
|
Вы можете выбрать несколько типов файлов, например:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
// get all php files AND txt files
$files = glob(‘*.{php,txt}’, GLOB_BRACE);
print_r($files);
/* output looks like:
Array
(
[0] => phptest.php
[1] => pi.php
[2] => post_output.php
[3] => test.php
[4] => log.txt
[5] => test.txt
)
*/
|
Обратите внимание, что файлы могут быть возвращены с путем, в зависимости от вашего запроса:
01
02
03
04
05
06
07
08
09
10
|
$files = glob(‘../images/a*.jpg’);
print_r($files);
/* output looks like:
Array
(
[0] => ../images/apple.jpg
[1] => ../images/art.jpg
)
*/
|
Если вы хотите получить полный путь к каждому файлу, вы можете просто вызвать функцию realpath () для возвращаемых значений:
01
02
03
04
05
06
07
08
09
10
11
12
13
|
$files = glob(‘../images/a*.jpg’);
// applies the function to each array element
$files = array_map(‘realpath’,$files);
print_r($files);
/* output looks like:
Array
(
[0] => C:\wamp\www\images\apple.jpg
[1] => C:\wamp\www\images\art.jpg
)
*/
|
3. Информация об использовании памяти
Наблюдая за использованием памяти вашими скриптами, вы сможете оптимизировать свой код лучше.
В PHP есть сборщик мусора и довольно сложный менеджер памяти. Объем памяти, используемой вашим скриптом. может идти вверх и вниз во время выполнения скрипта. Чтобы получить текущее использование памяти, мы можем использовать функцию memory_get_usage () , а для получения наибольшего объема памяти, используемого в любой момент, мы можем использовать функцию memory_get_peak_usage () .
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
echo «Initial: «.memory_get_usage().» bytes \n»;
/* prints
Initial: 361400 bytes
*/
// let’s use up some memory
for ($i = 0; $i < 100000; $i++) {
$array []= md5($i);
}
// let’s remove half of the array
for ($i = 0; $i < 100000; $i++) {
unset($array[$i]);
}
echo «Final: «.memory_get_usage().» bytes \n»;
/* prints
Final: 885912 bytes
*/
echo «Peak: «.memory_get_peak_usage().» bytes \n»;
/* prints
Peak: 13687072 bytes
*/
|
4. Информация об использовании процессора
Для этого мы будем использовать функцию getrusage () . Имейте в виду, что это не доступно на платформах Windows.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
print_r(getrusage());
/* prints
Array
(
[ru_oublock] => 0
[ru_inblock] => 0
[ru_msgsnd] => 2
[ru_msgrcv] => 3
[ru_maxrss] => 12692
[ru_ixrss] => 764
[ru_idrss] => 3864
[ru_minflt] => 94
[ru_majflt] => 0
[ru_nsignals] => 1
[ru_nvcsw] => 67
[ru_nivcsw] => 4
[ru_nswap] => 0
[ru_utime.tv_usec] => 0
[ru_utime.tv_sec] => 0
[ru_stime.tv_usec] => 6269
[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: swaps
- ru_utime.tv_usec: использованное время пользователя (микросекунды)
- ru_utime.tv_sec: использованное время пользователя (в секундах)
- ru_stime.tv_usec: используемое системное время (микросекунды)
- ru_stime.tv_sec: используемое системное время (секунды)
Чтобы увидеть, сколько ресурсов процессора потребляет скрипт, нам нужно взглянуть на значения «пользовательское время» и «системное время». Секции секунд и микросекунд предоставляются отдельно по умолчанию. Вы можете разделить значение микросекунд на 1 миллион и добавить его к значению секунд, чтобы получить общее количество секунд в виде десятичного числа.
Давайте посмотрим на пример:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
// sleep for 3 seconds (non-busy)
sleep(3);
$data = getrusage();
echo «User time: «.
($data[‘ru_utime.tv_sec’] +
$data[‘ru_utime.tv_usec’] / 1000000);
echo «System time: «.
($data[‘ru_stime.tv_sec’] +
$data[‘ru_stime.tv_usec’] / 1000000);
/* prints
User time: 0.011552
System time: 0
*/
|
Хотя запуск сценария занял около 3 секунд, загрузка процессора была очень низкой. Потому что во время операции сна скрипт фактически не потребляет ресурсы процессора. Есть много других задач, которые могут занимать в реальном времени, но могут не использовать процессорное время, например, ожидание дисковых операций. Итак, как вы видите, загрузка ЦП и фактическая продолжительность времени выполнения не всегда одинаковы.
Вот еще один пример:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
// loop 10 million times (busy)
for($i=0;$i<10000000;$i++) {
}
$data = getrusage();
echo «User time: «.
($data[‘ru_utime.tv_sec’] +
$data[‘ru_utime.tv_usec’] / 1000000);
echo «System time: «.
($data[‘ru_stime.tv_sec’] +
$data[‘ru_stime.tv_usec’] / 1000000);
/* prints
User time: 1.424592
System time: 0.004204
*/
|
Это заняло около 1,4 секунд процессорного времени, почти все из которых было пользовательским, поскольку системных вызовов не было.
Системное время — это время, которое процессор тратит на выполнение системных вызовов для ядра от имени программы. Вот пример этого:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
$start = microtime(true);
// keep calling microtime for about 3 seconds
while(microtime(true) — $start < 3) {
}
$data = getrusage();
echo «User time: «.
($data[‘ru_utime.tv_sec’] +
$data[‘ru_utime.tv_usec’] / 1000000);
echo «System time: «.
($data[‘ru_stime.tv_sec’] +
$data[‘ru_stime.tv_usec’] / 1000000);
/* prints
User time: 1.088171
System time: 1.675315
*/
|
Теперь у нас довольно много системного времени. Это связано с тем, что сценарий вызывает функцию microtime () много раз, которая выполняет запрос через операционную систему для получения времени.
Также вы можете заметить, что цифры не совсем составляют до 3 секунд. Это связано с тем, что на сервере, возможно, были и другие процессы, и сценарий не использовал 100% ЦП в течение всех 3 секунд.
5. Магические Константы
PHP предоставляет полезные магические константы для извлечения номера текущей строки ( __LINE__
), пути к файлу ( __FILE__
), пути к каталогу ( __FILE__
), имени функции ( __FUNCTION__
), имени класса ( __CLASS__
), имени метода (__METHOD__) и пространства имен ( __NAMESPACE__
).
Мы не будем рассматривать каждый из них в этой статье, но я покажу вам несколько вариантов использования.
При включении других сценариев рекомендуется использовать константу
__FILE__
(или также__FILE__
с PHP 5.3):
1
2
3
4
5
6
7
|
// this is relative to the loaded script’s path
// it may cause problems when running scripts from different directories
require_once(‘config/database.php’);
// this is always relative to this file’s path
// no matter where it was included from
require_once(dirname(__FILE__) . ‘/config/database.php’);
|
Использование __LINE__
облегчает отладку. Вы можете отследить номера строк:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
// some code
// …
my_debug(«some debug message», __LINE__);
/* prints
Line 4: some debug message
*/
// some more code
// …
my_debug(«another debug message», __LINE__);
/* prints
Line 11: another debug message
*/
function my_debug($msg, $line) {
echo «Line $line: $msg\n»;
}
|
6. Генерация уникальных идентификаторов
Могут быть ситуации, когда вам нужно сгенерировать уникальную строку. Я видел, что многие люди используют для этого функцию md5()
, хотя она не совсем предназначена для этой цели:
1
2
|
// generate unique string
echo md5(time() . mt_rand(1,1000000));
|
На самом деле есть функция PHP с именем uniqid (), которая предназначена для этого.
01
02
03
04
05
06
07
08
09
10
11
|
// generate unique string
echo uniqid();
/* prints
4bd67c947233e
*/
// generate another unique string
echo uniqid();
/* prints
4bd67c9472340
*/
|
Вы можете заметить, что, хотя строки уникальны, они кажутся похожими для первых нескольких символов. Это связано с тем, что сгенерированная строка связана со временем сервера. Это на самом деле имеет приятный побочный эффект, так как каждый новый сгенерированный идентификатор появляется позже в алфавитном порядке, поэтому они могут быть отсортированы.
Чтобы уменьшить вероятность получения дубликата, вы можете передать префикс или второй параметр для увеличения энтропии:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
// with prefix
echo uniqid(‘foo_’);
/* prints
foo_4bd67d6cd8b8f
*/
// with more entropy
echo uniqid(»,true);
/* prints
4bd67d6cd8b926.12135106
*/
// both
echo uniqid(‘bar_’,true);
/* prints
bar_4bd67da367b650.43684647
*/
|
Эта функция будет генерировать более короткие строки, чем md5()
, что также сэкономит вам немного места.
7. Сериализация
Вам когда-нибудь нужно было хранить сложную переменную в базе данных или текстовом файле? Вам не нужно придумывать причудливое решение для преобразования ваших массивов или объектов в форматированные строки, поскольку в PHP уже есть функции для этой цели.
Есть два популярных метода сериализации переменных. Вот пример, который использует serialize () и unserialize () :
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
// a complex array
$myvar = array(
‘hello’,
42,
array(1,’two’),
‘apple’
);
// convert to a string
$string = serialize($myvar);
echo $string;
/* prints
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»;}
*/
// you can reproduce the original variable
$newvar = unserialize($string);
print_r($newvar);
/* prints
Array
(
[0] => hello
[1] => 42
[2] => Array
(
[0] => 1
[1] => two
)
[3] => apple
)
*/
|
Это был родной метод сериализации PHP. Однако, поскольку JSON стал очень популярным в последние годы, они решили добавить поддержку для него в PHP 5.2. Теперь вы также можете использовать функции json_encode()
и json_decode()
:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
// a complex array
$myvar = array(
‘hello’,
42,
array(1,’two’),
‘apple’
);
// convert to a string
$string = json_encode($myvar);
echo $string;
/* prints
[«hello»,42,[1,»two»],»apple»]
*/
// you can reproduce the original variable
$newvar = json_decode($string);
print_r($newvar);
/* prints
Array
(
[0] => hello
[1] => 42
[2] => Array
(
[0] => 1
[1] => two
)
[3] => apple
)
*/
|
Он более компактен и, что лучше всего, совместим с javascript и многими другими языками. Однако для сложных объектов некоторая информация может быть потеряна.
8. Сжатие строк
Говоря о сжатии, мы обычно думаем о файлах, таких как ZIP-архивы. Возможно сжатие длинных строк в PHP без использования каких-либо архивных файлов.
В следующем примере мы будем использовать функции gzcompress () и gzuncompress () :
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
$string =
«Lorem ipsum dolor sit amet, consectetur
adipiscing elit.
adipiscing.
sapien vel feugiat vestibulum, nulla dui pretium orci,
non ultricies elit lacus quis ante.
sit amet, consectetur adipiscing elit.
pretium ullamcorper urna quis iaculis.
sed turpis tempor luctus.
mollis congue.
ornare a, aliquam a nunc.
tellus posuere adipiscing.
augue.
sed nunc.
Nullam in neque eget metus hendrerit scelerisque
eu non enim.
id euismod urna sodales.
$compressed = gzcompress($string);
echo «Original size: «.
/* prints
Original size: 800
*/
echo «Compressed size: «.
/* prints
Compressed size: 418
*/
// getting it back
$original = gzuncompress($compressed);
|
Мы смогли достичь почти 50% уменьшения размера. Также функции gzencode () и gzdecode () достигают аналогичных результатов, используя другой алгоритм сжатия.
9. Зарегистрируйте функцию отключения
Существует функция register_shutdown_function () , которая позволит вам выполнить некоторый код непосредственно перед завершением работы скрипта.
Представьте, что вы хотите получить некоторую статистику в конце выполнения вашего скрипта, например, сколько времени потребовалось для запуска:
01
02
03
04
05
06
07
08
09
10
|
// capture the start time
$start_time = microtime(true);
// do some stuff
// …
// display how long the script took
echo «execution took: «.
(microtime(true) — $start_time).
» seconds.»;
|
Сначала это может показаться тривиальным. Вы просто добавляете код в самый конец скрипта, и он запускается до его завершения. Однако, если вы когда-нибудь вызовете функцию exit () , этот код никогда не запустится. Кроме того, если есть фатальная ошибка или если сценарий завершается пользователем (нажатием кнопки «Стоп» в браузере), он снова может не запуститься.
Когда вы используете register_shutdown_function (), ваш код будет выполняться независимо от того, почему скрипт прекратил работу:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
$start_time = microtime(true);
register_shutdown_function(‘my_shutdown’);
// do some stuff
// …
function my_shutdown() {
global $start_time;
echo «execution took: «.
(microtime(true) — $start_time).
» seconds.»;
}
|
Вывод
Известны ли вам какие-либо другие функции PHP, которые не широко известны, но могут быть весьма полезны? Пожалуйста, поделитесь с нами в комментариях. И спасибо за чтение!