Мы начнём с создания очень простого расширения, которое первоначально реализует функцию, возвращающую целое число, принятое ей в качестве параметра. В Листинге 9.3 дан исходник.
/* включить/include стандартный header */ #include "php.h" /* объявление экспортируемой функции */ ZEND_FUNCTION(first_module); /* скомпилированный список функций, так что Zend знает, что находится в этом модуле */ zend_function_entry firstmod_functions[] = { ZEND_FE(first_module, NULL) {NULL, NULL, NULL} }; /* скомпилированная информация модуля */ zend_module_entry firstmod_module_entry = { STANDARD_MODULE_HEADER, "First Module", firstmod_functions, NULL, NULL, NULL, NULL, NULL, NO_VERSION_YET, STANDARD_MODULE_PROPERTIES }; /* реализуется стандартная "заглушка/stub" для введения в Zend */ #if COMPILE_DL_FIRST_MODULE ZEND_GET_MODULE(firstmod) #endif /* реализуется функция, которая должна стать доступной для PHP */ ZEND_FUNCTION(first_module) { long parameter; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", ¶meter) == FAILURE) { return; } RETURN_LONG(parmeter); } |
В этом коде содержится завершённый PHP-модуль. Мы коротко разъясним исходный код в деталях, но сначала необходимо обсудить процесс построения/build. (Это даст возможность самым нетерпеливым поэкспериментировать, прежде чем мы углубимся в дискуссию об API.)
Существуют три основных способа компиляции модулей:
Использовать предоставляемый "make"-механизм в директории dl.
Использовать предоставляемый "make"-механизм в директории ext, что позволяет также строить динамически загружаемые модули.
Компилировать исходник вручную.
Предпочтителен второй метод, так как в PHP 4.0 он стал стандартизованным сложным процессом построения. Такое усложнение имеет также, к сожалению, и недостатки, - в нём трудно разобраться. Для этого далее в этой главе будет дано развёрнутое объяснение, но пока поработаем с файлами по умолчанию.
Процесс make, содержащийся в директории dl, это не очень чистый вариант, планируемый на удаление из исходного дерева. Откровенно говоря, намного проще использовать построение динамических расширений, но, поскольку здесь нет возможностей директории ext и она в любом случае намечена к удалению, использование директории dl не рекомендуется.
Третий метод хорош для тех, кто (по некоторым причинам) не имеет полного исходного дерева PHP, не имеет доступа ко всем файлам или просто любит поработать с клавиатурой. Эти случаи должны быть чрезвычайно редкими, но мы обязаны рассмотреть также и этот метод.
Компиляция с использованием Make. Для компилирования исходников с использованием стандартного механизма скопируйте всех субдиректории в директорию ext вашего исходного дерева PHP. Затем запустите buildconf, который создаст новый скрипт configure, содержащий необходимые опции. По умолчанию все сэмплы исходников отключены/disabled, поэтому вы можете не бояться прерывания вашего процесса построения.
После запуска buildconf, configure --help покажет следующие дополнительные модули:
--enable-array_experiments BOOK: Enables array experiments --enable-call_userland BOOK: Enables userland module --enable-cross_conversion BOOK: Enables cross-conversion module --enable-first_module BOOK: Enables first module --enable-infoprint BOOK: Enables infoprint module --enable-reference_test BOOK: Enables reference test module --enable-resource_test BOOK: Enables resource test module --enable-variable_creation BOOK: Enables variable-creation module |
Модуль, показанный ранее в Листинге 9.3, может быть включён с помощью --enable-first_module или --enable-first_module=yes.
Компилирование вручную. Чтобы скомпилировать ваши модули вручную, вам нужно выполнить следующие команды:
Акция | Команда |
---|---|
Компиляция | cc -fpic -DCOMPILE_DL=1 -I/usr/local/include -I. -I.. -I../Zend -c -o <your_object_file> <your_c_file> |
Компоновка/Linking | cc -shared -L/usr/local/lib -rdynamic -o <your_module_file> <your_object_file(s)> |
Команда компиляции модуля просто инструктирует компилятор: генерировать позиционно независимый код (-fpic нельзя опускать), и дополнительно определяет константу COMPILE_DL, чтобы сообщить коду модуля, что он компилируется как динамически загружаемый модуль (вышеприведённый тестовый модуль проверяет это; мы обсудим это кратко). После этого специфицируется несколько стандартных include-путей, которые должны использоваться как минимальный набор при компиляции исходников.
Команда link (компоновки) это также обычная команда, выполняющая компоновку динамического модуля.
Вы можете включить в команду компоновки опции оптимизации, отсутствующие в нашем примере (но некоторые из них включены в makefile-шаблон, описанный в предыдущем разделе).
В зависимости от избранного вами процесса построения/build, вы должны либо
выполнить ваш новый исполняемый PHP как связанный с вашим Web-сервером (или
запускать как CGI), либо как файл .so (shared object/совместно используемого
объекта). Если вы скомпилировали файл примера first_module.c как shared object, ваш результирующий файл должен быть
first_module.so. Для его использования вы должны сначала скопировать его в место, из которого
он доступен для PHP. Для простого тестирования вы можете скопировать его в вашу директорию htdocs
и испытать его с исходником из Листинга 9.4.
Если вы скомпилировали его в исполняемый файл PHP,
исключите вызов dl(), так как функциональность модуля постоянно
доступна вашим скриптам.
Предупреждение! |
---|
Из соображений безопасности вы не должны помещать ваши динамические модули в публично доступные директории. Хотя это и возможно и упрощает тестирование, вы должны помещать эти модули в отдельную директорию в рабочей среде. |
<?php //dl("first_module.so"); $param = 2; $return = first_module($param); print("We sent \"$param\" and got \"$return\""); ?> |
Вызов этого PHP-файла в вашем Web-браузере должен дать вывод - We sent "2" and got "2".
Если необходимо, динамически загружаемый модуль загружается с помощью вызова функции dl(). Эта функция ищет специфицированный совместно используемый/shared объект, загружает его и делает его функциональность доступной для PHP. Этот модуль экспортирует функцию first_module(), которая принимает единственный параметр, конвертирует его в integer и возвращает результат конвертации.
Если у вас всё получилось, наши поздравления! Вы построили ваше первое расширение PHP.