Советы по оптимизации PHP-скриптов. Ускорение PHP-программ Оптимизация клиентской стороны на php

Производительность решений на PHP — частая тема различных споров и дискуссий. Мы не будем сейчас участвовать в них. Ведь как бы там ни было, все всегда зависит от конкретной задачи. К примеру, мне известен достоверный случай, когда некий программный код в течение полутора года переписывали на Ассемблере. Изначально он был написан на Си. Когда работы завершились, позади остались сотни рабочих дней большой группы разработчиков, а на руках — версия ПО, полностью написанная на Ассемблере. Какое же было удивление команды, когда в итоге их творение на Ассемблере заработало гораздо медленней их же, более раннего творения на Си!

Оптимизация программного кода — задача многогранная. Следует учитывать множество факторов. Следует понимать, что в ряде случаев ею вообще можно пренебречь: в конце концов, часто проще докупить высокопроизводительного «железа», чем оплачивать дополнительную работу команды высококлассных разработчиков. Автоматизация, индустриализация, други мои! Роботы заменяют людей. А ведь когда-то были такие профессии, как, например, профессия фонарщика или лифтера, нет, не того, который сейчас чинит и обслуживает лифты. Того, который раньше был штурманом лифта и возил пассажиров куда они просили. Сейчас это уже кажется смешным. А лет через энное количество смех будут вызывать пилоты самолетов. Те будут летать на полностью автоматизированных системах управления И т.д.

Так или иначе, нет смысла оптимизировать очень простые, либо редко используемые части программного обеспечения. По крайней мере до того момента, пока все остальное не в полном порядке. А на что именно следует обратить внимание в первую очередь? Сейчас мы об этом и будем говорить.

Рассмотрим на примере PHP. На самом деле, что бы там не говорили о нем, PHP ничуть не хуже Perl или ASP.NET, я бы сказал даже наоборот — у PHP значительно больше преимуществ. Почему же ему чаще всех достается? Очень просто — потому, что он самый популярный! Ведь и Windows ругают все, под нее больше всего вирусов, в ней больше всего найденных «дыр». Но стоит на ее популярность… Хм более 98% пользователей работают именно под ОС Windows. На все остальные вместе взятые операционные системы приходится не более 2% пользователей. Не удивительно, что к Windows такое внимание. Я уверен, что если любая другая ОС была бы настолько же популярна (и настолько же сложна, функциональна и доступна), в ней было бы найдено не меньше дыр. Ну да ладно, это разговор для отдельной темы.

Возвращаясь к PHP, кроме всего прочего, это, пожалуй, наиболее простой язык программирования, широко применяемый для веба. Его простота и доступность обусловливают возникшую армию новичков, которые хоть что-то в нем пытаются делать. Их некомпетентность часто становится причиной негативных дискуссий о PHP. Тот же ASP.NET не столь доступен. Как следствие — основные его «носители» — достаточно грамотные люди. Со всеми вытекающими последствиями. Но ведь доступность PHP никоим образом не нивелирует его достоинств в руках профессионалов.

В конце концов, на чем написана самая популярная социальная сеть, и второй по посещаемости веб-ресурс в мире, facebook? А его аналог vkontakte? Конечно же, на PHP!

Следует понимать область применения. Если вам нужно проводить серьезные вычисления, особенно связанные с мультимедиа, с большими данными и высокими нагрузками, например, обработкой видео онлайн, конечно же, лучше написать соответствующий код на том же Си и уже использовать его под PHP как откомпилированный модуль. PHP — это скорее некий универсальный шаблонизатор, чем язык программирования, каким мы его понимаем. У PHP задачи совсем иные.

В связи с этим, в оптимизации производительности PHP кода и подходы иные: тут важней оптимизация самого алгоритма, модели решения задачи, чем конкретно кода. Хотя есть и исключения.

7 принципов, или 7 позиций оптимизации кода PHP.

1) Любовь к готовым библиотекам.

Различные готовые библиотеки — вещи, безусловно, полезные и удобные. Но следует не забывать, что бесплатный сыр бывает только в мышеловке. За все, так или иначе, а платить приходится.

Разработка программного обеспечения для реализации задумки некоего сайта всегда (при условии соотносимых уровней исполнителей, конечно же) в плане производительности будет значительно более выгодна, чем применение готовой, универсальной CMS (Content Management System — система управления содержимым, «движок» сайта). Низкая производительность — расплата за универсальность CMS. Это то — же самое, что ездить на базар на личном автобусе, или даже, на самолете, но не на своем легковом автомобиле. То же самое и с готовыми библиотеками.

Но почему я поставил библиотеки на первое место? Потому, что если они применяются, то сразу съедают львиную долю производительности. Смотрите сами: подключение одних только Smarty и DbSimple сразу же «съедает» порядка 0.025 сек. времени и почти 3/4 Мб ОЗУ. И это на неплохом сервере при низкой общей нагрузке. Добавить сюда еще какой-нибудь phpMailer , и мы имеем 0.03 сек. затраченного времени и 1 Мб сожранной памяти попросту на пустом месте. Мы еще ничего не делали, лишь подключили модули, это еще даже без их инициализации! У меня есть один самописный проект, наподобие социальной сети, так в нем на полное создание странички в среднем уходит ощутимо меньше ресурсов. Другой пример — движок новостного сайта, который я разрабатывал: публикации, комментарии и т.д. По большому счету, ничего сверхсложного, но и скорость достойная — в среднем меньше 0.001 сек. на генерацию странички и до 0.15 Мб памяти. Проекты построены на связке PHP + MySQL. Кстати, таким образом, второй из них, спокойно держит более 400тыс. хитов в сутки, со всплесками до 1600 хитов за минуту в пиках и почти 500 хостами онлайн. На VPS за $30/мес. А подключи к нему те три библиотеки, тогда уже не обойтись без выделенного сервера, и не самой слабой конфигурации. А ведь дело нередко доходит до применения с десятка готовых библиотек.

