• Руслан
  • 07 Май 2009
  • Рубрика: PHP

Как устроено расширение PHP

В предыдущем посте Пишем простое расширение PHP на C я привел только исходники простого расширения (extension) языка PHP написанного на C добавив только инструкции по сборке и установке расширения, не объясняя как это работает и как устроено расширение PHP “изнутри”. В сегодняшней публикации я немного запоздало восполню этот пробел и начну с того что собой представляют расширения и зачем они обычно создаются…

Итак, начнем сначала:

Четыре причины, которые могут вас побудить написать расширение на C

  1. вам нужна какая-то системная библиотека или очень специфичный системный вызов которые недоступны из PHP напрямую, но могут быть вызваны из кода на C
  2. вы хотите добавить новую необычную возможность в сам язык PHP
  3. у вас уже есть написанный код PHP и вы хотите чтобы он работал быстрее или занимал меньше памяти во время выполнения
  4. если вы продаете программы на PHP, то, вынеся часть кода в расширение на C и откомпилировав его, вы можете таким образом весьма эффективно защитить критические части исходного текста программы от просмотра

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

Если вы были раньше пользователем PHP, то вы также использовали и его расширения. Не считая некоторых очень немногочисленных исключений, каждая доступная функция языка PHP относится к одному из его расширений. Большое количество (около 400) функций включены в стандартное расширение. Всего в поставку языка PHP включается около 86 расширений, каждое из которых насчитывает в среднем 30 функций. Всего получается примерно 2500 функций. В репозитории PECL доступны еще более 100 дополнительных расширений и еще большее количество можно найти на просторах сети Интернет.

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

Ядро PHP состоит из двух отдельных частей. В основе его лежит Zend Engine (далее ZE). Эта часть отвечает за разбор написанного скрипта PHP в человеко-читаемой форме и преобразует в последовательность токенов, которые будут восприниматься машиной. И после этого выполняет полученные токены внутри выделенного процессу пространства. ZE также занимается вопросами выделения памяти, видимости переменных и вызова функций.

Вторая часть представляет собой буфер между первой частью и уровнем SAPI (Server Application Programming Interface - специальный программный интерфейс для серверных приложений) через который и происходит обмен данными с окружением (Apache, IIS, CLI, CGI и так далее). Также этот уровень предоставляет возможность контроля для проверок, которые выполняют save_mode или open_basedir. На этом же уровне пользовательские функции fopen(), fread() и fwrite() получают доступ к файловому и сетевому вводу/выводу.

Жизненный цикл расширения PHP

Сразу после запуска SAPI приложения, которое служит основой для работы PHP (например веб-сервер Apache с mod_php), PHP начинает инициализацию подсистем которые входят в состав ядра. В конце процедуры запуска PHP загружает код каждого из подключенных в файле конфигурации расширений и для каждого из них вызывает специальную процедуру инициализации (MINIT).
Это дает возможность каждому из расширений возможность инициализировать внутренние переменные, выделить необходимые ресурсы, зарегистрировать свои функции в ZE и сделать их таким образом доступными для вызова из кода на PHP.

После этого PHP ожидает поступления запроса на обработку с SAPI уровня. В случае если PHP вызывается из CGI или CLI такой запрос передается сразу же и только один раз. В случае с Apache, IIS или другим веб-сервером возможны многочисленные передачи различных запросов в течении неопределенного времени. Но независимо от того как именно был передан запрос PHP создает для скрипта рабочее окружение и после этого вызывает для каждого из зарегистрированных расширений специальную функцию инициализации обработки запроса (RINIT). На этом этапе расширения получают возможность установить специфичные переменные окружения, выделить ресурсы которые необходимы для обработки именно этого запроса.

Работу функции RINIT можно рассмотреть на примере расширения, которое реализует механизм сессий. На этапе инициализации расширение проверит установлено ли значение ini-параметра session.auto_start и, в зависимости от результата, автоматически вызовет пользовательскую функцию session_start(), создаст и наполнит массив $_SESSION.

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

После окончания работы скрипта PHP вызывает функцию окончания обработки запроса (RSHUTDOWN) для каждого из расширений и проводит последнюю подчистку перед окончанием работы (на этом этапе сохраняются значения переменных сессии) и запускает “сборщик мусора” на уровне ZE который освобождает все затребованные во время обработки запроса ресурсы.

На следующем этапе PHP переходит в режим ожидания следующего запроса и находится в этом состоянии до тех пор пока не получит следующий запрос (или сигнал завершения работы :) ). Если запрос был сделан через интерфейс командной строки или шлюз CGI, то никаких “следующих” запросов уже быть не может и SAPI сразу же инициирует завершение работы.

Завершая работу, PHP уже в последний раз обращается последовательно к каждому из расширений и вызывает в каждом процедуру завершения работы модуля (MSHUTDOWN) и после этого завершает работу подсистем своего “ядра”.

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

Статья основана на материалах с сайта devzone.zend.com

Если вам понравился этот сайт, вы можете подписаться на rss

Отзывы: Комментариев нет

Ваш отзыв

Имя (*)

E-mail (*)

Сайт

Сообщение

Архивы

службы мониторинга серверов