От Автора:
Даже после многолетнего использования PHP мы натыкаемся на функции и особенности, о которых не знали. Некоторые из них могут быть очень полезными, но мало используемыми. Не все из нас читали руководство и справочник функций от корки до корки!
1. Функции с произвольным количеством параметров
Вы могли уже узнать, что PHP позволяет определять функции с необязательными параметрами. Однако существует способ, разрешающий совершенно произвольное количество параметров у функции.
Для начала, вот пример исключительно с необязательными параметрами:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
// 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():
1 2 3 4 5 6 7 8 9 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(). Она позволяет искать файлы, используя шаблоны.
1 2 3 4 5 6 7 8 9 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 ) */ |
Вы можете задавать несколько видов файлов, как здесь:
1 2 3 4 5 6 7 8 9 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 ) */ |
Обратите внимание, что файлы в действительности будут возвращаться с путями, зависящими от вашего запроса:
1 2 3 4 5 6 7 8 9 10 |
$files = glob('../images/a*.jpg'); print_r($files); /* output looks like: Array ( [0] => ../images/apple.jpg [1] => ../images/art.jpg ) */ |
Если вам нужен полный путь к каждому файлу, просто вызовите функцию realpath() для массива возвращенных значений:
1 2 3 4 5 6 7 8 9 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().
1 2 3 4 5 6 7 8 9 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. Сведения об использовании CPU
Для этого мы будем пользоваться функцией getrusage(). Помните о том, что она недоступна на платформе Windows.
1 2 3 4 5 6 7 8 9 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: количество обращений к диску при подкачке страниц
ru_utime.tv_usec: время работы в пользовательском режиме (микросекунды)
ru_utime.tv_sec: время работы в пользовательском режиме (секунды)
ru_stime.tv_usec: время работы в привилегированном режиме (микросекунды)
ru_stime.tv_sec: время работы в привилегированном режиме (секунды)
Чтобы узнать, какие ресурсы CPU потребляет скрипт, нам нужно посмотреть на значения ‘user time’ (время работы в пользовательском режиме) и ‘system time’ (время работы в привилегированном режиме). По умолчанию величины секунд и миллисекунд представляются раздельно. Таким образом, вы можете разделить значение микросекунд на 1 миллион и добавить к значению секунд, чтобы вычислить общее количество секунд как десятичное число.
Рассмотрим пример:
1 2 3 4 5 6 7 8 9 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 секунды, использование CPU было очень-очень низким. Это происходит потому, что во время ожидания (sleep) скрипт фактически не потребляет ресурсов CPU. Существует множество других задач, которые могут занять реальное время, но при этом не использовать время CPU, например ожидание дисковой операции. Так что, как вы видите, использование CPU и действительная длительность времени исполнения — не всегда одно и то же.
Вот другой пример:
1 2 3 4 5 6 7 8 9 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 секунды времени CPU, и почти все время в пользовательском режиме, так как системных вызовов не было.
Время работы в привилегированном режиме (System Time) – это количество времени, которое CPU тратит на выполнение системных запросов к ядру от имени программы. Вот пример этого:
1 2 3 4 5 6 7 8 9 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% CPU в течение всех 3 секунд.
5. Предопределенные, или «волшебные» константы
PHP предусматривает полезные «волшебные» константы для выборки текущего номера строки (__LINE__), пути файла (__FILE__), пути каталога (__DIR__), имени функции (__FUNCTION__), имени класса (__CLASS__), имени метода (__METHOD__) и пространства имен (__NAMESPACE__).
В этой статье мы не собираемся охватывать каждую из них, но я покажу вам некоторые случаи их использования.
Когда в дело включаются другие скрипты, хорошая идея — использование константы __FILE__ (или __DIR__ в версии PHP 5.3):
1 2 3 4 5 6 7 |
// этот код зависит от пути загруженного скрипт // и может вызвать проблемы при использовании из других каталогов require_once('config/database.php'); // а этот код всегда относителен к пути текущего файла // в независимости откуда он был включен require_once(dirname(__FILE__) . '/config/database.php'); |
Использование __LINE__ облегчает отладку программы. Можно отследить номера строк:
1 2 3 4 5 6 7 8 9 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. Генерирование уникальных ID
Могут возникать ситуации, когда вам нужно сгенерировать уникальную строку. Я видел множество людей, использовавших для этого функцию md5(), хотя она предназначена не совсем для этой цели:
1 2 |
// generate unique string echo md5(time() . mt_rand(1,1000000)); |
В действительности существует функция PHP с названием uniqid(), которая для этого подходит абсолютно точно.
1 2 3 4 5 6 7 8 9 10 11 |
// generate unique string echo uniqid(); /* prints 4bd67c947233e */ // generate another unique string echo uniqid(); /* prints 4bd67c9472340 */ |
Можно заметить, что, хотя строки уникальны, они кажутся подобными из-за нескольких первых символов. Это оттого, что сгенерированная строка связана со временем сервера. Прекрасный побочный эффект, так как каждый заново сгенерированный id в дальнейшем следует в алфавитном порядке, так что их можно сортировать.
Чтобы уменьшить вероятность получения дубликатов, можно использовать префикс или второй параметр для увеличения энтропии:
1 2 3 4 5 6 7 8 9 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():
1 2 3 4 5 6 7 8 9 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():
1 2 3 4 5 6 7 8 9 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():
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
$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() позволит вам выполнить какой-нибудь код прямо перед окончанием работы скрипта.
Представьте себе, что вы хотите в конце выполнения своего скрипта собрать некоторую эталонную статистику, скажем, сколько времени ушло на его выполнение:
1 2 3 4 5 6 7 8 9 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(), этот код никогда не выполнится. Также, если возникнет фатальная ошибка (fatal error) или если скрипт будет завершен пользователем (нажатием клавиши Stop в браузере), он снова может не выполниться.
При использовании функции register_shutdown_function() ваш код будет исполняться независимо от того, что скрипт уже окончил работу:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
$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, которые широко не известны, но могут быть очень полезны? Пожалуйста, поделитесь с нами в комментариях. И спасибо за прочтение!
Автор: Burak Guzel
Перевод и редакция: Рог Виктор и Андрей Бернацкий. Команда webformyself.
Источник: //net.tutsplus.com
E-mail: contact@webformyself.com
Проект webformyself.com — Как создать свой сайт. Основы самостоятельного сайтостроения
P.S. Хотите опубликовать интересный тематический материал и заработать? Если ответ «Да», то жмите сюда.
Комментарии (1)