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

  • Как оптимизировать сайт и ускорить его работу?
  • С какой скоростью будет и может работать сайт, в соответствии с теми технологиями на которых он будет запущен?
  • Какие технологии следует использовать настраивая сервер или VPS?

Типичная проблема:
В какой-то момент сайт начинает открываться и работать слишком медленно. Бывает, что хостинговая компания блокирует сайт за превышение нагрузки или перерасход ресурсов. Что же делать в такой ситуации?

Может быть, сайт стал пользоваться слишком высокой посещаемостью или был установлен какой-то ресурсоёмкий модуль, совершается атака или сайт заражен вирусом. Так или иначе, но у всех этих случаев есть кое-что общее и это проблема всех сайтов на всех хостингах.

И если говорить о серверах для PHP, то такой проблемой является способ исполнения php кода, ровно как и другие значимые настройки окружения на сервере.
Не зависимо от того, есть ли проблема в вашем коде или её нет, высокая у вас посещаемость или нет, от настроек сервера зависит очень многое. Что бы все сказанное не звучало пустыми словами и была написана эта статья.

В этом обзоре я протестирую только что установленный сайт на одном из самых распространённых движков управления контентом Drupal 7.33 .

Для теста выбрана лишь одна составляющая php-хостинга. Мы будем тестировать web-серверы Nginx и Apache2 , модули mod_php и php-fpm , версии php php53 и php56 , посмотрим, как влияют оптимизаторы apc и opcache на скорость работы сайта.


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

Дано:
  • Операционная система Centos 6.7
  • Сервер баз данных: MariaDB 10.21
  • Все сессии сайтов хранятся в memcache, чтобы убрать влияние скорости установки сессии на скорость работы сайта.
  • На всех тестах в качестве frontend выступает web-server nginx 1.93. В случае с Apache2, Nginx выступает в качестве балансировщика, а также для отдачи статики. В конфигурациях без использования Apache2 - непосредственным web-сервером является Nginx
  • Конфигурация Nginx и MariaDB содержат множество оптимизаций, направленных на достижение максимальной производительности, но для всех участников теста эти настройки одинаковые и поэтому их влиянием следует пренебречь
  • Параметры opcache и apc взяты из рекомендаций Bitrix, так как они оптимальны и универсальны для большинства сайтов
Как будем тестировать?

В локальной сети есть сервер zabbix и его задачи каждую минуту:

  • Открывать главную страницу испытуемого сайта, дожидаться определенного содержимого на странице, убеждаться, что ответ от сервера - код 200.
  • Следующим шагом идет авторизация в админку сайта, это происходит отправкой соответсвующего POST запроса. Сверка текста и кода ответа на странице с заложенным эталоном. Этот шаг касается почти всех подсистем web-сервера, и во многом его скорость зависит от скорости взаимодействия с базой данных
  • Последним шагом является выход из админки сайта, сверка кода ответа и текста на странице выхода
  • По итогам каждого шага, zabbix будет скрупулезно замерять и записывать скорость рендеринга php-кода в html понятный браузеру и демонстрировать нам графики полученных результатов
  • Для каждого испытуемого будут записываться значения в течение одного часа и в качестве результата будет выступать средние значения за этот час
  • Тестирование будет происходить внутри локальной сети, так что влияние на результат скорости интернет-соединения исключено
  • Для удобства восприятия, все результаты показываю в порядке возрастания. Т.е. самый первый результат - это самый медленный. Все конфигурации были вынесены под условный номер, это позволит лучше ориентироваться в результатах
  • Верхние графики - скорость генерации кода, чем выше значение, тем лучше. Нижние графики - время ответа сервера и чем ниже значение, тем лучше
  • Тестируемые сайты живут своей жизнью, в них происходят регулярные операции с базами данных и выполняются задания по расписанию, именно поэтому кривая на графиках может иметь взлеты и падения

Тестирование:

1. Nginx + php-fpm56 без оптимизатора opcache

По архитектуре - это один из самых передовых вариантов. По производительности - наибольшее разочарование.

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

2. Apache2 + mod_php53 без оптимизатора apc

Cамый типичный для хостингов вариант. 90% популярных хостинг-провайдеров используют этот вариант. Хоть php53 давно не поддерживается разработчиками, но в интернете очень много сайтов, до сих пор работающих на этой версии.

Такой вариант не только очень медленный, но и быстро падает под небольшой нагрузкой из-за нехватки рабочих процессов Apache2, либо из-за нехватки оперативной памяти на сервере.

3. Балансировка и статика через Nginx, динамическая часть Apache2 + mod_php56 без оптимизатора opcache

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

К сожалению, далеко не все сайты могут работать полноценно c этой версией. Почти каждая новая версия PHP перестает поддерживать некоторые устаревшие и «небезопасные» функции, нарушая работу «старого» кода.
Сам по себе php56 без оптимизатора довольно медленный, а mod_php склонен падать и занимать всю память на сервере под нагрузкой.

4. Nginx + php-fpm53 без оптимизатора apc

Достаточно передовая конфигурация, для тех кто не желает иметь проблемы из-за ошибок с оптимизатором кода. При этом используется «совместимая» версия интерпретатора PHP, а также из связки убирается ресурсоемкий Apache2.

5. Балансировка и статика через Nginx, динамическая часть Apache2 + mod_php53 + apc

Еще одна распространенная вариация. Очень многие хостинги применяют именно её, при этом либо используют по умолчанию, либо дают возможность включать оптимизатор в своих панелях управления.
Обычно Apache2 оставляют для работы.htaccess-правил, таких как преобразование ссылок и ЧПУ.

Получаем прирост скорости в 3,5 раза, по сравнению с вариантом без использования оптимизатора.
Сам по себе Apache (при использовании его собственного модуля mod_php) расходует для свой работы гораздо больше ресурсов, чем вариант с php-fpm. Apache2 склонен падать, если в одном из его модулей случается сбой или заполнять собой всю оперативную память сервера.

6. Nginx + php-fpm53 + apc

Отличный вариант для сайтов на старых движках, не требующих сложных.htaccess

