9 корисних функцій PHP і особливостей, які потрібно знати

21

Від Автора:

Навіть після багаторічного використання PHP ми натикаємося на функції і особливості, про яких не знали. Деякі з них можуть бути дуже корисними, але мало використовуються. Не всі з нас читали керівництво і довідник функцій від корки до корки!

1. Функції з довільною кількістю параметрів

Ви могли вже дізнатися, що PHP дозволяє визначати функції з необов’язковими параметрами. Проте існує спосіб, який дозволяє абсолютно довільну кількість параметрів у функції.

Для початку, ось приклад виключно з необов’язковими параметрами:

// 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():

// 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(). Вона дозволяє шукати файли, використовуючи шаблони.

// get all files php
$files = glob(‘*.php’);
print_r($files);
/* output looks like:
Array
(
[0] => phptest.php
[1] => pi.php
[2] => post_output.php
[3] => test.php
)
*/

Ви можете задавати декілька видів файлів, як тут:

// get all php files AND files txt
$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
)
*/

Зверніть увагу, що файли в дійсності будуть повертатися з шляхами, що залежать від вашого запиту:

$files = glob(‘../images/a*.jpg’);
print_r($files);
/* output looks like:
Array
(
[0] => ../images/apple.jpg
[1] => ../images/art.jpg
)
*/

Якщо вам потрібен повний шлях до кожного файлу, просто викличте функцію realpath() для масиву повернутих значень:

$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().

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. Відомості про використання CPU

Для цього ми будемо користуватися функцією getrusage(). Пам’ятайте про те, що вона недоступна на платформі Windows.

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: кількість звернень до диска при підкачки сторінок

ru_utime.tv_usec: час роботи в режимі користувача (мікросекунди)

ru_utime.tv_sec: час роботи в режимі користувача (секунди)

ru_stime.tv_usec: час роботи в привілейованому режимі (мікросекунди)

ru_stime.tv_sec: час роботи в привілейованому режимі (секунди)

Щоб дізнатися, які ресурси CPU споживає скрипт, нам потрібно подивитися на значення ‘user time’ (час роботи в режимі користувача) і ‘system time’ (час роботи в привілейованому режимі). За замовчуванням величини секунд і мілісекунд подаються роздільно. Таким чином, ви можете розділити значення мікросекунд на 1 мільйон і додати до значення секунд, щоб обчислити загальну кількість секунд, подані як десяткове число.

Розглянемо приклад:

// 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 секунди, використання CPU було дуже-дуже низьким. Це відбувається тому, що під час очікування (sleep) скрипт фактично не споживає ресурсів CPU. Існує безліч інших завдань, які можуть зайняти реальний час, але при цьому не використовувати час CPU, наприклад очікування дискової операції. Так що, як ви бачите, використання CPU і дійсна тривалість часу виконання — не завжди одне і те ж.

Ось інший приклад:

// 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 секунди часу CPU, і майже весь час в режимі користувача, так як системних викликів не було.

Час роботи в привілейованому режимі (System Time) – це кількість часу, який CPU витрачає на виконання системних запитів до ядра від імені програми. Ось приклад цього:

$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% CPU протягом всіх 3 секунд.

5. Зумовлені, або «чарівні» константи

PHP передбачає корисні «чарівні» константи для вибірки поточного номера рядка (__LINE__), шляху до файлу (__FILE__), шляхи каталогу (__DIR__), ім’я функції (__FUNCTION__), імені класу (__CLASS__), імені методу (__METHOD__) і простору імен (__NAMESPACE__).

У цій статті ми не збираємося охоплювати кожну з них, але я покажу вам деякі випадки їх використання.

Коли у справу включаються інші скрипти, хороша ідея — використання константи __FILE__ (або __DIR__ версії PHP 5.3):

// цей код залежить від шляху завантаженого скрипт
// і може викликати проблеми при використанні з інших каталогів
require_once(‘config/database.php’);
// а цей код завжди відносний шляху до поточного файлу
// незалежності звідки він був включений
require_once(dirname(__FILE__) . ‘/config/database.php’);

Використання __LINE__ полегшує налагодження програми. Можна відстежити номери рядків:

// some code
// …
my_debug(«some debug message», __LINE__);
/* prints
Line 4: some message debug
*/
// 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. Генерування унікальних ID

