T.me При разработке больших проектов постепенно встает вопрос об оптимизации кода проекта: насколько оправдан расход памяти, каким образом можно увеличить скорость выполнения написанного php-кода. Поначалу многие не задумываются о правильности и эффективности написанного кода, пишут по принципу: работает – да и ладно. Несмотря на то, что интерпретатор PHP довольно быстро выполняет php-код, и есть множество узких мест, замедляющих скорость выполнения кода, которые находятся вне PHP, оптимизация php-кода также занимает важное место, и оптимизацию кода необходимо применять уже в начале процесса написания кода.
Большинство сценариев PHP выполняют простые действия. Стандартное поведение сценария – загрузка небольшого количества информации от пользователя, получение некоторой информации из базы данных или файла, вывод соответствующего HTML и отправка результата работы клиенту. Здесь, первым делом нужно понять, что именно должно стать результатом оптимизации: быстродействие, удобство масштабирования, уменьшение количества используемых ресурсов сервера, уменьшение времени передачи данных или все вместе. В последнем случае, необходимо не только найти все критические участки, но и сбалансировать их оптимизацию.
Приведу простейший пример, пусть на сервере, имеющем 100 Мб свободной оперативной памяти, находятся два скрипта, результат работы которых одинаков. Первый скрипт оптимизирован на максимальное быстродействие, требует 10 Мб памяти и получает данные из файла путем полного его прочтения, второй – на минимальный расход памяти, требует 5 Мб памяти и получает данные из того же файла по частям. В результате одного запроса, первый скрипт выполнится быстрее второго, но если будет более десяти запросов одновременно, именно скорость работы второго скрипта станет более высокой. Почему же так происходит? В первом скрипте узким местом является использование ресурсов памяти, во втором – особенности системы ввода-вывода. После расхода первым скриптом всей доступной оперативной памяти, система перейдет к использованию виртуальной памяти, при этом, дополнительным узким местом этой схемы станет та же система ввода-вывода.
Конечно, этот пример сильно упрощен, и кроме оперативной памяти существуют и другие узкие места, но главная мысль такова: оптимизация для одного случая, может стать критическим местом в другом. В примере, в результате оптимизации для незначительного увеличения скорости при низких нагрузках, существенно уменьшилась скорость выполнения скрипта при более высоких. Поэтому, чтобы получить более высокую отдачу, важно тратить свои силы на оптимизацию областей, действительно заслуживающих внимания.
Я не буду здесь рассматривать оптимизацию операционной системы, оптимизация настроек сервера и т.п., т.к. большинство веб-мастеров пользуется хостингом и, соответственно, не сможет самостоятельно все настроить. Здесь будет рассмотрена только оптимизация php-кода. Следует отметить, что в каждом конкретном случае, некоторые виды оптимизации будут полезны, другие – будут напрасной тратой времени и сил. Часто полезность усовершенствования кода будет пренебрежимо мала. Возможно, со временем, внутренние изменения в PHP сделают успешную оптимизацию бесполезной или даже вредной.
Ниже перечислены основные действия по повышению производительности для PHP 5 версии:
Действия по оптимизации расхода оперативной памяти:
- Анализ результатов работы ваших функций. Перед написанием функции проверьте, не существует ли стандартный аналог.
- Освобождение памяти в случае окончания использования больших массивов или объектов только в глобальной области видимости (в локальной области видимости память будет освобождена автоматически). Обратите внимание, что функция unset() удаляет переменную из области видимости и, только в случае отсутствия на объект других ссылок, освобождает занимаемую объектом память. Присвоение переменной значения null всегда уничтожает объект и освобождает занимаемую объектом память, независимо от того, имеются ли ещё ссылки на этот объект. При этом переменная не будет удалена из области видимости, т.е. фактически переменная будет содержать неопределенное (нулевое) значение и, соответственно, занимать память на содержание этой переменной (порядка 72 байт).
- Анализ оправданности использования ООП (объектно-ориентированного программирования). Перед написанием объектно-ориентированного кода, задайте себе два вопроса: «нужен ли здесь объектно-ориентированный подход?» и «могу ли я писать объектно-ориентированный код?». Например, определение статической функции внутри класса увеличивает объем памяти, необходимой только для содержания этой функции, на 10-18%. Использование в качестве структуры массива, а не класса, также позволяет сэкономить память. Возможно, будет выгоднее просто вынести функции в отдельный файл, а не реализовывать их в качестве методов класса.
- Анализ возможности реализации статической версии метода в классе. Если метод не использует параметр $this, то он должен быть объявлен с использованием ключевого слова static.
Действия по увеличению скорости исполнения кода:
- Анализ оптимизированности SQL-запросов. В большинстве проектов именно оптимизация SQL-запросов дает наибольшее увеличение производительности.
- Использование буферизации вывода, всевозможных кеширующих модулей, позволяет увеличить производительность на 25%-100%.
- Использование более коротких коротких имен для переменных, функций, констант и классов может повысить производительность до 20%. В то же время не забывайте о дальнейшей поддержке кода, говорящее имя функции намного удобнее при модификациях кода.
- Проверка существования переменной (функция isset()) перед обращением к ней. Подавление ошибки, возникающей при обращении к несуществующей переменной, путем использования @ сильно снижает производительность.
- Использование ‘одинарных кавычек’ позволяет интерпретировать код быстрее, т.к. в случае «двойных кавычек» внутри строки ведется поиск переменных
- Анализ возможности выноса «лишних» функций из цикла. Например, замена функции count() на переменную, вычисленную до начала цикла и содержащую результат этой функций, в выражении for($i=0; $i<count($array);$i++) повысит производительность этого цикла. В противном случае функция count() будет вызываться и выполняться на каждой итерации цикла.
- Использование оператора case вместо множественного использования конструкции if…else.
- Использование явного обращения к полям массива. Обращение вида $array[‘id’] выполняется в 7 раз быстрее, чем обращение $array[id]. Кроме того, это защищает от ошибок при дальнейшей поддержке скрипта, т.к. в один прекрасный день может появиться константа с именем id.
- Использование дополнительной переменной, содержащей ссылку на конечный массив, при обработке многомерных массивов в цикле. Для ускорения цикла for($i = 0; $i < 5; $i++) $a[‘b’][‘c’][$i] = func($i);, до начала цикла возможно записать следующую инструкцию $item =p$a[‘b’][‘c’] и переписать цикл так: for($i = 0; $i < 5; $i++) $ref[$i] = $i;.
- Использование модулей Apache mod_gzip и mod_deflate позволяет сократить трафик, за счет чего увеличится скорость загрузки страниц.
Следующие действия по оптимизации кода повышают быстродействие только в случае многократного использования:
- Использование ++$i вместо $i++ в циклах дает прирост производительности в 6%.
- Использование «двойных кавычек» для конкатенации (склеивания) переменных. Инструкция вида $s=»$s1$s2$s3″ интерпретируется быстрее, чем $s=$s1.$s2.$s3. Это утверждение справедливо только для трех и более переменных.
- Использование полных путей в инструкциях include и require позволит тратить меньшее время на поиск системой реального пути.
- Закрытие открытых коннектов к базе данных после того как необходимость в них отпадает. В то же время не следует много раз подключаться к одной и той же базе данных.
- Анализ возможности замены include() и include_once() на require() и require_once() соответственно.
- Использование HTML-вставок в код, вместо вывода значительного объема oстатическихo строк (не содержащих результатов работы кода). Вообще, скорость выдачи статической страницы (HTML), в несколько раз быстрее выдачи страницы написанной на PHP. Но здесь не стоит увлекаться, т.к. ввод в интерпретатора в режим обработки PHP и вывод из него также нагружают сервер.
- Анализ возможности замены функций preg_replace и str_replace в некоторых случаях. Функция str_replace работает быстрее, чем preg_replace, и в тоже время функция strtr быстрее функции str_replace. Также, использование строковых функций strncasecmp, strpbrk и stripos более оптимально, чем использование регулярных выражений. Однако, вместо вложенности этих функций, следует использовать именно функции регулярных выражений.
- Использование явной инициализации переменных. Например, инкремент неинициализироанной переменной в 9-10 раз медленнее, чем предварительно инициализированной. Кроме того, при явной инициализации переменных возникает меньше ошибок.
- В качестве заключения хотелось бы отметить, что использование конструкции echo, вместо функции print, не дает ощутимого роста производительности.
Рекомендации по оценке производительности:
- Для определения времени начала исполнения скрипта, вместо функций, возвращающих текущее время, предпочтительнее использование $_SERVER[«REQUEST_TIME»].
- Используйте профайлер для определения критических участков кода.
Перед оптимизацией быстродействия кода, я настоятельно рекомендую проверить оптимизацию SQL-запросов к базе данных, а также оптимизировать http-запросы, уменьшить размер js и css, подумать над кэшированием шаблонов, и только после этого заняться проверкой кода на производительность.
10 советов по оптимизации PHP-кода
Для обеспечения максимальной производительности PHP-скриптов необходимо учитывать несколько особенностей языка. В этом посте я предлагаю некоторые практические советы по PHP оптимизации, которые вам могут пригодиться.
10 советов по оптимизации PHP-кода:
- echo работает быстрей print
Echo работает немного быстрее print, потому что конструкция echo не предполагает установку возвращаемого значения. Print ведёт себя как функция, хотя и не является «настоящей» функцией (это конструкция языка), и всегда возвращает значение 1. - Оптимизируйте вывод через
Не используйте конкатенацию при выводе через echo. Заключайте строки в одинарные кавычки, когда в ней нет переменных. Используйтеecho
'
var1=
'
,$var1,
'
var2=
'
,$var2;
вместоecho "var1=$var1 var2= $var2";
- ++$I работает быстрее, чем $I++
Это связано с особенностями реализации языка PHP. Постинкремент ($I++) создает одну временную переменную, в то время как преинкремент (++$I) непосредственно изменяет саму переменную. - Закрывайте неиспользуемые соединения с базой данных.
Зачем оставлять соединение с базой, если Вы получили все необходимые данные? Если вовремя не закрывать неиспользуемые соединения, можно исчерпать лимит соединений. Конечно же речь идет о высоконагруженных проектах. - Используйте require() вместо require_once() где это возможно.
Использование require() вместо require_once() хоть и позволяет выиграть в скорости, но может оказаться лишней головной болью, если Вам потребуется в большом проекте отслеживать не подключен где-либо уже этот файл. - ELSE IF работает быстрей,чем SWITCH
- Указывайте полные пути к файлам
При подключении файлов указывайте абсолютный путь к файлам – при этом не тратится время на преобразование относительного пути. - Подавления ошибок с помощью @ идет очень медленно
Старайтесь исключить все возможные ошибки. - Удаляйте свои переменные для освобождения памяти
Несомненно необходимо удалять ненужные переменные для освобождения памяти, тем более, если это большие массивы. Тут не все однозначно и зависит от ситуации. - Используйте кеширование
90% работы вашего приложения – это рутинное, повторяющееся извлечение данных. Используйте кеширование (например, memcached или eAccelerator).
Вот такие простые советы по оптимизации PHP-кода, которые должен знать каждый.
Хороший стиль программирования предполагает оптимизацию во время написания кода, а не латание дыр в последствии.