Экспорт собственных функций

Расширение PHP, конечно, может быть полезно только в том случае, если вы можете создавать функции и / или классы, которые можно вызывать из PHP-скриптов. Для функций это удивительно просто. До тех пор, пока у вас есть встроенная функция C++, которая имеет одну из следующих четырех подписей, вы можете вызвать ее почти непосредственно из PHP:

void example1();
void example2(Php::Parameters &params);
Php::Value example3();
Php::Value example4(Php::Parameters &params);

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

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

#include <phpcpp.h>
#include <iostream>

void myFunction()
{
    Php::out << "example output" << std::endl;
}

extern "C" {
    PHPCPP_EXPORT void *get_module() {
        static Php::Extension extension("my_extension", "1.0");
        extension.add<myFunction>("myFunction");
        return extension;
    }
}

Нетрудно представить, что делает этот код. Если вы развертываете это расширение, вы можете создать PHP-скрипты, в которых вы можете вызвать myFunction(), который будет печатать «пример вывода» на stdout.

As we've said before, there are four types of functions that can be used. In this first example we showed the most simple one: a function that does not take any parameters, and that returns nothing. What if you want to return a value from your function?

#include <phpcpp.h>
#include <stdlib.h>

Php::Value myFunction()
{
    if (rand() % 2 == 0)
    {
        return "string";
    }
    else
    {
        return 123;
    }
}

extern "C" {
    PHPCPP_EXPORT void *get_module() {
        static Php::Extension extension("my_extension", "1.0");
        extension.add<myFunction>("myFunction");
        return extension;
    }
}

Это нормально или не очень? В PHP вполне законно создавать функции, которые иногда возвращают число,а иногда и строку. Это невозможно сделать в C++, поскольку функция всегда должна возвращать переменную одного типа. Но поскольку класс Php::Value может использоваться для представления как числовых переменных, так и строк (и массивов, и объектов, но об этом позже), теперь мы можем также создавать собственные функции C++, которые иногда возвращают строку, а иногда и числовое значение. Вы можете протестировать функцию с помощью простого PHP-скрипта.

<?php
    for ($i=0; $i<10; $i++) echo(myFunction()."\n");
?>

Возможные выходные данные этого сценария могли бы, например, быть:

123
123
string
123
123
string
string
string
string

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

#include <phpcpp.h>

Php::Value sum_everything(Php::Parameters &parameters)
{
    int result = 0;
    for (auto &param : parameters) result += param;
    return result;
}

extern "C" {
    PHPCPP_EXPORT void *get_module() {
        static Php::Extension extension("my_extension", "1.0");
        extension.add<sum_everything>("sum_everything");
        return extension;
    }
}

Это выглядит так просто, не так ли? Класс Php::Parameters на самом деле не что иное, как std::vector, заполненный объектами Php::Value - и вы можете таким образом перебирать его. Мы используем новый C++11 способ сделать это, и мы используем ключевое слово new-for-C++11 "auto", чтобы попросить компилятор выяснить, какой тип переменных хранится в векторе параметров (это объекты Php::Value, конечно).

И вы можете снова увидеть, насколько мощным является класс Php::Value. Его можно использовать в правой части оператора +=, добавляемого к целочисленному значению, и конечная целочисленная результирующая переменная автоматически преобразуется обратно в объект Php::Value, когда функция возвращает - так же, как если бы вы работали с обычными PHP $переменными. Но помните, что это C++ код и поэтому намного, намного быстрее!

Функция sum_everything (), которую мы только что создали, теперь доступна из вашего PHP-скрипта. Давайте проведем тестирование.

<?php
    echo(sum_everything(10,"100",20)."\n");
?>

Выход вышеуказанного скрипта, конечно, 130. Строковая переменная "100", которая передается в функцию, автоматически преобразуется в целое число, что в точности соответствует поведению PHP-скрипта.

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

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