С другой стороны, безусловно, если вы разрабатываете небольшой сайт — для фирмы, или личную страничку, заботиться об оптимизации, и, таким образом, отказываться от применения готовых библиотек тут смысла нет. Время дороже. Если посещаемость вашего сайта не более 1000 посетителей в сутки, не стоит тратить время на идеальный и быстрый код. Пользуйтесь готовыми библиотеками. Вам хватит ресурсов любого хорошего виртуального хостинга. Если у вас посещаемость достигает 2-3 тыс. посетителей в сутки, уже есть смысл задуматься об оптимизации кода. Но все же следует хорошо подумать над тем, стоит ли вам на данном этапе отказываться от готовых библиотек и убивать время на переработку кода (либо же время и деньги на программиста, который это сделает). Зачастую проще просто купить дополнительных ресурсов, или перейти на VPS, оплачивая по $10-50 в месяц.

С другой стороны, следует учитывать сложность перехода на решения без применения готовых библиотек. Тот же движок новостного сайта я написал едва ли не за один день. Ведь кроме всего прочего, «тяжелые» скрипты не только требуют более мощного хостинга, но и замедляют открытие страничек сайта в браузере, особенно если страничка формируется в течение нескольких секунд. Если вам не очень накладно отказаться от применения готовых библиотек — я бы советовал делать это в любом случае.

Подводя итоги, еще раз подчеркну — вы можете спокойно применять библиотеки, наращивая мощность серверов, но не следует забывать, что это первая причина медленной работы ваших скриптов, и кроме высокой нагрузки на «железо», они являются причиной многих задержек загрузки страничек сайта.

2) Игнорирование Zend Optimizer, eAccelerator

Эти замечательные модули главным образом занимаются оптимизацией и динамическим кэшированием откомпилированного PHP кода (байт — кода ). Часто позволяют поднять производительность чуть ли не в десятки раз. Их применение имеет смысл в первую очередь на достаточно больших и высокопосещаемых проектах, хоть вы можете оптимизировать и любые другие сайты на PHP — это не потребует от вас по сути никаких дополнительных манипуляций. О применении данных модулей мы еще поговорим, в следующий раз, это достаточно объемная тема. Пока что вам достаточно запомнить этот пункт.

3) «Кривое» применение баз данных

По сути это отдельная тема. Вам следует помнить, что каждое подключение к БД, каждый запрос, каждая лишняя таблица в запросе и т.д. — все это создает ощутимую нагрузку. Но все же, логика самой БД, а не интерфейса работы с ней, несет наибольшую нагрузку. Мне недавно приходилось оптимизировать один очень популярный модуль для одного из самых популярных «движков» форума. Как мне сразу удалось выяснить — тот самый модуль и был главной причиной существенных тормозов. Добавив одну небольшую таблицу и два новых SQL запроса в PHP код, производительность форума была повышена на 60-80% (в зависимости от странички), потребление памяти снизилось на 5-7%! И это все практически на ровном месте. Как видите — это тот случай, когда добавление «лишней» таблицы и «лишних» запросов существенно увеличивает производительность. Я пошел не экстенсивным, а интенсивным путем, улучшив логику. И получив поистине замечательный результат.

На тему оптимизации БД мы поговорим в ближайшем будущем. Сейчас затрону лишь аспект, связанный с интерфейсом работы, как на PHP, так, впрочем, и на любом другом языке программирования.

Итак, прежде всего, всегда используйте файлы вместо БД, если в этом есть смысл. Когда в этом есть смыл? Предположим, вы пишите движок сайта новостей. Новость добавляется туда раз и навсегда. Она не подвержена последующим изменениям, она большая и цельная. Намного проще и эффективней поместить ее в отдельный файл, а не в БД. А вот рецензию к новости — уже лучше в БД. Ведь на определенных страничках вам явно придется выводить список последних рецензий по теме, или список случайных рецензий. Если писать каждую рецензию в отдельный файл — то при выводе, скажем, 50 рецензий на страничке, нам придется подключать к работе столько же соответствующих файлов рецензий. Писать все рецензии в один и тот же файл тоже не очень хорошо: при их большом количестве файл будет очень большим, и только разрастаться со временем, производительность же, соответственно — снижаться. Да и это попросту может быть достаточно неудобным и небезопасным делом — работа с такими файлами. Другое дело «закидать» наши небольшие рецензии в БД и «выдернуть» нужные одним несложным запросом. То же самое относится к любым часто редактируемым данным. Например, писать счетчик просмотров новостей на файлах — большая глупость. Только БД.

Что касается соединения с БД, его стоит закрывать как только в нем отпадает потребность. Однако, не стоит этого делать, если в работе данного скрипта оно еще пригодится.

Следите за содержимым переменных, которым присваиваются результаты выполнения запросов. Есть смысл использовать unset в ситуациях, когда серьезные объемы данных более не нужны.

4) Отсутствие кэширования

В целом ряде случаев кэширование просто незаменимо. Рассмотрим простой пример. Чуть выше, когда речь шла о БД, я приводил пример со списком рецензий. Предположим, мы заходим на некую страничку, где отображается список из 50 рецензий к последним новостям. Как правило, всех их можно выбрать из БД одним несложным запросом. Но с другой стороны, мы можем заранее создать некий файл, который будет содержать все эти 50 рецензий в готовом виде. Нам не нужно будет выбирать их из БД, форматировать согласно нашему шаблону и вставлять в нужное место в страничке. Мы просто сразу подключаем все это из заранее сформированного файла.

