Pull to refresh

PHP модуль — это просто

Reading time3 min
Views20K
Недавно мы опубликовали визард для VisualStudio, с помощью которого можно создать экстеншн в пару кликов мыши. Теперь с помощью него мы напишем наши два первых расширения: «Привет, мир» и «вытащим иконку из exe».
Сразу прошу прощение, что очень сильно задержал статью, но жизненные обстоятельства вынудили это сделать, но они исключительно уважительные.





Итак, начнем.
1. Качаем «волшебника» для VS 2008.
По ссылке из темы VS wizard: PHP extension
Устанавливаем его, это произойдет автоматически.

2. Скачиваем необходимые для сборки файлы.
Нужны лишь исходники PHP и бинарники. Скачиваем 5.2.11 версию обоих файлов
Разархивируем php-5.2.11-Win32.zip в C:\PHPDEV\php-5.2.11-Win32 и php-5.2.11.tar.bz2 в C:\PHPDEV\php-5.2.11.

3. Запускаем VS, создаем новый проект.

И вводим его название. Пути настраивать не придется ;)

После этого видим главное окно студии, смотрим, что же там в файлах.


4. Создаем функции.
Как уже замечено, то скелет полностью создан, осталось лишь написать функции и прописать их.
В проекте есть тестовая функция, раскоментируем ее.
Для справки:
1) Заголовок функции должен быть в h файле. В виде PHP_FUNCTION(имя_функции).
2) Определение — в c файле.
3) Функция должна быть прописана в function_entry test_functions в c файле. В виде PHP_FE(имя_функции, NULL).
Как написать саму функцию, я расскажу позднее. А пока ограничимся этой:
PHP_FUNCTION(hello_world) {
    RETURN_STRING("Hello World", 1);
}


5. Сборка и запуск.
Собираем в релизе. Собралось.
Создаем каталог C:\PHPDEV\test
Копируем туда php.exe и php5ts.dll из каталога.
Копируем собранный dll под именем test.dll.
Создаем php.ini:
extension_dir = .
extension = test.dll

Создаем test.php со строкой <?=hello_world()?> и запускаем его в консоли.


6. Продвинутое создание функций.
Разберемся, как принимать значения из функций и передавать их.
Сложность заключается в том, что функция принимает и возвращает различные значения различных типов.
Рассмотрим пример, при котором принимается строка и целое и возвращается строка.
PHP_FUNCTION(foo) {
    char* input;
    int inputLength;
    long multy;
    char* result;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &input, &inputLength, &multy)) {
        return;
    }
    result = (char*) emalloc(strlen(input) + sizeof(long) + 3);
    sprintf(result, "%s, %ld", input, multy);
    RETURN_STRING(result, 1);
}

Как можно увидеть, здесь использованы следующие конструкции:
zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, строка_формата, адреса_дляполучаемых_значений)
RETURN_*;
Рассмотрим 2 таблицы, в первой указаны принимаемые PHP-типы и соответствующие им форматы и типы C.
Во второй возвращаемые значения с соответствующими конструкциями.
Дабы не утруждать себя, я прилагаю фотографии таблиц из книги, которую я всем советую прочитать.


Еще раз смотрим на примеры выше и понимаем, как все просто.
Кстати хочу обратитьт внимание, что выделение памяти ведется через e-аналоги функций c(emalloc, efree, erealloc), это нужно для того, чтобы GC PHP сам смог «прибраться».

7. Полезный пример. Вытащим иконку из exe.
Конечно можно написать это и на PHP, но работы будет больше. А тут уже есть необходимые заголовки.
Напишем код на C(писал одепт bl4de):
В файле pe.h мы видим использование кусков кода из библиотек windows: они нам помогут, а прямое их подключение невозможно, мы ведь пишем кроссплатформенное расширение, не так ли? ;)
В pe.c же пишем код. Как и понятно, мы будем оборачивать функцию void _extract_ico(char *filename, char *filenameOut).
PHP_FUNCTION(extract_ico) {
    char *filename;
    char *filenameOut;
    int len1, len2;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &filename, &len1, &filenameOut, &len2)) {
        return;
    }
    _extract_ico(filename, filenameOut);
    RETURN_NULL();
}

Ничего сложного, как мы видим. Просто и понятно. Вот такие вот файлы получились в итоге: php_ico.c и php_ico.h.

8. Бонус: сборка под *nix
Бонус заключается в наличии config.m4 файла, так что для сборки надо лишь выполнить серию команд:
phpize
./configure
make
Естественно в системе должны стоять соответствующие пакеты.
Для ubuntu 9.10 server это делается так:
sudo apt-get install build-essential php5 php5-dev
Берем собранную so-библиотеку и прописываем в расширения. Готово.
Да, *nix гораздо удобнее для веб-программиста, среди моих знакомых на винде сидит мешишинство. Многие предпочитают убунту или мак =)

9. Литература и полезные ссылки.
1) Джордж Шлосснейгл. Профессиональное программирование на PHP. Купить можно на books.ru, там дешевле всего из популярных магазинов имхо. Если хотите меня поддержать, то жмите эту ссылку =)
2) Extension Writing Part I: Introduction to PHP and Zend
3) PHP: internals:windows [PHP Wiki]

P.S. А в следующий раз я расскажу, как встроить PHP в свое приложение на С/C++. Но не буду обещать, что это будет «на днях».
Tags:
Hubs:
Total votes 96: ↑80 and ↓16+64
Comments17

Articles