PHP-CPP开发扩展(五)
PHP-CPP是一個用于開發PHP擴展的C++庫。本節講解如何在C++中實現PHP類。
類和對象
類和對象
怎樣在PHP-CPP里寫出PHP的類呢?很簡單,看下面的例子:
main.cpp
首先,C++類必須繼承自Php::Base;其次,當我們將類添加到擴展對象時,還必須指定要從PHP訪問的所有方法;最后再注冊導出類。
我們先測試:
/*** User: 公眾號: 飛鴻影的博客(fhyblog)* Date: 2018/7*/ $counter = new Counter; echo 'result of increment() = '. $counter->increment() . PHP_EOL; echo 'result of increment() = '. $counter->increment() . PHP_EOL; echo 'result of decrement() = '. $counter->decrement() . PHP_EOL; echo 'result of value() = '. $counter->value() . PHP_EOL; echo 'result of gettime() = '. Counter::gettime() . PHP_EOL;輸出:
result of increment() = 1 result of increment() = 2 result of decrement() = 1 result of value() = 1 result of gettime() = 1531621728訪問修飾符
我們還可以對導出的方法添加訪問修飾符:
//初始化導出類 Php::Class<Counter> counter("Counter");//注冊導出類的可訪問普通函數 counter.method<&Counter::increment> ("increment", Php::Private, {Php::ByVal("a", Php::Type::Numeric) }); counter.method<&Counter::decrement> ("decrement", Php::Protected, {Php::ByVal("a", Php::Type::Numeric) }); counter.method<&Counter::value> ("value");Php::Class::method第二個參數支持設置訪問修飾符,默認是public;第三個參數和普通函數一樣,支持設置參數類型。
支持的訪問修飾符:
extern PHPCPP_EXPORT const int Static; extern PHPCPP_EXPORT const int Abstract; extern PHPCPP_EXPORT const int Final; extern PHPCPP_EXPORT const int Public; extern PHPCPP_EXPORT const int Protected; extern PHPCPP_EXPORT const int Private; extern PHPCPP_EXPORT const int Const;有一點需要注意:C++里要導出的方法,必須全是Public的, 即使我們在PHP中將它們標記為私有或受保護。因為我們寫的方法由PHP-CPP庫調用,如果將它們設為私有,它們將對庫不可見。
抽象類、Final類
聲明類為Final很簡單,只需要在初始化導出類的時候聲明一下即可:
Php::Class<Counter> counter("Counter", Php::Final);那么怎么聲明一個抽象類呢?上面的例子里Php::Class::method都傳入了真正的C ++方法的地址,但是抽象方法通常沒有實現,那么我們需要怎么提供指向方法的指針?幸運的是,在PHP-CPP里注冊抽象方法不用提供指向C ++方法的指針。
示例:
抽象類原申明:
我們在test.php嘗試去實例化MyAbstract類,提示:
PHP Fatal error: Uncaught Error: Cannot instantiate abstract class MyAbstract注:官方示例里初始化導出類里沒有加Php::Abstract,測試的時候發現還是可以實例化的,只是調用抽象方法才報錯。
構造函數和析構函數
在C++代碼里,PHP的構造函數和析構函數本質上是普通方法。明白了這點,就不難實現了。
示例:
/*** User: 公眾號: 飛鴻影的博客(fhyblog)* Date: 2018/7*/ #include <phpcpp.h>/*** Simple counter class*/ class Counter : public Php::Base { private:/*** Internal value* @var int*/int _value = 0;public:/*** c++ constructor*/Counter() = default;/*** c++ destructor*/virtual ~Counter() = default;/*** php "constructor"* @param params*/void __construct(Php::Parameters ¶ms){// copy first parameter (if available)if (!params.empty()) _value = params[0];}/*** functions to increment and decrement*/Php::Value increment() { return ++_value; }Php::Value decrement() { return --_value; }Php::Value value() const { return _value; } };/*** Switch to C context so that the get_module() function can be* called by C programs (which the Zend engine is)*/ extern "C" {/*** Startup function for the extension* @return void**/PHPCPP_EXPORT void *get_module() {static Php::Extension myExtension("my_extension", "1.0");// description of the class so that PHP knows which methods are accessiblePhp::Class<Counter> counter("Counter");counter.method<&Counter::__construct>("__construct");counter.method<&Counter::increment>("increment");counter.method<&Counter::decrement>("decrement");counter.method<&Counter::value>("value");// add the class to the extensionmyExtension.add(std::move(counter));// return the extensionreturn myExtension;} }如果需要構造函數為私有的,只需要在注冊的時候加個flag:
counter.method<&Counter::__construct>("__construct", Php::Private);如果要禁止被clone,可以:
// alternative way to make an object unclonable counter.method("__clone", Php::Private);接口
接口(Interface)由于不需要具體方法的實現,我們可以通過與定義類的方式類似的方式來實現。唯一的區別是我們不使用Php::Class<YourClass>,而是一個Php::Interface實例。
//初始化 Php::Interface interface("MyInterface");//添加成員方法 interface.method("myMethod", { Php::ByVal("value", Php::Type::String, true) });//注冊到擴展 extension.add(std::move(interface));繼承
implement 實現
我們除了可以在PHP代碼去實現接口或者繼承類,也可以在C++里實現。該Php::Class<YourClass>對象有extends()和implements(),可用于指定基類和實現的接口。我們需要傳入之前配置的類或接口。我們來看一個例子。
/*** User: 公眾號: 飛鴻影的博客(fhyblog)* Date: 2018/7*/ #include <phpcpp.h> #include <iostream>class MyClass : public Php::Base {public:Php::Value myMethod(Php::Parameters ¶ms){Php::out << "MyClass" << std::endl;return params;} };extern "C" {PHPCPP_EXPORT void *get_module() {static Php::Extension extension("helloworld", "1.0.0");//定義接口Php::Interface interface("MyInterface");interface.method("myMethod", { Php::ByVal("value", Php::Type::String, true) });extension.add(std::move(interface));// 注冊一個自定義類Php::Class<MyClass> myClass("MyClass");// 實現接口定義myClass.implements(interface);myClass.method<&MyClass::myMethod>("myMethod", {Php::ByVal("value", Php::Type::String, true) });extension.add(std::move(myClass));// 返回擴展對象指針return extension;} }測試:
$obj = new MyClass(); var_dump($obj->myMethod(11));extends 繼承
PHP的繼承與C++的繼承沒有直接關系,必須顯示使用Php::Class::extends()進行繼承。
還是接著上面的例子說明。
/*** User: 公眾號: 飛鴻影的博客(fhyblog)* Date: 2018/7*/ #include <phpcpp.h> #include <iostream>class MyClass : public Php::Base {public:Php::Value myMethod(Php::Parameters ¶ms){Php::out << "MyClass" << std::endl;return params;} };class MySubClass : public Php::Base{ };extern "C" {PHPCPP_EXPORT void *get_module() {static Php::Extension extension("helloworld", "1.0.0");//定義接口Php::Interface interface("MyInterface");interface.method("myMethod", { Php::ByVal("value", Php::Type::String, true) });// 注冊一個自定義類Php::Class<MyClass> myClass("MyClass");// 實現接口定義myClass.implements(interface);myClass.method<&MyClass::myMethod>("myMethod", {Php::ByVal("value", Php::Type::String, true) });Php::Class<MySubClass> mySubClass("MySubClass");mySubClass.extends(myClass);extension.add(std::move(interface));extension.add(std::move(mySubClass));extension.add(std::move(myClass));// 返回擴展對象指針return extension;} }注:注冊類(extension.add)需要放到extends方法的后面,也就是不能先注冊父類再使用extends,否則無法繼承。建議實際編程的時候注冊統一放到最后面。
魔術方法
在PHP-CPP里,僅__construct()需要顯示的在get_module()里注冊,其他的魔術方法像__get()、__set()、__call()等都不需要注冊。
/*** User: 公眾號: 飛鴻影的博客(fhyblog)* Date: 2018/7*/ #include <phpcpp.h>/*** A sample class, that has some pseudo properties that map to native types*/ class User : public Php::Base { private:/*** Name of the user* @var std::string*/std::string _name;/*** Email address of the user* @var std::string*/std::string _email;public:/*** C++ constructor and C++ destructpr*/User() = default;virtual ~User() = default;/*** Get access to a property* @param name Name of the property* @return Value Property value*/Php::Value __get(const Php::Value &name){// check if the property name is supportedif (name == "name") return _name;if (name == "email") return _email;// property not supported, fall back on defaultreturn Php::Base::__get(name);}/*** Overwrite a property* @param name Name of the property* @param value New property value*/void __set(const Php::Value &name, const Php::Value &value) {// check the property nameif (name == "name") {// store member_name = value.stringValue();}// we check emails for validityelse if (name == "email"){// store the email in a stringstd::string email = value;// must have a '@' character in itif (email.find('@') == std::string::npos) {// email address is invalid, throw exceptionthrow Php::Exception("Invalid email address");}// store the member_email = email;}// other properties fall back to defaultelse{// call defaultPhp::Base::__set(name, value);}}/*** Check if a property is set* @param name Name of the property* @return bool*/bool __isset(const Php::Value &name) {// true for name and email addressif (name == "name" || name == "email") return true;// fallback to defaultreturn Php::Base::__isset(name);}/*** Remove a property* @param name Name of the property to remove*/void __unset(const Php::Value &name){// name and email can not be unsetif (name == "name" || name == "email") {// warn the user with an exception that this is impossiblethrow Php::Exception("Name and email address can not be removed");}// fallback to defaultPhp::Base::__unset(name);} };/*** 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() {// extension objectstatic Php::Extension myExtension("my_extension", "1.0");// description of the class so that PHP knows // which methods are accessiblePhp::Class<User> user("User");// add the class to the extensionmyExtension.add(std::move(user));// return the extensionreturn myExtension;} }測試:
<?php /*** User: 公眾號: 飛鴻影的博客(fhyblog)* Date: 2018/7*/// initialize user and set its name and email address $user = new User(); $user->name = "John Doe"; $user->email = "john.doe@example.com";// show the email address echo($user->email."\n");// remove the email address (this will cause an exception) unset($user->email); ?>(未完待續)
想第一時間獲取最新動態,歡迎關注關注飛鴻影的博客(fhyblog),不定期為您呈現技術干貨。
轉載于:https://www.cnblogs.com/52fhy/p/9388764.html
總結
以上是生活随笔為你收集整理的PHP-CPP开发扩展(五)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 0801作业
- 下一篇: php7连接mongodb,批量添加数据