Суть кэширования сводится к созданию кэша из наиболее часто используемых и наиболее редко изменяемых данных. К примеру, как часто вам придется обновлять кэш ваших 50 рецензий? Ясно, что каждый раз, когда будут добавляться новые новости — чтоб наш кэш отображал актуальную информацию. А как часто будут добавляться новые новости? Предположим, примерно каждые 15 минут, т.е. до 100 раз за сутки. А какая посещаемость у этого сайта, как часто просматривают эти рецензии? На проекте, «движок» которого я разрабатывал, порядка 70 тыс. раз за сутки. Таким образом, вместо того, чтобы выполнять выборку из базы, форматирование и вставку этих рецензий по 70 тыс. раз на сутки, она выполняется обычно не более 100 раз, остальное — лишь простые инклуды полностью готовых данных.

Вы должны по возможности создавать окончательно завершенные данные для кэширования, которые достаточно просто подключить к страничке в процессе выполнения запроса, без надобности парсинга, дообработки, шаблонизирования и т.д.

Не забывайте о том, что кэш не обязательно хранить только в файлах и в нем не обязательно можно хранить только части нашей будущей HTML — странички. А особенно если он подвержен частым, систематическим обновлениям. Например, список данных о пользователях, находящихся онлайн, гораздо разумней держать в БД, в таблице типа Memory.

5) Буфер, сжатие, фронтенд http-сервер

Все очень просто. В процессе выполнения все данные, которые выводятся пользователю, тут же ему и отправляются. Грубо говоря, пока данные не будут забраны, продолжение выполнения кода не выполняется. Так что если в процессе работы ваш скрипт отправляет готовый HTML — код через функцию echo, например, или любым другим методом, то крипт передает данные «по кусочкам», каждый раз «подвисая». Намного грамотней выводить данные в буфер, примерно так:

php//инициализируем буферизацию
ob_start (); //выполнение кода скрипта
//... //завершаем буферизацию, извлекаем данные
$html = ob_get_contents ();
ob_end_clean ();
exit ( $html ); ?>

Включение динамического сжатия готовых HTML — страниц (

ob_start(`ob_gzhandler`);

) может сжать их в среднем на 20-60%, увеличивая скорость загрузки и снижая количество «висящих» процессов. У вас ограничение по трафику на хостинге? Тогда динамическое сжатие страниц принесет двойную выгоду.

Конечно, следует учитывать, что буферизация несколько повышает потребление памяти, а сжатие — нагрузку на процессор. Но эти жертвы зачастую с лихвой окупаются приростом скорости. Причем не только скоростью создания, но и скоростью загрузки странички.

В завершение, фронтенд http-сервер может вывести производительность ваших PHP скриптов на новый уровень. Дело в том, что даже с кэшированием, процессы, связанные с запросом пользователя, будут «висеть» до того, пока пользователь не примет все данные (либо пока не выйдет лимит отведенного на это времени). Суть фронтенд сервера в том, чтобы сразу же принимать данные, позволяя сразу выгружать отработавшие процессы. Он является неким связующим звеном между пользователем и достаточно «тяжелым» бэкенд сервером — где выполняются ваши PHP скрипты. Но благодаря своей «легкости», фронтенд сервер существенно снижает потребляемые ресурсы. Опять-таки, это очень обширная тема и мы будем рассматривать ее более детально, в ближайшем будущем.

6) Тотальный инклуд

Предположим, вы создали свой «движок» на PHP, соблюдали все предыдущие советы. В нем практически неизбежно будет множество различный инклудов: файлов конфигурации, функций, языков и т.д. Суть сводится к тому, что даже обычный инклуд того же файла с функциями будет требовать немало времени и памяти, даже если кроме функций в инклуде нет никакого исполняемого кода, и не одна из функций не вызывается.

Но ведь функции бывают самые разнообразные и специфические. Так что помещать весь список функций в один файл, и каждый раз подключать его — не лучший выход. Например, на сайте есть регистрация пользователей: для этого у вас может быть целый ряд специальных функций, которые используются только при регистрации. Так зачем выносить их в общий инклуд функций, который будет подключаться при каждом обращении к страничкам сайта?

Не пренебрегайте оптимизацией инклудов. Выносите то, что применяется не повсеместно в отдельные, специализированные инклуды. Еще один пример для закрепления. Мой любимый движок новостного сайта. Функции добавления новостей, комментариев, их контроля и пре-парсинга занимает около 1/3 кода общего количества функций. Но как часто они необходимы? В 1 из 100 запросах? Или в 1 из 200? Или еще реже? Так зачем же их каждый раз грузить? Это действительно может существенно снизить производительность ваших решений.

7) Лишняя функциолизация и ООП-тимизм

Функции необходимо применять только тогда, когда это действительно имеет смысл. Давайте вспомним базовую цель функций. Это не что иное, как вынос

часто используемых в пределах одного цикла работы программы

частей кода в отдельную, общую часть. В принципе, выносить код в «отдельную часть» имеет смысл и тогда, когда он выполняется по некому, относительно маловероятному событию. К примеру, прикрепление фото к посту на форуме. Вынос обработчика загрузки и обработки картинки в «отдельную часть» позитивно отразится на производительности, даже если он заключен в условие (факт загрузки картинки). При этом, если данная «отдельная часть» нам понадобится лишь один раз, лучше выполнить ее просто как код (инклуд), а не как функцию. Функции всегда требуют некоторых дополнительных ресурсов. То же самое касается и ООП-программирования в PHP. ООП-код потребляет несколько больше ресурсов, поэтому если вам не принципиально ООП-форматирование кода, лучше отказаться от него. Я говорю именно о ООП-форматировании, поскольку ООП-подход в PHP имеет мало общего с самим понятием ООП-программирования. Как и PHP с классическим пониманием языков программирования и их задач — о чем я писал в начале.

Вот вы и ознакомились с 7 основными принципами производительного кода на PHP. Это только — только самое начало. Впереди у нас еще много интересного, более конкретного материала по данной теме.

