摘要:第一步打開項(xiàng)目下的文件,在文件中輸入我們的函數(shù)的原型聲明代碼。這行代碼注冊一個(gè)原型為的函數(shù),當(dāng)這個(gè)函數(shù)被執(zhí)行的時(shí)候,我們的函數(shù)將被運(yùn)行時(shí)調(diào)用。原文地址開發(fā)擴(kuò)展之原生函數(shù)定義
在上一篇中我們在hellozapi擴(kuò)展中我們定義了幾個(gè)常量,但是一個(gè)有用的擴(kuò)展,必須得有函數(shù),沒有函數(shù)的擴(kuò)展啥用沒有,如果您覺得定義函數(shù)很難的話,您又錯(cuò)了,zendAPI就是為了讓您生活變得美好而生的,而不會讓事情變得復(fù)雜。
說到函數(shù),咱們就不得不說函數(shù)最重要的兩個(gè)組成部分,一個(gè)是函數(shù)的參數(shù),另一個(gè)是函數(shù)的返回值。因?yàn)?b>C++是靜態(tài)語言,所以咱們的函數(shù)的類型必須在編譯時(shí)就要確定,不像PHP語言中那么靈活。
zendAPI主要支持如下幾種函數(shù)原型:
有返回值, 無參數(shù)
有返回值, 有參數(shù)
有返回值, 可變參數(shù)
無返回值, 無參數(shù)
無返回值, 有參數(shù)
無返回值, 可變參數(shù)
說明:zendAPI支持引用類型的參數(shù)傳遞
考慮到我們是新手學(xué)堂,在本篇中我們就不介紹可變參數(shù)和引用傳參了,這部分我們放在我們的高級教程部分講。
我們會在hellozapi中定義以下PHP原型的函數(shù):(PHP 語言描述)
print_project_name($prefix);
print_develop_team();
get_version();
add_two_num($num1, $num2);
下面我們聲明這幾個(gè)PHP函數(shù)對應(yīng)的C++函數(shù)原型
C++ Codeusing zapi::ds::Variant; using zapi::ds::NumericVaraint; using zapi::ds::StringVariant; void print_project_name(const StringVariant &prefix); void print_develop_team(); Variant get_version(); Variant add_two_num(const NumericVariant &num1, const NumericVariant num2);背景知識學(xué)習(xí)
在上面的C++函數(shù)的原型聲明中出現(xiàn)兩個(gè)陌生的類Variant和NumericVariant, 不要擔(dān)心,現(xiàn)在我們簡單介紹一下這兩個(gè)類。
在zendAPI中,zapi::ds::Variant類的一個(gè)對象就代表PHP的一個(gè)變量,您可以將zapi::ds::Variant想象成一個(gè)容器,它將常見的C++類型包裝成一個(gè)zapi::ds::Variant對象,方便跟zend engine整合。
您可以用這個(gè)類去包裝如下類型:
常見的整形 (int, std::int8_t, std::int16_t, std::int32_t, long ... )
浮點(diǎn)型 (float, double)
布爾型 (true, false)
字符串 (std::string, char *, char [])
空指針 (std::nullptr_t)
上面說的既然zapi::ds::Variant可以包裝一切必要的類型,是不是就夠了呢?答案是否定的,雖然zapi::ds::Variant可以容納C++的這些數(shù)據(jù)類型,但是它不提供任何特定類型的計(jì)算,比如常見的四則運(yùn)算,字符串連接,函數(shù)調(diào)用等等。
那么問題又來了,你可能會問,為什么不提供這樣的接口呢?接下來我就來解釋下為什么不在zapi::ds::Variant為什么不提供這些接口,原因有如下幾點(diǎn):
1.zapi::ds::Variant設(shè)計(jì)的目的就是充當(dāng)一個(gè)容器,方便zendAPI向zend engine進(jìn)行數(shù)據(jù)傳遞,它強(qiáng)調(diào)的數(shù)據(jù)傳遞而不是數(shù)據(jù)的計(jì)算。
2.zendAPI的設(shè)計(jì)理念是,單一的類完成單一的任務(wù),把字符串操作和整形操作甚至函數(shù)調(diào)用等等雜在一起違背了這個(gè)理念。
using zapi::ds::Variant; Varaint nullVar(nullptr); Variant numVar(123); Variant doubleVar(3.14);
根據(jù)上面討論的,看著名字不用我說,大家都能猜出這個(gè)類的作用吧,沒錯(cuò),您猜的是對的,這個(gè)是對zapi::ds::Variant再次封裝,為數(shù)值類型的zapi::ds::Variant提供數(shù)值計(jì)算的能力,比如四則運(yùn)算, 大小比較運(yùn)算。
using zapi::ds::NumericVariant; NumericVariant num1(123); NumericVariant num2(321); NumericVariant sum = num1 + num2; long rawSum = sum.toLong(); bool cmp = num1 < num2; // cmp is true std::int32_t raw32int1 = 123; std::int16_t raw32int2 = 23; NumericVariant num3(raw32int1); // value is 123 NumericVariant num4(raw32int2); // value is 23 sum = num3 + num4; // sum is 146
zapi::ds::NumericVariant 參考手冊
這個(gè)類跟zapi::ds::NumericVariant一樣,看名字我們就知道這個(gè)類是為字符串操作而設(shè)計(jì)的,它為我們提供了常見的字符串接口,拼接,子串查找,替換等等。下面我們就舉幾個(gè)常見的使用的范例:
using zapi::ds::StringVariant; StringVariant str1("hello zapi"); // str1 is hello zapi str1 += ", hello"; // now hello zapi, hello char c = str1[0]; // c is h std::string upperStr1 = str1.?toUpperCase(); str1.?replace("zapi", "zendAPI"); // str1 is hello zendAPI, hello str1.prepend("=> "); // str1 now is => hello zendAPI, hello
zapi::ds::StringVariant 參考手冊
好了數(shù)據(jù)類型了解完畢,我們下面開始進(jìn)入實(shí)現(xiàn)環(huán)節(jié)。
第一步打開hellozapi項(xiàng)目下的hellozapi/defs.h文件,在文件中輸入我們的C++函數(shù)的原型聲明代碼。
?#ifndef ZAPI_HELLOZAPI_DEFS_H #define ZAPI_HELLOZAPI_DEFS_H ?#include "zapi/ZendApi.h" using zapi::ds::Variant; using zapi::ds::?NumericVariant; using zapi::ds::StringVariant; void print_project_name(const StringVariant &prefix); void print_develop_team(); Variant get_version(); Variant add_two_num(const ?NumericVariant &num1, const ?NumericVariant &num2); #endif // ZAPI_HELLOZAPI_DEFS_H第二步
打開hellozapi項(xiàng)目下的hellozapi/impls.cpp文件,在文件中輸入我們的C++函數(shù)的實(shí)現(xiàn)代碼。
?#include "defs.h" #include第三步void print_project_name(const StringVariant &prefix) { zapi::out << prefix << " " << "hellozapi" << std::endl; } void print_develop_team() { zapi::out << "qcoreteam" << std::endl; } Variant get_version() { return "v1.0.2"; } Variant add_two_num(const NumericVariant &num1, const NumericVariant &num2) { return num1 + num2; }
將我們的實(shí)現(xiàn)的C++函數(shù)與zend engine進(jìn)行整合。打開我們的入口文件hellozapi/entry.cpp,輸入我們的函數(shù)注冊代碼。
?#include "zapi/ZendApi.h" #include "defs.h" using zapi::lang::Constant; using zapi::lang::ValueArgument; extern "C" { ZAPI_DECL_EXPORT void *get_module() { static zapi::lang::Extension hellozapi("hellozapi", "1.0"); Constant hellozapiVersionConst("HELLO_ZAPI_VERSION", 0x010002); Constant hellozapiNameConst("HELLO_ZAPI_NAME", "Hello zendAPI!"); Constant helloDebugModeConst("HELLO_DEBUG_MODE", true); Constant helloPiConst("HELLO_ZAPI_PI", 3.14); hellozapi.registerConstant(std::move(hellozapiVersionConst)); hellozapi.registerConstant(std::move(hellozapiNameConst)); hellozapi.registerConstant(std::move(helloDebugModeConst)); hellozapi.registerConstant(std::move(helloPiConst)); hellozapi.registerFunction("print_project_name", { ValueArgument("prefix", zapi::lang::Type::String) }); hellozapi.registerFunction ("print_develop_team"); hellozapi.registerFunction ("get_version"); hellozapi.registerFunction ("add_two_num", { ValueArgument("num1", zapi::lang::Type::Numeric), ValueArgument("num2", zapi::lang::Type::Numeric) }); return hellozapi; } }
到這里,代碼稍稍有些復(fù)雜了,但是細(xì)心的同學(xué)會發(fā)現(xiàn),其實(shí)代碼是很有規(guī)律的,只是重復(fù)調(diào)用而已,在這段代碼中我們引入了幾個(gè)新的類型,下面我先將這樣類型做些講解,然后我們再對這個(gè)代碼段進(jìn)行解釋。
zendAPI對zend engine的宏類型定義重新用enum class進(jìn)行了重新定義,方便實(shí)施C++的類型檢查,比如常用的類型有:
zapi::lang::Type::Undefined
zapi::lang::Type::Null
zapi::lang::Type::False
zapi::lang::Type::True
zapi::lang::Type::Long
zapi::lang::Type::String
zapi::lang::Type 參考手冊
zendAPI支持的參數(shù)傳遞有兩種,按值傳參和按引用傳參。zapi::lang::ValueArgument類型就是為了支持按值傳遞參數(shù)機(jī)制,它的構(gòu)造函數(shù)很簡單,第一個(gè)參數(shù)是傳遞的參數(shù)的名字,第二個(gè)參數(shù)是這個(gè)參數(shù)的類型,第三個(gè)參數(shù)設(shè)置這個(gè)參數(shù)是否是必須的參數(shù)。
比如下面的代碼我們定義了一個(gè)名叫arg1的參數(shù),類型是字符串并且是非必要參數(shù)
ValueArgument("arg1", zapi::lang::Type::String, false);
zapi::lang::ValueArgument 參考手冊
為了支持不同類型的函數(shù),zapi::lang::Extension::registerFunction被設(shè)計(jì)成了一個(gè)模板函數(shù),在這篇文章中我們暫時(shí)使用了用于注冊非成員函數(shù)指針的部分。
傳遞的模板參數(shù)有:
函數(shù)的類型 (一般我們不定義函數(shù)的類型,使用decltype進(jìn)行獲取)
函數(shù)指針值 (會被zendAPI在運(yùn)行時(shí)進(jìn)行調(diào)用)
decltype 參考手冊
傳遞的調(diào)用參數(shù)有:
函數(shù)的名字
函數(shù)接受的參數(shù)列表std::initializer_list
這里的 zapi::lang::Argument 是 zapi::lang::ValueArgument 的基類,一般不直接使用。
zapi::lang::Extension::registerFunction 參考手冊
std::initializer_list 參考手冊
有了上面的背景知識,現(xiàn)在我們解釋函數(shù)注冊代碼就簡單多了,您也很容易就能理解。
hellozapi.registerFunction("print_project_name", { ValueArgument("prefix", zapi::lang::Type::String) });
這行代碼注冊一個(gè)原型為print_project_name($prefix);的PHP函數(shù),當(dāng)這個(gè)函數(shù)被zend engine執(zhí)行的時(shí)候,我們的C++函數(shù)void print_project_name(const StringVariant &prefix);將被運(yùn)行時(shí)調(diào)用。
hellozapi.registerFunction("print_develop_team");
這行代碼注冊一個(gè)原型為print_develop_team的PHP函數(shù),當(dāng)這個(gè)函數(shù)被zend engine執(zhí)行的時(shí)候,我們的C++函數(shù)void print_develop_team();將被運(yùn)行時(shí)調(diào)用。
hellozapi.registerFunction("get_version");
這行代碼注冊一個(gè)原型為get_version的PHP函數(shù),當(dāng)這個(gè)函數(shù)被zend engine執(zhí)行的時(shí)候,我們的C++函數(shù)Variant get_version();將被運(yùn)行時(shí)調(diào)用。
hellozapi.registerFunction("add_two_num", { ValueArgument("num1", zapi::lang::Type::Numeric), ValueArgument("num2", zapi::lang::Type::Numeric) });
這行代碼注冊一個(gè)原型為add_two_num的PHP函數(shù),當(dāng)這個(gè)函數(shù)被zend engine執(zhí)行的時(shí)候,我們的C++函數(shù)Variant add_two_num(const ?NumericVariant &num1, const ?NumericVariant &num2);將被運(yùn)行時(shí)調(diào)用。
我們走到這里,函數(shù)注冊就完成了,雖然有些小長,但是您不也堅(jiān)持看完了嗎?
下面讓我們在PHP代碼中愉快的進(jìn)行調(diào)用吧。
怎么樣,實(shí)現(xiàn)函數(shù)也不過如此吧,根本沒啥難度,哈哈哈,您到時(shí)候也能自豪的說,我也能沒事的試試寫寫擴(kuò)展啦,給PHP語言添加幾個(gè)原生函數(shù)了。下一篇,我們來點(diǎn)更刺激的,教大家怎么實(shí)現(xiàn)原生的Class。
原文地址:C++ 開發(fā) PHP 7 擴(kuò)展之原生函數(shù)定義
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/30635.html
摘要:大家如果經(jīng)常閱讀官方手冊的話會發(fā)現(xiàn),在擴(kuò)展那一章里面的每個(gè)擴(kuò)展的介紹的時(shí)候,都有一節(jié)是預(yù)定義常量,這些常量是不需要您在里面進(jìn)行定義就可以使用的。比如擴(kuò)展的那么我們必須也在我們擴(kuò)展中也定義幾個(gè)常量玩玩啊,其實(shí)真的很簡單,不信那咱們走著看。 大家如果經(jīng)常閱讀 PHP 官方手冊的話會發(fā)現(xiàn),在擴(kuò)展那一章里面的每個(gè)擴(kuò)展的介紹的時(shí)候,都有一節(jié)是 Predefined Constants 預(yù)定義常量...
摘要:每一個(gè)擴(kuò)展必須有一個(gè)描述對象,在中我們類主要的作用主要完成這個(gè)功能。表示我們擴(kuò)展導(dǎo)出符號給其他庫使用。文章使用的編程文檔的引用連接參考手冊參考手冊原文鏈接開發(fā)擴(kuò)展之模塊入口定義 zendAPI 項(xiàng)目不提供任何底層的功能,只是封裝了 zend engine 提供的功能,對上提供一個(gè)易用的編程接口。這篇文章中,我們將介紹 C++ 世界與 C 世界交匯的地方,在這里也是 zendAPI 的接...
摘要:比如擴(kuò)展的那么我們必須也在我們擴(kuò)展中也定義幾個(gè)常量玩玩啊,其實(shí)真的很簡單,不信那咱們走著看。好了,到這里我們就把預(yù)定義常量就講完了,我沒有騙您吧,真的很簡單,稍作調(diào)整讓我們繼續(xù)前進(jìn)原文鏈接開發(fā)擴(kuò)展之定義常量 大家如果經(jīng)常閱讀 PHP 官方手冊的話會發(fā)現(xiàn),在擴(kuò)展那一章里面的每個(gè)擴(kuò)展的介紹的時(shí)候,都有一節(jié)是 Predefined Constants 預(yù)定義常量,這些常量是不需要您在 PHP...
摘要:入門,第一個(gè)這是一門很新的語言,年前后正式公布,算起來是比較年輕的編程語言了,更重要的是它是面向程序員的函數(shù)式編程語言,它的代碼運(yùn)行在之上。它通過編輯類工具,帶來了先進(jìn)的編輯體驗(yàn),增強(qiáng)了語言服務(wù)。 showImg(https://segmentfault.com/img/bV1xdq?w=900&h=385); 新的一年不知不覺已經(jīng)到來了,總結(jié)過去的 2017,相信小伙們一定有很多收獲...
摘要:入門,第一個(gè)這是一門很新的語言,年前后正式公布,算起來是比較年輕的編程語言了,更重要的是它是面向程序員的函數(shù)式編程語言,它的代碼運(yùn)行在之上。它通過編輯類工具,帶來了先進(jìn)的編輯體驗(yàn),增強(qiáng)了語言服務(wù)。 showImg(https://segmentfault.com/img/bV1xdq?w=900&h=385); 新的一年不知不覺已經(jīng)到來了,總結(jié)過去的 2017,相信小伙們一定有很多收獲...
閱讀 2377·2021-11-22 14:56
閱讀 1186·2019-08-30 15:55
閱讀 3215·2019-08-29 13:29
閱讀 1366·2019-08-26 13:56
閱讀 3515·2019-08-26 13:37
閱讀 569·2019-08-26 13:33
閱讀 3358·2019-08-26 13:33
閱讀 2239·2019-08-26 13:33