Вероятно, вы знаете, что родные расширения PHP скомпилированы в .so-файлы в unix-подобных системах и DLL-файлах в средах Windows и что глобальный файл php.ini содержит список всех расширений, доступных в вашей системе. Это означает, что если вы создаете собственное расширение, вы также создадите такой файл .so или .dll, и вам придется обновить файл конфигурации PHP, чтобы ваше собственное расширение было загружено PHP.

Функция запуска get_module()

Прежде чем мы объясним, как вы можете создать собственное расширение, мы сначала объясним, что PHP делает для загрузки расширения. Когда PHP запускается, он загружает файлы конфигурации * .ini из своего каталога конфигурации и для каждой строки «extension = name.so» в этих файлах конфигурации, он открывает соответствующую библиотеку и вызывает функцию get_module() из него. Поэтому каждая библиотека расширений (также как и  ваше расширение) должно определять и реализовывать эту функцию «get_module()». Эта функция вызывается PHP сразу после загрузки библиотеки (и, таким образом, перед обработкой страниц), и она должна возвращать адрес памяти, который указывает на структуру, которая содержит информацию обо всех функциях, классах, переменных и константах, которые становятся доступными  расширению.

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

#include <phpcpp.h>

/**
 *  сообщить компилятору, что get_module - это чистая функция C
 */
extern "C" {

    /**
     *  Функция, которая вызывается PHP сразу после начала процесса PHP,
     *  и возвращает адрес внутренней структуры PHP со всеми подробностями
     *  и функциями вашего расширения
     *
     *  @return void*   указатель на адрес, который понимается PHP
     */
    PHPCPP_EXPORT void *get_module() 
    {
        // static(!)Php::Extension объект, который должен оставаться в памяти
        // на протяжении всего процесса (поэтому он статический)
        static Php::Extension myExtension("my_extension", "1.0");

        // @todo    добавить свои собственные функции, классы, пространства имен в расширение

        // return the extension
        return myExtension;
    }
}

В приведенном выше примере вы видите очень простую реализацию функции get_module (). Каждое расширение PHP, использующее библиотеку PHP-CPP, реализует эту функцию более или менее аналогично, и это отправная точка каждого расширения. Ряд элементов требует особого внимания. Для начала единственным заголовочным файлом, который вы видите, является заголовочный файл phpcpp.h. Если вы используете PHP-CPP-библиотеку для создания собственных расширений, вам не нужно включать сложные, неструктурированные и в основном недокументированные файлы заголовков движка Zend - все, что вам нужно, это один заголовочный файл phpcpp.h Библиотека PHP-CPP. Если вы настаиваете, вы, конечно, можете также включать заголовочные файлы основного PHP-движка, но вам этого не нужно. PHP-CPP заботится о работе с внутренними механизмами PHP и предлагает вам простой в использовании API.

Следующее, что вы заметите, это то, что мы поместили функцию get_module () внутри кодового блока   extern "C". Поскольку имя библиотеки уже отдается, PHP-CPP является библиотекой C ++. Однако PHP ожидает, что ваша библиотека и особенно ваша функция get_module () будут реализованы в C, а не на C ++. Вот почему мы завершили функцию get_module () в блоке extern "C". Это даст указание компилятору C ++, что get_module () является регулярной функцией C и что он не должен применять к нему какое-либо имя C ++.

Библиотека PHP-CPP определяет макрос «PHPCPP_EXPORT», который должен быть помещен перед функцией get_module (). Этот макрос гарантирует, что функция get_module () будет публично экспортироваться и, следовательно, вызвана PHP. Макрос имеет другую реализацию, основанную на компиляторе и операционной системе.

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

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

Последним шагом в функции get_module () является то, что возвращается объект расширения. Сначала это может показаться странным, потому что функция get_module () должна возвращать указатель-на-void, а не полный объект Php :: Extension. Почему компилятор не жалуется на это? Ну, класс Php :: Extension имеет оператор cast-to-void-pointer-operator. Поэтому, хотя кажется, что вы возвращаете полный объект расширения, на самом деле вы возвращаете только адрес памяти, который указывает на структуру данных, которая понимается основным движком PHP, и которая содержит все детали вашего расширения.

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