Изучил весь httpd.conf, перекопал кучу гайдов по highload (они старые и с сомнительными советами типа "отключить лишние модули"
Один из первых модулей, который стоит отключить у Apache"а, для скорости - это поддержку файлов.htaccess, сама эта поддержка производительности не добавляет, а наличие этих файлов - уж и подавно.
1) Это у всех VPS так называемый "мощный" процессор медленнее, чем на каком-то жалком хостинге, пусть и с VIP-тарифом?
Нет, возможно это у Вас, персонально, какой-то дрянной VPS-хостер, или того хуже, тариф аки "OpenVZ, мы не перепродаём проданные ресурсы... ну разве что раз 10, но больше не перепродаём"
2) Поможет ли в такой ситуации FastCGI?
FastCGI - это режим работы PHP, напрямую, на производительность в значительной степени он не влияет, более того, сама логика работы FCGI (если сравнивать Apache-FCGI и Apache-mod_php) будет медленнее, по тому как для взаимодействия FastCGI будет использоваться сокет ("обычный" или unix-сокет), что подразумевает сетевое взаимодействие, вместо непосредственной работы интерпретатора PHP "внутри" сервера. Думаю, Вам поможет несколько другое (постараюсь описать ниже).
3) Почему не популярны фишки типа eAccelerator (кеширование AST и т.п.)?
Понятия не имею, почему они не популярны и откуда у Вас такая статистика... Но, возможно, дело в том, что eAccelerator морально и физически устарел, и если верить например, вот такой банальной статье (нет, я не работаю с такой "шедевральной" CMS как "Битрикс", просто это первое упоминание про eAccelerator, которое пришло мне в голову) - с версиями PHP выше 5.3 не работает.
Я знаю, что многие из них заброшены, но это не причина, а следствие.
Не могу прокомментировать это, так как Вы не указали следствие - чего именно. Другими словами, я не совсем понимаю, что Вы хотели этим сказать.
4) Что еще может помочь?
Ну так, сходу, по памяти (варианты могут быть не связаны между собой):
1. Отказ от поддержки.htaccess в Apache или хотя бы сокращение их количества
2. Установка Nginx в качестве фронтального сервера, для отдачи статики
3. Полный отказ от Apache вообще и переход на Nginx+FCGI (только не подумайте, я очень люблю Apache за его гибкость в настройке и широкие возможности, другой вопрос, что мало кому эта гибкость фактически нужна и мало кто способен его грамотно, качественно и полноценно настроить... Nginx в этом плане будет куда попроще). Почему FCGI? По тому, что другой приемлемый способ взаимодействия Nginx"а с PHP мне не известен. Настройка FCGI-пула - обязательна.
4. OpCache - с версии 5.5 встроено "искаропки", к включению и настройке - настоятельно рекомендуется. Я не знаю, как обстоят дела с CMS и используете ли Вы CMS на сайте, но из моей практики, скорость работы PHP-фреймворков возрастает в среднем 8-20 раз.
5. HHVM , как альтернатива
6. Проверка:
а) Того, что дело действительно в PHP. В частности, стоит собрать все логи сервера, например, сколько длились запросы, в БД, их количество и так далее.
б) Проверка скорости работы дисковой подсистемы... Не буду "тыкать пальцем", но одно время я арендовал довольно большое кол-во VPS"ок у одного популярного хостера, и в какой-то момент, я заметил, что средняя скорость работы дисковой подсистемы - 1.4Кбайт/сек., при этом "отказы" (аки "невозможно записать блок") были примерно в 50% случаев... это продлилось не очень долго, но и через несколько месяцев, у этого же хостера, тарифы с "обычным HDD", почему-то обладали более быстрой дисковой подсистемой, нежели тарифы с "быстрыми SSD"... можно сделать выводы...
в) Проверить реальную скорость работы процессора, не редко она отличается от завяленной достаточно сильно.

P.S. Если Вы сформулируете вопрос(ы) более точно - я смогу дать более точные рекомендации, если конечно они Вам нужны:)

P.P.S. Есть вариант решения проблемы вообще "в лоб", самый наверное сложный и пожалуй самый производительный в ряде случаев. Это Varnish + тонкая настройка оного, позволяет выдавать большую часть страниц из кэша (оперативной памяти) за наносекунды, иногда позволяет обслуживать очень много тысяч запросов в минуту, при этом, это не просто кэширование кода или что-то подобное... это кэширование целиком страниц и/или ответов сервера. Среди прочего - позволяет "не трогать бэкенд вообще", т.е. при запросе страницы, может не быть ни обращений к БД, ни выполнения того же PHP (или любого другого) кода, на стороне сервера. Требует довольно тонкой настройки, не очень подходит для сайтов "на CMS", для сайтов на фреймворках - требует изначально корректного подхода к разработке и продумывания того, что и как будет/должно кэшироваться. При некорректном подходе - наиболее вероятный результат - работать будет, но не так быстро как хотелось бы, а часть сайта вообще может перестать нормально функционировать. Есть так же другие решения, но с учётом довольно общих формулировок вопроса - говорить о них довольно сложно.

Ах, да, забыл важную деталь... Почему "хостинги" используют Apache и не откажутся от него (совсем)? В большей степени по тому, что Apache позволяет делегировать часть настроек пользователю через.htaccess. При этом, для статики не редко стоит всё тот же Nginx, который, как Вы понимаете, подобным образом делегировать часть настроек пользователю не позволяет, в виду чего для этих задач не подходит и не "буксует" на этом (в отличии от Apache"а). В т.ч. и по этому, мы на 99% отказались от "хостингов" (по причине наличие Apache"а, и невозможности от него избавиться или самостоятельно настроить, и как следствие "тормозов" которые приходят вместе с подобным подходом).