Можуть виникати ситуації, коли вам потрібно згенерувати унікальну рядок. Я бачив безліч людей, які використовували для цього функцію md5(), хоча вона призначена не зовсім для цієї мети:

// generate unique string
echo md5(time() . mt_rand(1,1000000));

В дійсності існує функція PHP з назвою uniqid(), яка для цього підходить абсолютно точно.

// generate unique string
echo uniqid();
/* prints
4bd67c947233e
*/
// generate another unique string
echo uniqid();
/* prints
4bd67c9472340
*/

Можна помітити, що, хоча рядки унікальні, вони здаються подібними з-за кількох перших символів. Це тому, що згенерувала рядок пов’язана з часом сервера. Прекрасний побічний ефект, так як кожен заново згенерований id надалі слід в алфавітному порядку, так що їх можна сортувати.

Щоб зменшити ймовірність отримання дублікатів, можна використовувати префікс або другий параметр для збільшення ентропії:

// with prefix
echo uniqid(‘foo_’);
/* prints
foo_4bd67d6cd8b8f
*/
// entropy with more
echo uniqid(«,true);
/* prints
4bd67d6cd8b926.12135106
*/
// both
echo uniqid(‘bar_’,true);
/* prints
bar_4bd67da367b650.43684647
*/

Ця функція буде генерувати більш короткі строки, ніж md5(), що дозволить заощадити місце.

7. Серіалізація

Вам коли-небудь доводилося зберігати комплексну змінну в базі даних або в текстовому файлі? Вам не потрібно додумувати до химерного рішення перетворити свої масиви або об’єкти відображені рядки, тому що у PHP вже є функції, призначені для цієї мети.

Є два популярних методу серіалізації змінних. У цьому прикладі вживаються serialize() і unserialize():

// 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():

// 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():

$string =
«Lorem ipsum dolor sit amet, consectetur
adipiscing elit. Nunc ut elit id mi ultricies
adipiscing. Nulla facilisi. Praesent pulvinar,
sapien vel feugiat vestibulum, nulla dui pretium orci,
non ultricies elit lacus quis ante. Lorem ipsum dolor
sit amet, consectetur adipiscing elit. Aliquam
pretium ullamcorper urna quis iaculis. Etiam ac massa
sed turpis tempor luctus. Curabitur sed nibh eu elit
mollis congue. Praesent ipsum diam, consectetur vitae
ornare a, aliquam a nunc. In id magna pellentesque
tellus posuere adipiscing. Sed non mi metus, at lacinia
augue. Sed magna nisi, ornare in mollis in, mollis
sed nunc. Etiam at justo in leo congue mollis.
Nullam in neque eget metus hendrerit scelerisque
eu non enim. Ut malesuada lacus eu nulla bibendum
id euismod urna sodales. «;
$compressed = gzcompress($string);
echo «Original size: «. strlen($string).»\n»;
/* prints
Original size: 800
*/
echo «Compressed size: «. strlen($compressed).»\n»;
/* prints
Compressed size: 418
*/
// getting it back
$original = gzuncompress($compressed);

Ми в змозі досягти зменшення розміру майже на 50%. Функції gzencode() і gzdecode() видають схожі результати, використовуючи іншим алгоритмом стискування.

9. Функція Register Shutdown

Функція з назвою register_shutdown_function() дозволить вам виконати який-небудь код прямо перед закінченням роботи скрипта.

Уявіть собі, що ви хочете в кінці виконання свого скрипта зібрати деяку еталонну статистику, скажімо, скільки часу пішло на його виконання:

// 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(), цей код ніколи не виконається. Також, якщо виникне фатальна помилка (fatal error) або якщо скрипт буде завершено користувачем (натисненням клавіші Stop в браузері), він знову може не виконатися.

При використанні функції register_shutdown_function() ваш код буде виконуватися незалежно від того, що скрипт вже закінчив роботу:

$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, які широко не відомі, але можуть бути дуже корисні? Будь ласка, поділіться з нами в коментарях. І спасибі за прочитання!

Переклад і редакція: Ріг Віктор і Андрій Бернацький. Команда webformyself.

E-mail: [email protected]

Проект webformyself.com — Як створити свій сайт. Основи самостійного сайтобудування

P. S. Хочете опублікувати цікавий тематичний матеріал і заробити? Якщо відповідь «Так», то тисніть сюди.