Именно такой вариант я использую, когда необходимо поднять устаревший сайт, добиться от него удовлетворительной скорости и надежной работы при высоких нагрузках.

7. Балансировка и статика через Nginx, динамическая часть Apache2 + php-fpm53 + apc

Вариант для устаревших сайтов со сложными.htaccess. Например - старые инсталляции Bitrix.

Это идеальный вариант для устаревших сайтов. Данная конфигурация устойчива к высоким нагрузкам, совместима и достаточно производительна.
Отлично подходит, когда нужны правила.htaccess и дополнительные модули Apache2.
Из недостатков - устаревшая и не обновляемая версия php, но если нет выбора - это самый лучший вариант. Отлично подходит для старой версий Bitrix, Joomla и других распространенных CMS не самых свежих версий.

8. Балансировка и статика через Nginx, динамическая часть Apache2 + mod_php56 + opcache

Достаточно производительная, но ресурсоёмкая конфигурация со всеми недостатками mod_php.

Достаточно быстро, но под нагрузкой у сервера может закончится память, а скорость существенно упадет.

9. Nginx + php-fpm56 + opcache

Самый производительный вариант.

Это самый лучший вариант для всех современных сайтов. Хорошо держит нагрузку, показывает самый лучший результат с точки зрения производительности. Именно такой вариант я использую, когда стоит задача оптимизировать производительность сайта и увеличить скорость его работы.
Единственный недостаток - это то, что мы не сможем использовать.htaccess и все правила mod_rewrite нужно переписать на синтаксис Nginx.
Также не будут работать модули Apache2. Если таковые используются, то этот вариант не подойдёт.

10. Балансировка и статика через Nginx, динамическая часть Apache2 + php-fpm56+ opcache

Самый лучший вариант для сайтов, где нужен.htaccess. Идеально подходит для свежих версий Bitrix.

Хорошо держит нагрузку за счет php-fpm. Активно использую этот вариант для большинства сайтов.

Главная страница тестового сайта
Номер конфигурации Архитектура Средний отклик мс.
1 77,04 103,6
2 78,79 103,98
3 78,85 102,38
4 81,55 97,88
5 Apache2 + mod_php53 + apc 303,37 29,36
6. Nginx + php-fpm53 + apc 312,33 24,73
7. Apache2 + php-fpm53 + apc 339,63 23,32
8. 484,96 16,91
9. Nginx + php-fpm56 + opcache 546,34 14,08
10. Apache2 + php-fpm56+ opcache 571,14 13,78
Авторизация в админке тестового сайта
Номер конфигурации Архитектура Средняя скорость загрузки кб. Средний отклик мс.
1 Nginx + php-fpm56 без оптимизатора opcache 67,51 239,01
2 Apache2 + mod_php53 без оптимизатора apc 64,61 257,51
3 Apache2 + mod_php56 без оптимизатора opcache 66,75 242,42
4 Nginx + php-fpm53 без оптимизатора apc 68.79 233.15
5 Apache2 + mod_php53 + apc 173,81 94,26
6. Nginx + php-fpm53 + apc 173,3 91,3
7. Apache2 + php-fpm53 + apc 182,1 90,5
8. Apache2 + mod_php56 + opcache 218,35 77,55
9. Nginx + php-fpm56 + opcache 252,83 62,25
10. Apache2 + php-fpm56+ opcache 262,8 60,85
Выход из админки тестового сайта
Номер конфигурации Архитектура Средняя скорость загрузки кб. Средний отклик мс.
1 Nginx + php-fpm56 без оптимизатора opcache 41,01 184,49
2 Apache2 + mod_php53 без оптимизатора apc 42,42 188,97
3 Apache2 + mod_php56 без оптимизатора opcache 42,06 188,37
4 Nginx + php-fpm53 без оптимизатора apc 45,48 169,15
5 Apache2 + mod_php53 + apc 190,1 41,87
6. Nginx + php-fpm53 + apc 185,92 41,24
7. Apache2 + php-fpm53 + apc 202,78 39,21
8. Apache2 + mod_php56 + opcache 315,56 26,23
9. Nginx + php-fpm56 + opcache 373,19 20,43
10. Apache2 + php-fpm56+ opcache 381,21 20,57

В качестве итогов:

  • В реальной жизни, все варианты с Apache2 могут быть медленней, так как в своих тестах я умышленно передал отдачу статики Nginx. Это сделано, чтобы исключить влияние скорости отдачи статики на результаты замера скорости работы интерпретатора PHP. Одной из наиболее слабой стороной Apache2 и при этом сильной Nginx - является скорость отдачи статики. Особенно, это заметно на высоких нагрузках. Кроме того, Nginx менее подвержен атаке «медленных соединений»
  • mod_php очень быстро занимает всю доступную память сервера и теряет производительность на нагрузках
  • php-fpm расходует память значительно эффективнее, безопаснее и гибче в настройках. В ряде случаев он быстрее и без высоких нагрузок.
  • Тест имеет узкую специфику, тут мы увидели особенности работы движка Drupal, другие могут вести себя иначе, но общая тенденция будет такой же.

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

Если у вас возникнут вопросы, трудности или потребуется совет:
Мои контакты в


Как без особых усилий заставить PHP -код работать на порядок быстрее ? Перед тем как задаваться вопросами кеширования и масштабирования стоит попробовать оптимизировать код. Есть ряд несложных правил:

Еще про оптимизацию....

При вставке кусков PHP-кода в HTML страницы всегда используйте полные открывающие и закрывающие скобки ! Это обезопасит Вас от вариаций настройки php.ini short_open_tag на разных серверах и возможно сэкономит много времени при переносе или загрузке проектов на разные сервера.

Старайтесь использовать функцию вывода echo вместо printf и sprintf там где возможно. Нет надобности использовать эти функции, так как они выполняются медленней потому, что созданы для интерпретации и вывода строки с ее обработкой, подстановкой значений, в отформатированном виде. О чем и говорит буква f в конце названия этих 2-х функций.

Sprintf("мама"); printf("папа");