Всем доброго времени суток.

  1. Если метод может быть статическим, объявляйте его статическим.
  2. echo быстрее, чем print.
  3. Передавайте в echo несколько параметров, вместо того, чтобы использовать конкатенацию строк.
  4. Устанавливайте максимальное количество проходов ваших циклов for до цикла, а не во время его выполнения.
  5. Удаляйте свои переменные для освобождения памяти, тем более, если это большие массивы.
  6. Остерегайтесь магических методов, таких как __set, __get, __autoload.
  7. require_once дорого обходится.
  8. Указывайте полные пути в конструкциях include/require, меньше времени будет тратится на поиск файла.
  9. Если вам необходимо определить время, когда скрипт был запущен, используйте $_SERVER[’REQUEST_TIME’] вместо time().
  10. Старайтесь использовать strncasecmp, strpbrk и stripos вместо регулярных выражений.
  11. str_replace быстрее, чем preg_replace, но strtr быстрее, чем str_replace.
  12. Если функция, как и функции замены строк, может принимать в аргументы как массивы, так и одиночные символы, и если ваш список аргументов не слишком длинный, подумайте над тем, чтобы записать несколько одинаковых выражений замены, проходя один символ за раз, вместо одной строки кода, которая принимает массив как аргумент поиска и замены
  13. Лучше выбирать утверждения при помощи конструкции else if, чем использовать несколько конструкций if.
  14. Подавление ошибок при использовании @ работает очень медленно.
  15. Используйте модуль Apache mod_deflate.
  16. Закрывайте свои соединения с БД, когда закончите работать с ними.
  17. $row["id"] в семь раз быстрее, чем $row.
  18. Сообщения об ошибках дорого стоят
  19. Не используйте функции внутри условия цикла for, например как здесь: for ($x=0; $x < count($array); $x). В данном случае функция count() будет вызываться с каждым проходом цикла.
  20. Инкремент локальной переменной в методе - самый быстрый. Почти также работает инкремент локальной переменной в функции.
  21. Инкремент глобальной переменной в два раза медленее, чем локальной.
  22. Инкремент свойства объекта (т.е. $this->prop++) в три раза медленнее, чем локальной переменной.
  23. Инкремент неопределённой переменной в 9-10 раз медленнее, чем заранее инициализированной.
  24. Объявление глобальной переменной, без использования её в функции, также замедляет работу (примерно на ту же величину, что и инкремент локальной переменной). Вероятно, PHP осуществляет проверку на существование переменной.
  25. Скорость вызов метода, судя по всему, не зависит от количества методов, определённых в классе. Я добавил 10 методов в тестовый класс (до и после тестового метода), без изменения производительности.
  26. Методы в производных классах работают быстрее, чем они же, определённые в базовом классе.
  27. Вызов функции с одним параметром и пустым телом функции в среднем равняется 7-8 инкрементам локальной переменной ($localvar++). Вызов похожего метода, разумеется, около 15 инкрементов.
  28. Ваши строки, определённые при помощи ", а не ", будут интерпретироваться чуть быстрее, т.к. PHP ищет переменные внутри "..", но не "...". Конечно, вы можете использовать это только тогда, когда в вашей строке нет переменных.
  29. Строки, разделённые запятыми, выводятся быстрее, чем строки, разделённые точкой. Примечание: это работает только с функцией echo, которая может принимать несколько строк в качестве аргументов.
  30. PHP-скрипты будут обрабатываться, как минимум, в 2-10 раз медленнее, чем статические HTML-страницы. Попробуйте использовать больше статических HTML-страниц и меньше скриптов.
  31. Ваши PHP-скрипты перекомпилируются каждый раз, если скрипты не кэшируются. Кэширование скриптов обычно увеличивает производительность на 25-100% за счёт удаления времени на компиляцию.
  32. Кэшируйте, насколько это возможно. Используйте memcached — это высокопроизводительная система кэширования объектов в памяти, которая повышает скорость динамических веб-приложений за счёт облегчения загрузки БД. Кэшированный микрокод полезен тем, что позволяет вашему скрипту не компилироваться снова для каждого запроса.
  33. При работе со строками, когда вам понадобится убедиться в том, что строка определённой длины, вы, разумеется, захотите использовать функцию strlen(). Эта функция работает очень быстро, ведь она не выполняет каких-либо вычислений, а лишь возвращает уже известную длину строки, доступную в zval-структуре (внутренняя структура C, используемая при работе с переменными в PHP). Однако потому, что strlen() — функция, она будет работать медленно за счёт вызова некоторых операций, таких как приведение строки в нижний регистр и поиска в хэш-таблице, только после которых будут выполнены основные действия функции. В некоторых случаях вы сможете ускорить свой код за счёт использования хитрости с isset().
    Было: if (strlen($foo) < 5) { echo «Foo is too short»; }
    Стало: if (!isset($foo{5})) { echo «Foo is too short»; }
    Вызов isset() быстрее, чем strlen() потому, что, в отличие от strlen(), isset() - не функция, а языковая конструкция. За счёт этого isset() не имеет практически никаких накладных расходов на определение длины строки.
  34. Инкремент или декремент переменной при помощи $i++ происходит немного медленнее, чем ++$i. Это особая специфика PHP, и не нужно таким образом модифицировать свой C и Java-код думая, что он будет работать быстрее, этого не произойдёт. ++$i будет быстрее в PHP потому, что вместо четырёх команд, как в случае с $i++, вам понадобится только три. Пост-инкремент обычно используется при создании временных переменных, которые затем увеличиваются. В то время, как пре-инкремент увеличивает значение оригинальной переменной. Это один из способов оптимизации PHP-кода в байт-код утилитой Zend Optimizer. Тем не менее, это хорошая идея, поскольку не все байткод-оптимизаторы оптимизируют это, также остаётся немало скриптов, работающих без оптимизации в байткод.
  35. Не всё должно быть ООП, часто это излишне, поскольку каждый метод и объект занимает много памяти.
  36. Не определяйте каждую структуру данных как класс, массивы бывают очень полезны
  37. Не слишком разбивайте методы. Думайте, что вы действительно будете повторно использовать.
  38. Вы всегда можете разбить код на методы позже, по необходимости.
  39. Используйте бесчисленное количество предопределённых функций.
  40. Если в вашем коде есть функции, выполняющиеся очень долго, обдумайте их написание на C в виде расширения
  41. Профилируйте свой код. Профилирование покажет вам, как много времени выполняются части вашего кода.
  42. mod_gzip — модуль Apache, который позволяет сжимать ваши данные на лету и может уменьшить объем передаваемых данных до 80%.

