Русская документация PHP-CPP

Наследование

PHP и C++ оба являются объектноориентрованными языками программировния, поддерживающими наследование классов. С++ поддерживает множественное наследование. В PHP каждый класс может иметь только один базовый класс. Но для восполнения отсутствия множественного наследования, в PHP есть поддержка интерфейсов и трэйтов.

Библиотека PHP-CPP также позволяет определять PHP-интерфейсы и создавать иерархии PHP-классов и PHP-интерфейсов.

Определение интерфейсов

Чтобы определить интерфейс в своем расширении и дать возможность использовать его в пользователском PHP коде, нужно поступить почти так же как и при определении обычного класса. С то й разницей, что вместо Php::Class<YourClass> вам нуно использовать Php::Interface. Следующий пример иллюстрирует сказанное:

/**
 *  Switch to C context to ensure that the get_module() function
 *  is callable by C programs (which the Zend engine is)
 */
extern "C" {
    /**
     *  Startup function that is called by the Zend engine 
     *  to retrieve all information about the extension
     *  @return void*
     */
    PHPCPP_EXPORT void *get_module() {
        // create static instance of the extension object
        static Php::Extension myExtension("my_extension", "1.0");
        
        // description of the interface so that PHP knows which methods 
        // are defined by it
        Php::Interface interface("MyInterface");
        
        // define an interface method
        interface.method("myMethod", { 
            Php::ByVal("value", Php::Type::String, true) 
        });
        
        // register other methods
        //...
        
        // add the interface to the extension
        // (or move it into the extension, which is faster)
        myExtension.add(std::move(interface));
        
        // return the extension
        return myExtension;
    }
}

PHP-Наследование и реализация PHP-интерфейсов

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

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

В классе Php::Class<CustomClass> определены два метода: Php::Class<CustomClass>::extends() и Php::Class<CustomClass>::implements(), которые используются для спецификации базового класса и реализуеммых интерфейсов соответственно. Что бы продиманстрировать как это работает, давайте рассмотрим пример:

/**
 *  Switch to C context to ensure that the get_module() function
 *  is callable by C programs (which the Zend engine is)
 */
extern "C" {
    /**
     *  Startup function that is called by the Zend engine 
     *  to retrieve all information about the extension
     *  @return void*
     */
    PHPCPP_EXPORT void *get_module() {
        // create static instance of the extension object
        static Php::Extension myExtension("my_extension", "1.0");
        
        // Определяем интерфейс
        Php::Interface myInterface("MyInterface");
        
        // Определяем методы интерфейса
        myInterface.method("myMethod", { 
            Php::ByVal("value", Php::Type::String, true) 
        });
        
        // Регистрируем пользовательский PHP-класс
        Php::Class<MyClass> myClass("MyClass");
        
        // Следующая строчка собщит PHP, что пользовательский класс 'MyClass'
        // реализует интерфейс MyInterface
        myClass.implements(myInterface);
        
        // Поскльку наш класс MyClass реализует интерфейс MyInterface,
        // То мы должны реализовать и определяемые интерфейсом методы.
        // Иначе наш класс автоматически станет абстрактным.
        myClass.method("myMethod", &MyClass::myMethod, {
            Php::ByVal("value", Php::Type::String, true) 
        });
        
        // Этот класс, будет производным от MyClass
        Php::Class<DerivedClass> derivedClass("DerivedClass");
        
        // Сообщаем PHP, что DerivedClass будет наследовать MyClass
        derivedClass.extends(myClass);
        
        // Добавляем наш интерфейс и классы в расширение
        myExtension.add(myInterface);
        myExtension.add(myClass);
        myExtension.add(derivedClass);
        
        // return the extension
        return myExtension;
    }
}

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

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

Установка PHP-CPP Загрузка расширений Ваше первое расширение Вывода и ошибок Функции Параметры Вызов функций и методов Классы и объекты Конструкторы и деструкторы Наследование Магические методы Магические интерфейсы Генерация исключений Специальные возможности Поля классов Работа с переменными ini записи Extension callbacks Пространства имен