Echo "мама"; echo "папа";

По тем же причинам используйте одинарные кавычки там где это возможно и пользуйтесь оператором "." для склейки строк, вместо прямой подстановки переменный в строку, заключенную в кавычки.

Лучший вариант(самый быстрый)

Echo "Вес равен: ".$weight;

Худший вариант(медленный):

Echo "Вес равен: $weight";

Если Вам нужно проверить не равно ли возвращенное значение функции нулю (а функция сама по себе возвращает только положительные или только отрицательные значения), то лучше использовать оператор сравнения. Он выполняется быстрей, нежели конкретное сравнение значений.

$i = 0; if ($i != 0) { //Не равно } else { //Равно }

$i = 0; if ($i > 0) { //Не равно } else { //Равно } Нужно также учитывать, что если строка принимает только пустое значения, либо пользовательские строковые данные, то вместо сравнения строки со строкой, для выявления ее пустоты, так же можно использовать сравнение с нулем, которые выполнится быстрее.

Для проверки строки на пустоту используйте функцию trim($str) ; Она не только проверит заполнена ли строка, но также обрежет несущественные символы - пробелы (табуляции, white-spaces) и вернет положительное значение, в случае если в строке ей действительно какие то значимые символы.

If ($str != "") { //обработка строки }

If (trim($str)) { //обработка строки }

Для получения данных из форм методом Get и Post лучше использовать следующий минимальный набор самописных функций:

GetParam ($array, $value, $default = "") { return (isset($array[$value])) ? $array[$value] : $default; } GetParamSafe ($array, $value, $default = "") { return (isset($array[$value])) ? addslashes($array[$value]) : $default; }

Функция GetParam($_POST, "myvar", "empty") к примеру коректно получит данные из $_POST["myvar"], и в случае если $_POST переменная не существует вернет значение по умолчанию, без всяких Waring и Notice. Фунция GetParamSafe($_POST, "myvar", "empty") делает ту же операцию, только возвращает экранированную переменную. Для защиты от SQL инъекций к примеру. А данная конструкция позволяет получить целочисленное число из $_POST.

Intval(GetParam($_POST, "myvar", "empty")):

В случае если в массиве $_POST лежало совсем не число функия вернет 0;

Для простого сравнения строк не используйте preg_match() или preg_match_all() . Используйте strstr() и strpos() .

При получении строк из базы данных (MySQL к примеру) старайтесь использовать функцию mysql_fetch_object . К примеру при изменении кода запроса с

$query = "SELECT field7, field3 FROM mytable WHERE id = 5" на $query = "SELECT * FROM mytable WHERE id = 5" код вывода строки полученной из этих запросов $row = mysql_fetch_array(mysql_query($query)); echo $row."-->".$row; //перестанет работать, в то время, как $row = mysql_fetch_object(mysql_query($query)); echo $row->field7."-->".$row->field3; // останется работоспособным.

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

При формировании больших запросов вставки данных в БД через insert все строчки старайтесь поместить в один-три insert"а. Выполнение каждой строчки отдельно не только загрузит сервер БД, но и задержит работу Вашего скрипта.

В случае если необходимо в разных местах (разных классах) одной системы использовать одни и те же сложно вычисляемые данные (например которые достаются из БД через запрос с последющей обработкой строк), старайтесь их вычислять единожды, хранить глобально для всей системы и передавать в класс(скрипт) один раз, непосредственно при создании класса (подключении скрипта)

При больших нагрузках на Web-сервер задумайтесь над использованием стандартных решений для включения кэша(кэш-технологии). Например бесплатный PHP класс JCache_Lite_Function.

При проектировании/разработке больших систем отдавайте предпочтение Объектно-Ориентированному программированию с использование шаблонов проектирования. Наиболее частые шаблоны: MVC, PageController, BodyHandler, Fabric...


Читать дальше:

Существует ряд правил, которые стоит соблюдать, чтобы увеличить скорость работы приложений на PHP. Правила простые и не потребуют значительных изменений в существующих приложениях.

Fastcgi

FastCGI — это один из вариантов подключения PHP к Web серверу. Лучше всего использовать в связке с Nginx. PHP-fpm (Fastcgi контейнер для PHP) и Nginx по умолчанию поддерживают совместную работу и очень легко настраиваются .

OpCache


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

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

В версии PHP5.5+ этот модуль поставляется в стандартной сборке. В предыдущих версиях модуль нужно устанавливать самостоятельно. Проверить наличие можно так: php -i | grep opcache

# Пустой вывод будет означать, что модуля нет

Если версия слишком ранняя, лучше использовать APC: apt-cache search php-apc

# Это альтернатива opCache, но делает то же самое

Кэширование

Часто код просто медленный. Например:

  • обращения к внешним API
  • тяжелые выборки из баз данных
  • обработка больших файлов
session.save_handler = memcache session.save_path = "tcp://localhost:11211 "

# localhost:11211 это стандартный хост и порт Memcache

Кроме этого, такая схема хранения позволит масштабироваться на несколько серверов.

Оптимизация кода

ООП

Помните! ООП — это всегда медленно. Объекты нужно создавать, где-то хранить и уничтожать. Не используйте объекты, если они не нужны. Например, тут:

set_title($_GET["title"]); $post->set_description($_GET["description"]); $post->save();

# $posts = список объектов Post, полученных каким-то образом foreach ($posts as $post) { echo $post->title . "
"; }

# Используем список объектов только для того, чтобы вывести свойство

В этих примерах использование ООП не имеет особого смысла. Зато расходует ресурсы. Старайтесь использовать массивы, когда объекты не нужны:

$_GET["title"], "description" => $_GET["description"]]);

# Избежали создания объекта, функция просто сохраняет данные из массива в базу

"; }

# Намного лучше — сделать простую выборку и вывести нужные данные из массива

Мелочи

При работе с файлами используйте абсолютные пути. Тогда не будут происходить лишние операции поиска файла:

include "/var/www/file.php"; file_get_contents("/var/www/dir/data.txt");

Константы классов работают эффективнее, чем define:

class posts { const PER_PAGE = 10; ... }

Не используйте функции в условии for, т.к. они будут повторяться на каждой итерации цикла:

$max = mysql::get_col("SELECT count(*) FROM posts"); for ($i = 0; $i < $max; $i++) { ... }

В качестве ключей массивов всегда указывайте строки с кавычками :

$post["title"] = "Первый пост";

Используйте встроенные функции работы со строками вместо регулярных выражений, если это возможно.

strpos($post["title"], "хорошо");

Используйте строки с одинарными кавычками:

$post["title"] = "В этом случае нет дополнительной обработки переменных"

PHP cron-скрипты

Когда PHP используется для разработки скрипта, который будет выполняться по крону, следует избегать использования глобальных переменных. Например:

(.+?)<\/title/", $rss, $matches ); }

(.+?)<\/title/", $rss); if ($has_something) $updates = time(); $rss = file_get_contents("http://othersource.com/rss"); $has_something = preg_match("/title>(.+?)<\/title/", $rss); if ($has_something) $updates = time(); }

Теперь переменная $updates будет расти до максимального предела. Когда будет достигнут лимит по памяти, скрипт будет остановлен. Уследить за всеми переменными довольно тяжело, поэтому лучше использовать функции. Все переменные, созданные внутри функции будут удаляться после ее завершения:

process(); function process() { $rss = file_get_contents("http://somesite.com/rss"); $has_something = preg_match("/title>(.+?)<\/title/", $rss); if ($has_something) $updates = time(); $rss = file_get_contents("http://othersource.com/rss"); $has_something = preg_match("/title>(.+?)<\/title/", $rss); if ($has_something) $updates = time(); }

Самое важное

  • Обязательно используйте opCache для PHP. Это бесплатно экономит ресурсы.
  • Используйте FastCGI (лучше всего Nginx + PHP-fpm).
  • Функции в крон задачах помогут избежать утечек памяти.
  • Кэширование медленных участков кода часто самое простое решение для ускорения работы.
  • Помните о

Тема данной статьи - тот факт, что применение FastCGI в PHP не ускоряет время загрузки PHP-кода по сравнению, например, с mod_php.

Большинство традиционных языков Web-программирования (Perl, Ruby, Python и т. д.) поддерживают написание скриптов, работающих в так называемом «FastCGI-режиме». Более того, Ruby on Rails, к примеру, вообще невозможно использовать в CGI-режиме, т.к. он тратит на подключение всех своих многочисленных библиотек десятки секунд.

Ниже я расскажу о методе, который позволяет в ряде случаев ускорить загрузку объемного PHP-кода более чем в 20 раз, не получая при этом побочных эффектов и значительных неудобств. Но вначале давайте поговорим об основах…

Что такое FastCGI?

Вначале поговорим, что называется, о «классическом» FastCGI, который применяют в Си, Perl, Ruby и т. д. В PHP же FastCGI имеет свои особенности, мы их рассмотрим чуть позже. Сейчас речь идет о не-PHP.

FastCGI работает следующим образом: скрипт загружается в память, запускает некоторый тяжелый код инициализации (например, подключает объемистые библиотеки), а затем входит в цикл обработки входящих HTTP-запросов. Один и тот же процесс-скрипт обрабатывает несколько различных запросов один за другим, что отличается от работы в CGI-режиме, когда на каждый запрос создается отдельный процесс, «умирающий» после окончания обработки. Обычно, обработав N запросов, FastCGI-скрипт завершается, чтобы сервер перезапустил его вновь уже в «чистой песочнице».

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

Старые скрипты, написанные с расчетом на CGI, приходится дорабатывать, чтобы они могли работать в FastCGI-окружении (касается использования FastCGI в Си, Perl и т. д.; на PHP дорабатывать не нужно, но у этого свои недостатки, см. ниже). Действительно, ведь раньше скрипт стартовал каждый раз «с чистого листа», а теперь ему приходится иметь дело с тем «мусором», который остался от предыдущего запроса. Если раньше CGI-скрипт на Perl выглядел как

use SomeHeavyLibrary; print "Hello, world!\n";

то после переделки под FastCGI он становится похож на что-то типа

use SomeHeavyLibrary; while ($request = get_fastcgi_request()) { print "Hello, world!\n"; }

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

FastCGI имеет значительный недостаток: новый запрос начинает обрабатываться не в «чистом» окружении, а в том, которое осталось «с прошлого раза». Если в скрипте имеются утечки памяти, они постепенно накапливаются до тех пор, пока не произойдет крах. Это же касается и ресурсов, которые забыли освободить (открытые файлы, соединения с БД и т. д.). Есть и еще один недостаток: если код скрипта изменился, то приходится как-то сообщать об этом FastCGI-серверу, чтобы он «убил» все свои процессы и начал заново.

Собственно, техника «иницилизируйся один раз, обрабатывай много запросов» работает не только в FastCGI. Любой сервер, написанный на том же самом языке, что и скрипт, под ним запущенный, использует ее неявно. Например, сервер Mongrel написан целиком на Ruby как раз для того, чтобы под ним быстро запускать Ruby On Rails. Сервер Apache Tomcat, написанный на Java, быстро выполняет Java-сервлеты, т.к. не требует их повторной инициализации. Технология mod_perl также основана на том, что Perl-код не выгружается между запросами, а остается в памяти. Конечно, все эти серверы имеют те же самые проблемы с непредсказуемостью, утечками памяти и сложностью перезапуска, что и FastCGI-приложение.

Почему FastCGI не ускоряет PHP

Вероятно, вы слышали, что PHP тоже можно запускать в режиме FastCGI, и что так делают многие нагруженные проекты (Мамба, некоторые проекты Mail.Ru и т. д.). Это якобы дает «существенный прирост» производительности, потому что (согласно слухам) FastCGI экономит время инициализации скрипта и подключения библиотек.

Не верьте! В действительности поддержка FastCGI в PHP имеет чисто номинальный характер. Точнее, она не дает преимуществ в том смысле, в котором ей привыкли оперировать для уменьшения времени инициализации скрипта. Конечно, вы можете запустить PHP FastCGI-сервер и даже заставить nginx или lighttpd работать с ним напрямую, однако прирост скорости на загрузку кода, который вы от этого получите, будет нулевым. Тяжелые PHP-библиотеки (например, Zend Framework) как загружались долго в mod_php- или CGI-режимах, так и будут продолжать загружаться долго в режиме FastCGI.

Собственно, это неудивительно: ведь чтобы запустить любой PHP-скрипт в FastCGI-режиме, его не приходится дорабатывать. Ни строчки измененного кода! Когда я впервые решил поэкспериментировать с FastCGI в PHP, я потратил несколько часов времени на поиски в Интернете информации о том, как именно следует модифицировать PHP-код, чтобы оптимально запускать его в режиме FastCGI. Я проштудировал всю документацию PHP и несколько десятков форумов PHP-разработчиков, даже просмотрел исходный код PHP, но так и не нашел ни единой рекомендации. Имея прежний опыт работы с FastCGI в Perl и Си, я был несказанно удивлен. Однако все встало на свои места, когда выяснилось, что изменять код не нужно и, хотя в рамках одного FastCGI-процесса обрабатываются несколько соединений, PHP-интерпретатор каждый раз инициализируется заново (в отличие от «классического» FastCGI). Более того, похоже, большинство PHP-разработчиков, радостно использующих FastCGI+PHP, даже не подозревают о том, что оно должно работать как-то по-другому…

eAccelerator: ускорение повторной загрузки PHP-кода

Каждый раз, когда PHP-скрипт получает управление, PHP компилирует (точнее, транслирует) код скрипта во внутреннее представление (байт-код). Если файл небольшой, трансляция происходит очень быстро (Zend Engine в PHP - один из лидеров по скорости трансляции), однако, если включаемые библиотеки «весят» несколько мегабайтов, трансляция затягивается.

Существует ряд инструментов, кэширующих в разделяемой оперативной памяти (shared memory) оттранслированное внутреннее представление PHP-кода. Таким образом, при повторном включении PHP-файла он уже не транслируется, а байт-код берется из кэша в памяти. Естественно, это значительно ускоряет работу.

Одним из таких инструментов является eAccelerator. Он устанавливается в виде расширения PHP (подключается в php.ini) и требует самой минимальной настройки. Рекомендую включить в нем режим кэширования байт-кода исключительно в оперативной памяти и отключить сжатие (установить параметры eaccelerator.shm_only=1 и eaccelerator.compress=0). Также установите и настройте контрольную панель control.php, идущую в дистрибутиве eAccelerator, чтобы в реальном времени отслеживать состояние кэша. Без контрольной панели вам будет очень трудно проводить диагностику, если eAccelerator по каким-то причинам не заработает.

Преимущество eAccelerator в том, что он работает весьма стабильно и быстро даже на больших объемах PHP-кода. У меня ни разу не возникало проблем с этим инструментом (в отличие от Zend Accelerator, к примеру).

«Мой скрипт вместе с библиотеками занимает 5 МБ, как же быть?..»

Думаете, 5 МБ кода - это чересчур много для PHP? Ничего подобного. Попробуйте воспользоваться такими системами, как Zend Framework и Propel , чтобы убедиться в обратном. Zend Framework целиком занимает как раз около 5 МБ. Классы, сгенерированные Propel-ом, также весьма объемисты и могут отнять еще несколько мегабайтов.

Многие на этом месте посмеются и скажут, что не надо использовать Zend Framework и Propel, т.к. они «тормозные». Но действительность заключается в том, что тормозные вовсе даже не они… Плохую производительность имеет метод, который по умолчанию использует PHP для загрузки кода. К счастью, ситуацию нетрудно исправить.

Чтобы не быть голословным, я приведу результаты небольшого тестирования, которое я специально провел в «чистом» окружении, не привязанном к какому-либо конкретному проекту. Тестировалась скорость подключения всех файлов Zend Framework (за исключением Zend_Search_Lucene). Предварительно из кода были вырезаны все вызовы require_once, а загрузка зависимостей поизводилась только через механизм autoload .

Итак, всего подключались 790 PHP-файлов общим объемом 4.9 МБ. Немало, верно? Подключение осуществлялось примерно так:

function __autoload($className) { $fname = str_replace("_", "/", $className) . ".php"; $result = require_once($fname); return $result; } // Подключаем классы один за другим в порядке их зависимостей. class_exists("Zend_Acl_Assert_Interface"); class_exists("Zend_Acl_Exception"); class_exists("Zend_Acl_Resource_Interface"); class_exists("Zend_Acl_Resource"); // ... и так для всех 790 файлов

Благодаря тому, что используется autoload, вызов class_exists() заставляет PHP подключить файл соответствующего класса. (Это самый простой способ «дернуть» autoload-функцию.) Порядок подключения я выбрал таким, чтобы каждый следующий класс уже имел загруженными все свои зависимые классы на момент запуска. (Этот порядок нетрудно установить, просто печатая в браузер значение $fname в функции __autoload).

Вот результаты тестирования с eAccelerator-ом и без на моем не очень мощном ноутбуке (Apache, mod_php):

  • Подключение всех файлов по одному, eAccelerator выключен: 911 мс.
  • Подключение всех файлов по одному, eAccelerator включен: 435 мс. Занято 15 М кэш-памяти под байт-код.

Как видите, eAccelerator дает примерно двукратное ускорение на 790 файлах общим объемом 4.9 МБ. Слабовато. К тому же, 435 мс - явно чересчур для скрипта, который только и делает, что подключает библиотеки.

А теперь добавим стероидов

Ходят слухи, что PHP гораздо быстрее загружает один большой файл, чем десять маленьких того же суммарного объема. Я решил проверить это утверждение, объединив весь Zend Framework в один файл размером 4.9 МБ и подключив его единственным вызовом require_once. Давайте посмотрим, что получилось.

  • Включение одного большого слитого файла, eAccelerator выключен: 458 мс.
  • Включение одного большого слитого файла, eAccelerator включен: 42 мс. Занято 31 МБ кэш-памяти под байт-код.

Первая строчка говорит о том, что один большой файл размером 4.9 МБ и правда загружается быстрее, чем 790 маленьких: 458 мс против 911 мс (см. выше). Экономия в 2 раза.

А вот вторая строчка заставила меня от удивления подпрыгнуть на стуле и перепроверить результат несколько раз. Надеюсь, это же произойдет и с вами. Действительно, 42 мс - это в 11 раз быстрее, чем с отключенным eAccelerator-ом! Получается, что eAccelerator еще меньше любит мелкие файлы (кстати, даже в режиме eaccelerator.check_mtime=0): экономия в 11 раз.

Итак, мы действительно получили ускорение загрузки в 22 раза, как и было обещано в заголовке. Раньше весь Zend Framework, разбитый на файлы, подключался 911 мс, а с использованием eAccelerator и объединенем всех файлов в один - 42 мс. И это, заметьте, не на реальном сервере, а всего лишь на рядовом ноутбуке.

Вывод: ускорение в 22 раза

Подведем итоги.

  • Слияние всех файлов в один большой плюс включение eAccelerator для этого большого файла дает ускорение в 22 раза при объеме кода 4.9 МБ и числе файлов 790.
  • В случае небольшого числа файлов значительного объема eAccelerator может дать 10-кратное ускорение. Если файлов много, а суммарный объем большой, то ускорение примерно в 2 раза.
  • Расход кэш-памяти зависит от числа файлов разбиения: при фиксированном объеме чем файлов больше, тем расход меньше.

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

Заметьте также, что мы подключали весь Zend Framework. В реальных скриптах объем кода будет сильно меньше, т.к. обычно для работы требуется лишь незначительная часть ZF. Но даже при условии, что библиотеки занимают 4.9 МБ, мы получаем время загрузки 42 мс - вполне приемлемое для PHP-скрипта. Ведь в нагруженных проектах PHP-скрипты могут работать и несколько сотен миллисекунд (Facebook, Мой Круг и т. д.).

Конечно, если вы планируете запускать FastCGI в PHP не из соображений производительности, а просто чтобы не «завязываться» за Apache и ограничиться связкой «nginx+PHP» или «lighttpd+PHP», ничто этому не мешает. Более того, задействовав eAccelerator для FastCGI+PHP и слив много файлов кода в один большой, вы получите то же самое ускорение, которое я описал выше. Однако не тешьте себя надеждами, что ускорение дал именно FastCGI: это не так. Применяя mod_php+eAccelerator, вы достигли бы практически такого же результата, что и FastCGI+eAccelerator.

Вручную объединять все файлы библиотек в один - утомительное занятие. Лучше написать утилиту, которая будет автоматически анализировать список PHP-файлов, подключенных скриптом, а при следующем запуске - объединять эти файлы и записывать во временную директорию (если это еще не сделано), после чего - подключать по require_once. Сегодня я оставляю написание такой утилиты (плюс-минус детали) на совести читателя.

Также рекомендую вам отказаться от явного включения файлов по require_once и переходить на autoload. Только не пытайтесь использовать для этого Zend_Loader: он очень медленный (по моим замерам, подключение ста файлов отнимет дополнительно около 50 мс). Лучше напишите собственную несложную autoload-функцию, которая будет быстро выполнять всю работу. Autoload позволит вам безопасно объединять несколько файлов библиотек в один, не думая о том, как бороться с «ручными» require_once.

Наконец, применяйте функцию set_include_path() , чтобы код подключения библиотек выглядел вот так:

require_once "Some/Library.php";

require_once LIB_DIR . "/Some/Library.php";

Константы, определяющие путь к директории библиотек явным образом, - большое зло и усложнение программы. Они также косвенно противоречат стандартам кодирования Zend Framework и PEAR, которых я тоже рекомендую по возможности придерживаться.

Итак, хотите использовать «тяжелые» библиотеки в PHP-скриптах - на здоровье! PHP - скриптовый язык, по-настоящему позволяющий это делать без оглядки на неудобства FastCGI и проблемы «встроенных» серверов.

Одним из основных критериев успешности любого интернет-ресурса является скорость его работы и с каждым годом пользователи становятся всё более и более требовательными по этому критерию. Оптимизация работы php-скиптов - это один из методов обеспечения скорости работы системы.

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

Почему сборник советов и фактов, а не жестких правил? Потому что, как я убедился, не существует «абсолютно правильной оптимизации». Многие приёмы и правила противоречивы и выполнить их все невозможно. Приходиться выбирать совокупность методов, которыми приемлемо пользоваться без ущерба безопасности и удобности. Я занял рекомендательную позицию и поэтому у меня советы и факты, которые Вы можете соблюдать, а можете и не соблюдать.

Что бы не было путаницы, я разделил все советы и факты на 3 группы:

  • Оптимизация на уровне логики и организации приложения
  • Оптимизация кода
  • Бесполезная оптимизация

Группы выделены условно и некоторые пункты можно отнести сразу к нескольким из них. Цифры приведены для среднестатистического сервера (LAMP). В статье не рассматриваются вопросы связанные с эффективностью различных сторонних технологий и фреймворков, так как это тема отдельных дискуссий.

Оптимизация на уровне логики и организации приложения

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

  • Постоянно профилируйте свой код на сервере (xdebug) и на клиенте (firebug), что бы выявить узкие места кода
    Следует отметить, что профилировать надо и серверную, и клиентскую часть, так как не все серверные ошибки можно обнаружить на самом сервере.
  • Количество, используемых в программе пользовательских функций, никак не влияет на скорость
    Это позволяет использовать в программе бесчисленное число пользовательских функций.
  • Активно используйте пользовательские функций
    Положительный эффект достигается за счёт того, что внутри функций операции ведутся только с локальными переменными. Эффект этого больше, чем расходы на вызовы пользовательских функций.
  • «Критически тяжёлые» функции желательно реализовать на стороннем языка программирования в виде расширения PHP
    Это требует навыков программирования на стороннем языке, что значительно увеличивает время разработки, но в тоже время позволяет использовать приёмы вне возможности PHP.
  • Обработка статического файла html быстрее, чем интерпретируемого файла php
    Различие повремени на клиенте может составлять около 1 секунды, поэтому имеет смысл четкое разделение статики и генерируемых средствами PHP страниц.
  • Размер обрабатываемого (подключаемого) файла влияет на скорость
    Примерно на обработку каждых 2 Кб тратиться 0.001 секунды. Этот факт толкает нас на проведение минимизации кода скриптов при перенесении на рабочий сервер.
  • Старайтесь не использовать постоянно require_once или include_once
    Эти функции нужно использовать при наличии возможности повторного считывания файла, в остальных случаях желательно использовать require и include .
  • При ветвлении алгоритма, если имеются конструкции, которые могут не обрабатываться и их объём порядка 4 Кб и более, то более оптимально их подключать при помощи include.
  • Желательно использовать проверку отправляемых данных на клиенте
    Это вызвано тем, что при проверке данных на стороне клиента, резко снижается количество запросов с неверными данными. Системы проверки данных на клиенте строятся в основном с использованием JS и жестких элементов формы (select).
  • Желательно большие конструкций DOM для массивов данных строить на клиенте
    Это очень эффективный метод оптимизации при работе с отображением большого объёма данных. Суть его сводится к следующему: на сервере подготавливается массив данных и передаётся клиенту, а построение конструкций DOM предоставляется JS функциям. В результате нагрузка частично перераспределяется с сервера на клиент.
  • Системы, построенные на технологии AJAX, значительно быстрее, чем системы, не использующие эту технологию
    Это вызвано уменьшением объёмов вывода и перераспределением нагрузки на клиента. На практике скорость систем с AJAX в 2-3 раза выше. Замечание: AJAX в свою очередь создаёт ряд ограничений на использование других методов оптимизации, например, работа с буфером.
  • При получение post-запроса всегда возвращайте что-нибудь, можно даже пробел
    Иначе клиенту будет отправлена страница ошибки, которая весит несколько килобайт. Данная ошибка очень часто встречается в системах, использующих технологию AJAX.
  • Получение данных из файла быстрее, чем из БД
    Это во многом вызвано затратами на подключение к БД. К моему удивлению, огромный процент программистов маниакально хранят все данные в БД, даже когда использование файлов быстрее и удобнее. Замечание: в файлах можно хранить данные, по которым не ведётся поиск, в противном случае следует использовать БД.
  • Не осуществляйте подключение к БД без необходимости
    По неизвестной мне причине, многие программисты осуществляют подключение к БД на этапе считывания настроек, хотя далее они могут не делать запросов к БД. Это вредная привычка, которая стоит в среднем 0.002 секунды.
  • Используйте постоянное соединение с БД при малом количестве одновременно активных клиентов
    Выгода во времени вызвана отсутствием затрат на подключение к БД. Разница во времени примерно 0.002 секунды. Замечание: при большом количестве пользователей постоянные соединения использовать нежелательно. При работе с постоянными соединениями должен быть механизм завершения соединений.
  • Использование сложных запросов к БД быстрее, чем использование нескольких простых
    Разница во времени зависит от многих факторов (объём данных, настройка БД и пр.) и измеряется тысячными, а иногда даже сотыми, секунды.
  • Использование вычислений на стороне СУБД быстрее, чем вычисления на стороне PHP для данных хранящихся в БД
    Это вызвано тем фактором, что для таких вычислений на стороне PHP требуется два запроса к БД (получение и изменение данных). Разница во времени зависит от многих факторов (объём данных, настройка БД и пр.) и измеряется тысячными и сотыми секунды.
  • Если данные выборки из БД редко меняются и к этим данным обращается множество пользователей, то имеет смысл сохранить данные выборки в файл
    Например можно использовать следующий простой подход: получаем данные выборки из БД и сохраняем их как сериализованный массив в файл, далее любой пользователь использует данные из файла. На практике такой метод оптимизации может дать многократный прирост скорости выполнения скрипта. Замечание: При использовании данного метода требуются писать инструменты для формирования и изменения данных хранимых файле.
  • Кэшируйте данные, которые редко меняются, при помощи memcached
    Выигрыш времени может быть весьма значительным. Замечание: кэширование эффективно для статичных данных, для динамичных данных эффект снижается и может быть отрицательным.
  • Работа без объектов (без ООП) быстрее, чем работа с использованием объектов, примерно, в три раза
    Памяти «съедается» также больше. К сожалению, интерпретатор PHP не может работать с ООП также быстро как с обычными функциями.
  • Чем больше мерность массивов, тем медленнее они работают
    Потеря времени возникает из-за обработки вложенности структур.

Оптимизация кода

Данные советы и факты дают незначительны по сравнению с предыдущей группой прирост скорости, но в своей совокупности эти приёмы могут дать неплохой выигрыш времени.

  • echo и print значительно быстрее, чем printf
    Разница во времени может доходить до нескольких тысячных секунды. Это вызвано тем, что printf служит для вывода форматированных данных и интерпретатор проверяет полностью строку на вхождение таких данных. printf используется только для вывода данных, которым нужно форматирование.
  • echo $var."text" быстрее, чем echo "$var text"
    Это вызвано тем, что движок PHP во втором случае вынужден искать переменные внутри строки. Для больших объёмов данных и старых версий PHP различия по времени заметны.
  • echo "a" быстрее, чем echo "a" для строк без переменных
    Это вызвано тем, что во втором случае движок PHP пытается найти переменные. Для больших объёмов данных различия во времени достаточно заметны.
  • echo "a","b" быстрее, чем echo "a"."b"
    Вывод данных через запятую быстрее, чем через точку. Это вызвано тем, что во втором случае происходит конкатенация строк. Для больших объёмов данных различия во времени достаточно заметны. Примечание: это работает только с функцией echo, которая может принимать несколько строк в качестве аргументов.
  • $return="a"; $return.="b"; echo $return; быстрее, чем echo "a"; echo "b";
    Причина в том, что вывод данных требует некоторых дополнительных операций. Для больших объёмов данных различия во времени достаточно заметны.
  • ob_start(); echo "a"; echo "b"; ob_end_flush(); быстрее, чем $return="a"; $return.="b"; echo $return;
    Это вызвано тем, что вся работа осуществляется без обращения к переменным. Для больших объёмов данных различия во времени достаточно заметны. Замечание: данный прием неэффективен, если вы работаете с AJAX, так как в этом случае данные желательно возвращать в виде одной строки.
  • Используйте «профессиональную вставку» или?> a b
    Статические данные (вне программного кода) обрабатываются быстрее, чем вывод данных PHP. Этот прием называется профессиональной вставкой. Для больших объёмов данных различия во времени достаточно заметны.
  • readfile быстрее, чем file_get_contents , file_get_contents быстрее, чем require , а require быстрее, чем include для вывода статического контента из отдельного файла
    По времени считывания пустого файла колебания от 0.001 для readfile до 0.002 для include .
  • require быстрее, чем include для интерпретируемых файлов
    Замечание: при ветвлении алгоритма, когда есть возможность не использовать интерпретируемый файл, надо использовать include , т.к. require подключает файл всегда.
  • if (...) {...} else if (...) {} быстрее, чем switch
    Время зависит от количества веток.
  • if (...) {...} else if (...) {} быстрее, чем if (...) {...}; if (...) {};
    Время зависит от количества веток и условий. Необходимо использовать else if везде, где это возможно, так как это самая быстрая «условная» конструкция.
  • Наиболее часто встречающиеся условия конструкции if (...) {...} else if (...) {} надо помещать в начале ветвления
    Интерпритатор просматривает конструкцию сверху вниз, пока не найдет выполнение условия. Если интерпретатор находит выполнение условия, то остальныю часть конструкции он не просматривает.
  • < x; ++$i) {...} быстрее, чем for($i = 0; $i < sizeOf($array); ++$i) {...}
    Это вызвано тем, что во втором случае операция sizeOf будет выполнятся при каждой итерации. Время разницы выполнения зависит от числа элементов массива.
  • x = sizeOf($array); for($i = 0; $i < x; ++$i) {...} быстрее, чем foreach($arr as $value) {...} для не ассоциативных массивов
    Разница во времени значительна и увеличивается при увеличении массива.
  • preg _replace быстрее, чем ereg_replace , str_replace быстрее, чем preg_replace , но strtr быстрее, чем str_replace
    Разница во времени зависит от объёма данных и может достигать нескольких тысячных секунд.
  • Функции работы со строками быстрее, чем регулярные выражения
    Это правило является следствием предыдущего.
  • Удаляйте уже ненужные переменные-массивы для освобождения памяти.
  • Старайтесь не использовать подавление ошибок @
    Подавление ошибок производит ряд очень медленных операций, а так как частота повтора может быть очень большой, потери скорости могут быть значительными.
  • if (isset($str{5})) {...} быстрее, чем if (strlen($str)>4){...}
    Это вызвано тем, что вместо функции для работы со строками strlen используется стандартная операция проверки isset .
  • 0.5 быстрее, чем 1/2
    Причина в том, что во втором случае выполняется операция деления.
  • return быстрее, чем global при возвращении значения переменной из функции
    Это вызвано тем, что во втором случае создаётся глобальная переменная.
  • $row["id"] быстрее, чем $row
    Первый вариант быстрее в 7 раз.
  • $_SERVER[’REQUEST_TIME’] быстрее, чем time() для определения времени запуска скрипта
  • if ($var===null) {...} быстрее, чем if (is_null($var)) {...}
    Причина в том, что в первом случае нет использования функции.
  • ++i быстрее, чем i++ , --i быстрее, чем i--
    Это вызвано особенностями ядра PHP. Разница по времени менее 0.000001, но если у Вас данные процедуры повторяются тысячи раз, то присмотритесь к данной оптимизации.
  • Инкремент инициализированной переменой i=0; ++i; быстрее, чем не инициализированной ++i
    Разница по времени около 0.000001 секунды, но из-за возможной частоты повтора следует помнить данный факт.
  • Использование «отработавших» переменных быстрее, чем объявление новых
    Или перефразирую иначе – Не создавайте лишних переменных.
  • Работа с локальными переменными быстрее, чем с глобальными, примерно, в 2 раза
    Хоть и разница во времени менее 0.000001 секунды, но из-за высокой частоты повторения следует стараться работать с локальными переменными.
  • Обращение к переменной напрямую быстрее, чем вызов функции, внутри которой определяется эта переменная в несколько раз
    На вызов функции тратиться примерно в три раза больше времени, чем на вызов переменной.

Бесполезная оптимизация

Ряд методов оптимизации на практике не оказывают большого влияния на скорость выполнения скриптов (выигрыш времени менее 0.000001 секунды). Несмотря на это, такая оптимизация зачастую становиться предметом споров. Я привел данные «бесполезные» факты для того, чтобы вы в последующим не уделяли им особого внимания при написании кода.

  • echo быстрее, чем print
  • include("абсолютный путь") быстрее, чем include("относительный путь")
  • sizeOf быстрее, чем count
  • foreach ($arr as $key => $value) {...} быстрее, чем reset ($arr); while (list($key, $value) = each ($arr)) {...} для ассоциативных массивов
  • Не комментированный код быстрее, чем комментированный, так как уходит дополнительное время на чтение файла
    Весьма глупо уменьшать объём комментариев ради оптимизации, надо просто в рабочих («боевых») скриптах проводить минимизацию.
  • Переменные с короткими названиями быстрее, чем переменные с длинными названиями
    Это вызвано сокращением объёмов обрабатываемого кода. Аналогично предыдущему пункту, надо просто в рабочих («боевых») скриптах проводить минимизацию.
  • Разметка кода с использованием табуляции быстрее, чем с использованием пробелов
    Аналогично предыдущему пункту.

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


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