В наши дни, когда выделенный канал Интернета стал нормой, не особо стоит переживать о размере страничек. Однако, все таки на это стоит обращать внимание. Если Вы хотите уменьшить нагрузку на сервер, сократить количество HTTP запросов - для этого существует несколько техник. Этот урок расскажет о нескольких PHP трюках (кеширования, сжатие).

1. Объединение CSS файлов с помощью PHP .

Как веб разработчики, мы часто разделяем стили между несколькими таблицами стилей для более логичной структуры и легкого изменения в дальнейшем. Однако, это увеличивает количество запросов на сервер, что выливается в более медленную загрузку страниц. Используя PHP мы можем сразу убить двух зайцев: иметь несколько таблиц стилей, и использовать всего один запрос для обращения к ним всем.

Подготовка

Перед оптимизацией CSS файлов, нам необходимы стили для работы. Давайте создадим несколько файлов с стилями:

// main.css
// CSS для примера

body {
width: 800px;
margin: 0 auto;
color: grey;
}

#wrapper {
margin-top: 30px;
background: url(../images/cats.png);
}
// typography.css
// CSS для примера

body {
font-family: Arial, san-serif;
font-weight: bold;
}

strong {
font-size: 120%;
}
// forms.css
// CSS для примера

form {
position: relative;
top: 400px;
z-index: 99;
}

input {
height: 50px;
width: 400px;
}

Нам необходимо извлечь содержание всех файлов и соединить в определенном порядке. Значит наш скрипт должен получить имена таблиц стилей через УРЛ параметры, открыть эти файлы и соединить.

//Определяем переменные
$cssPath = "./css/";
if (isset($_GET["q"])) {
$files = $_GET["q"];
// Получаем массив файлов


foreach ($files as $key => $file) {
}

$cssData = "";
foreach ($files as $file) {

fclose($fileHandle);
}
}
// Скажи браузеру, что у нас CSS файл
if (isset($cssData)) {
echo $cssData;
} else {
}
?>

//Определяем переменные
// --- NOTE: PATHS NEED TRAILING SLASH ---
$cssPath = "./css/";
if (isset($_GET["q"])) {
$files = $_GET["q"];
// Got the array of files!

//Давайте убедимся, что в файловых именах нет страшных символов:) .
foreach ($files as $key => $file) {
$files[$key] = str_replace(array("/", "\\", "."), "", $file);
}

Этот код устанавливает путь к папке со стилями и проверяет на наличие файлов. Путь к папке должен иметь слеши вначале и в конце названия папки, так как в противном случае у нас будет масса ошибок. Далее мы проверяем каждое имя файла и удаляем точки и/или слеши.

$cssData = "";
foreach ($files as $file) {
$cssFileName = $cssPath . $file . ".css";
$fileHandle = fopen($cssFileName, "r");

$cssData .= "\n" . fread($fileHandle, filesize($cssFileName));
fclose($fileHandle);
}
}

Теперь нам необходимо создать общую таблицу стилей из файлов. Для этого мы запускаем цикл, который просматривает массив файлов, открывает каждый файл и соединяет в единый файл. "\n" добавляет новую строку для порядка и чистоты. Функция filesize() используется для того, чтобы узнать длину файла и передать fread().

// Скажи браузеру, что у нас CSS файл
header("Content-type: text/css");
if (isset($cssData)) {
echo $cssData;
echo "\n\n// Generated: " . date("r");
} else {
echo "// Files not avalable or no files specified.";
}
?>

Последняя часть кода передает все стили браузеру. Это значит, что нам необходимо сказать PHP, что мы передаем CSS информацию и что PHP должно проинформировать об этом браузер. Мы делаем это с помощью функции header(), и устанавливаем Content-type: text/css. Далее мы передаем CSS клиенту. Но перед этим проверяем наличие CSS стилей в файле. Если их нет, значит это означает, что названия CSS файлов не были переданы. Если же у нас есть файлы мы их передаем и добавляем сообщение о генерации.

Проверка

Теперь время проверить скрипт. Создаем папку и файлы в ней. Взгляните на структуру папки ниже. Если Вам необходимо другая структура, тогда не забудьте поменять пути.

Теперь загрузите все файлы в корень сайта и обратитесь к файлу index.php через браузер. Вас должна встретить фраза "Files not available or no files specified" (файлы не доступны или не указаны). Это означет, что мы не дали названия файлов, которые необходимо соединить. Однако, хорошая новость - что все работает без ошибок. Давайте попробуем напечатать в браузере "index.php?q=main". У Вас на экране появится содержание файла main.css. Если нам необходимо извлечь несколько файлов и объединить их, нам необходимо отправить следющий запрос "index.php?q=main&q=forms". Как Вы видите мы можем повторять "q=" сколько угодно раз. Вы можете объединить в один файл хоть 50 таблиц стилей.

Заключение

Данный метод может быть очень полезным, и иметь множество плюсов. У Вас может быть общая таблица стилей для всего сайта, и отдельная, например, для страниц с формами.

Небольшое предупреждение: если Вы поместите файл index.php в любую папку (не в папку с CSS), тогда Вам необходимо прописывать относительные пути к фоновым изображениям так, как будто index.php является Вашей таблицей стилей. Так будет думать браузер.

2. Удаление пустых строк из HTML и CSS

Многие из нас используют большое количество пустых строк при написании кода. Хорошие новости - пустые строки в PHP не передаются браузеру. Однако, передаются в HTML.

Пустые строки потребляют незначительное количество траффика. Если посещаемость сайтов большая, эта маленькая цифра может перерости в значительную. И тут нам на помощь придет PHP.

Подготовка

Ниже представлены коды для HTML и CSS файлов.

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">


Hey a Page!






Lorem Ipsum dol...



body {
min-height: 800px;
background: black;
font-size: 18px;
}
#wrapper {
width: 960px;
margin: 20px auto;
padding: 15px;
}
#header h1 {
text-indent: -99999em;
background: url(../images/header.png);

Display: block;
width: 100%;
height: 48px;
}
#mainbody {
font-weight: bold;
}

Преимуществом данного скрипта является то, что он может одновременно работать как с HTML, так и с CSS. Скрипт загружает файл, убирает все пустые строки, оставляет только 1 пробел, чтобы слова не соединялись в одно целое.

$fileDirectory = "";
$file = $_GET["q"];
$ext = $nameExplode;

//Проверка для хакеров
die("Hackers...!");
} else {
//Начнем


//Чудеса регулярных выражений

fclose($handle);
//Выводим данные
if ($ext == "css") {
header("Content-type: text/css");
}
echo $newData;
}
?>

Более подробно о каждой части кода

Мы получаем имя файла и проверяем его тип. Далее извлекаем все данные и убираем пробелы и пустые строки. Этот метод наиболее примитивный и не удалит все пустые строки, но он справится с большинством. И это всего несколько строк кода.

$fileDirectory = "";
$file = $_GET["q"];
$nameExplode = explode(".", $file);
$ext = $nameExplode;
$fileName = $fileDirectory . $file;

Этот код задает необходимые переменные. Снова, мы передаем все данные через "q". Тут также определяется папка для файлов.

If ($ext != "css" AND $ext != "htm" AND $ext != "html") {
//Проверка для хакеров
die("Hackers...!");
} else {

Тут мы проверяем действительно ли файл является CSS или HTML.

//Начнем
$handle = fopen($fileName, "r");
$fileData = fread($handle, filesize($fileName));
//Чудеса регулярных выражений
$newData = preg_replace("/\s+/", " ", $fileData);
fclose($handle);
//Выводим данные
if ($ext == "css") {

header("Content-type: text/css");
}
echo $newData;
}
?>

Этот код открывает и читает файл - и потом убирает по возможности все пустое пространство. Это достигается путем использования регулярных выражений. Находятся все пробелы, табуляции, пустые строки и заменяются на пробел.

Работает ли это?

Если Вы в браузере напечатаете "index.php?q=css.css", то увидите одну линию CSS. Значит все работает! Если откроете исходный код страницы, то увидите такую же картину. С помощью данного метода мы уменьшили 314 символьный CSS файл до 277 символов. HTML файл с 528 до 448 символов. Неплохо для 15 строк кода.

Заключение

Это отличный пример того, как мы можем сделать много используя несколько строк кода. Если Вы взгляните на исходный код таких сайтов как Гугл, то заметите, что там практически нет пустых строк.

3. Кеширование PHP скриптов.

Я покажу Вам как настроить кеширование Ваших скриптов используя пример выше. Цель - ускорить работу сайта. Суть очень проста - данные не будут генерироваться каждый раз при обращении к сайту. Они будут храниться в кеше.

Для добавления кеширования, нам необходимо добавить три вещи к нашему скрипту. Во-первых, нам необходимо собрать все данные в скрипт и сгенерировать файл уникальный для этого набора введенных данных. Во-вторых, нам необходимо найти файл с кешем и проверить насколько он "свеж". В-третьих, нам необходимо использовать кешированную копию или сгенерировать новый файл кеша для использования в дальнейшем.

Подробнее

$fileDirectory = "";
$file = $_GET["q"];
$nameExplode = explode(".", $file);
$ext = $nameExplode;
$fileName = $fileDirectory . $file;
//-- WE HAVE ENOUGH DATA TO GENERATE A CACHE FILE NAME HERE --
if ($ext != "css" AND $ext != "htm" AND $ext != "html") {
//Check for evil people...
die("Hackers...!");
} else {

//-- WE CAN INTERCEPT AND CHECH FOR THE CACHED VERSION HERE --

//Lets get down to business
$handle = fopen($fileName, "r");
$fileData = fread($handle, filesize($fileName));
//Now for some regex wizardry!
$newData = preg_replace("/\s+/", " ", $fileData);

Fclose($handle);
//Time to output the data.

//-- NOW WE CAN STORE THE NEW DATA IF REQUIRED AND OUTPUT THE DATA --

If ($ext == "css") {
header("Content-type: text/css");
}
echo $newData;
}
?>

$fileDirectory = "";
$file = $_GET["q"];
$nameExplode = explode(".", $file);
$ext = $nameExplode;
$fileName = $fileDirectory . $file;
$cacheName = "./cache/" . $nameExplode . $nameExplode . ".tmp";
if ($ext != "css" AND $ext != "htm" AND $ext != "html") {
//Хакеры
print_r($ext);
die("Hackers...!");
} else {
if (file_exists($cacheName) AND filemtime($cacheName) > (time() - 86400)) {


fclose($cacheHandle);
$isCached = TRUE;
} else {
//Начнем
$handle = fopen($fileName, "r");
$fileData = fread($handle, filesize($fileName));
//Чудеса регулярных выражений
$newData = preg_replace("/\s+/", " ", $fileData);
fclose($handle);
//Кешируем


fclose($cacheHandle);
$isCached = FALSE;
}
//Выводим данные
if ($ext == "css") {
header("Content-type: text/css");
if ($isCached) {

}
} else {
if ($isCached) {
echo "";

}
}
echo $newData;

Объяснение

В данном скрипте была добавлена функция обновления кеша каждые 24 часа. Это удобно. Допустим, если Вы поменяли что-либо на сайте - можете подождать 24 часа или же очистить кеш.

$cacheName = "./cache/" . $nameExplode . $nameExplode . ".tmp";

Этот отрезок кода достает название файлов и их расширения, склеивает их вместе и добавляет в кеш с правильным расширением ".tmp".

If (file_exists($cacheName) AND filemtime($cacheName) > (time() - 86400)) {
$cacheHandle = fopen($cacheName, "r");
$newData = fread($cacheHandle, filesize($cacheName));
fclose($cacheHandle);
$isCached = TRUE;
} else {

Тут мы проверяем наличие сохраненного кеша и был ли он создан в течении последних 24 часов (значение в секундах - можно поменять на любое другое). Если оба условия выполняются, открываем файл и извлекаем содержание, чтобы заменить им результат работы скрипта. Мы также устанавливаем $isCached true для вывода дополнительных сообщений в конце.

//Lets cache!
$cacheHandle = fopen($cacheName, "w+");
fwrite($cacheHandle, $newData);
fclose($cacheHandle);
$isCache = FALSE;
}

Кешируем результат скрипта для использования при дальнейших обращениях. Мы просто открываем файл в режиме записи, сбрасываем туда информацию и закрываем.

//Time to output the data.
if ($ext == "css") {
header("Content-type: text/css");
if ($isCached) {
echo "// Retrieved from cache file. \n";
}
} else {
if ($isCached) {
echo "";
}
}

Эта часть скрипта была немного модифицирована, чтобы мы могли увидеть результат работы. Если содержание файла было извлечено из кеша, мы можем добавить сообщение об этом.

Пробуем

Если мы воспользуемся скриптом вновь, мы не увидим изменений до тех пор, пока не обновим страницу. Снизу увидим надпись, что файл взят из кеша.

Заключение

Умение быстро добавить простое кеширование к любому скрипту означает, что вы идете в верном направлении. Скрипт с кешированием существенно снизит нагрузку на любой сервер.

Подводим Итоги

В данном уроке я Вам показал несколько удобных и простых путей ускорения Вашего сайта с помощью PHP.

От автора: каждый уважающий себя разработчик переживает за «судьбу» своего кода. Старается сделать приложение как можно удобнее, быстрее и повысить его отказоустойчивость. Но не всегда оптимизация PHP позволит вам достичь этих высот.

Не лечи руку, если хромой на ногу!

Пардон за народный ирландский афоризм! Но он в самое «яблочко» отражает всю суть проблемы. Чаще всего оптимизация кода не позволит вам повысить быстродействие созданного скрипта или ресурса. А в случае с все крайне усложняется из-за большого количества факторов, повлиять на которые вы (как разработчик) просто не в силах.

Что касается неподвластных явлений, то я имею в виду скорость интернет-соединения, загруженность сервера, настройки ОС на клиентской машине, мощность железа ПК пользователя. На все эти составляющие вы не сможете повлиять. И в итоге получается, что проведенная оптимизация PHP кода не даст полноценного результата.

Что остается под властью веб-разработчика:

Настройки сервера – ограниченно. Настройка параметров через файл конфигурации Apache httpd.conf позволяет задать количество дочерних процессов, таймаут соединения через сокет, объем буфера для вывода при соединении TCP/IP, время простоя и другие.

Настройки ядра языка – через параметры, прописанные в файле php.ini. Позволяет задать значения буферизации, изменить максимальное время выполнения скриптов, обработку ошибок, управление логами и другие настройки.

С помощью PHP оптимизации изображений – об этом позже. Оптимизация программного кода – позволяет «сэкономить» ресурсы и повысить быстродействие.

Например, нужно знать, что echo работает быстрее, чем print. Вывод сообщений об ошибках после отладки лучше выключать для экономии ресурсов. Вместо конкатенации строк используйте echo. Объекты и методы классов () съедают много памяти.

Работа с изображениями

Я не сторонник обработки изображений на стороне сервера. Это также ведет к трате драгоценных ресурсов, которых на хостинге всегда мало. Получается, что экономя на одном, мы понапрасну расходуем другие «запасы».

Более оптимальным является вариант загрузки изображений на сторонний сервис, откуда они уже в оптимизированном виде подгружаются в браузер пользователя по заданному адресу. В Сети таких сервисов множество. Хочу назвать только несколько из них: kraken.io, TinyPNG

Как видите, знание поисковой оптимизации на PHP для профессиональных разработчиков тоже являет немаловажным.

Кроме этого обладает собственным встроенным инструментарием для «облегчения» изображений. Например, функция imagecopyresampled (). Она уменьшает вес контента за счет ресамплинга и изменения размеров рисунка. Пример использования:

header ("Content-Type: image/jpeg" ) ;

$file = "sample.jpg" ;

$img_obrabot = imagecreatetruecolor (200 , 100 ) ;

$img_orig = imagecreatefromjpeg ($file ) ;

imagecopyresampled ($img_obrabot , $img_orig , 0 , 0 , 0 , 0 , 200 , 100 , 541 , 286 ) ;

imagejpeg ($img_obrabot ) ;

Что можно еще

Также не забывайте о применении оптимизации клиентской стороны с помощью PHP. В какой-то мере сервер может влиять на клиентский браузер через Cache-Control, а также атрибуты этого заголовка: post-check, max-age и другие.

Кроме этого управлять состоянием кэша на клиентской машине позволяют заголовки Last-Modified и ETag. Для изменения каждого файла они устанавливают уникальный идентификатор. Благодаря чему сервер не пересылает ресурсы заново, а лишь ответы 304 статусом.

В статье мы не поднимали вопроса оптимизации с помощью PHP FPM. Но для его рассмотрения потребуется отдельная статья. А на сегодня все. До следующей встречи!