[教學] 用 PHP-CPP 寫 PHP extension (1)

看板PHP作者 (Neisseria)時間8年前 (2016/12/07 11:03), 6年前編輯推噓3(300)
留言3則, 3人參與, 最新討論串1/1
如果 PHP 程式的速行速度無法滿足需求 將其改寫成 PHP extension 或許可以處理這個議題 傳統上,要寫 PHP extension 要用 C,而且要懂 Zend C API 說實在,還蠻費心力的 幸好有工程師開發了替代的方案,讓後人不需再和 Zend C API 奮戰 經 google 可知大致上有兩種方案: 1. Zephir:一個新的 PHP-like 編譯語言,寫完後程式碼可編譯成 PHP extension 是由 Phalcon 團隊開發的,Phalcon 本身也有使用這個語言 2. PHP-CPP:一個 C++ 函式庫,加入特有的 PHP 相關物件 由於 PHP-CPP 的寫法,和原來的 C++ 略有不同,筆者將其視為一種 DSL 使用這個方案的好處在易於橋接外部 C/C++ 函式庫 預計會寫兩篇,這是第一篇 首先,要實作 doubler 這個 toy library 這個函式庫是用 Rust 撰寫,輸出成 C shared library 如果不想用 Rust,也可用其他語言,能輸出 C/C++ shared library 即可 目前這個 library 已完成 但是,Rust 不會自動生成 header,要自己撰寫 撰寫 header 時要注意,我們會輸出到 C++ 中 要用 extern "C" 避免 name mangling #ifndef _DOUBLER_H_ #define _DOUBLER_H_ #ifdef __cplusplus extern "C" { #endif int double_int(int); double double_float(double); char* double_str(char*); void str_free(char*); #ifdef __cplusplus } #endif #endif // _DOUBLER_H_ 接著,要到 PHP-CPP 官網下載 EmptyExtension 這個專案骨架,再自行修改 目前仍要手動改 Makefile,還沒有自動化的流程 這部分請板友參考小弟的 repo 自行修改 接著,實作 C++ 程式碼的部分 要注意的是,PHP-CPP 的撰寫方式,和一般的 C++ 程式碼略有不同 我們看一下實際的範例 #include <phpcpp.h> #include <string> #include "doubler.h" using std::string; class Doubler : public Php::Base { public: Doubler() = default; virtual ~Doubler() = default; static Php::Value int_number(Php::Parameters&); static Php::Value float_number(Php::Parameters&); static Php::Value str(Php::Parameters&); }; Php::Value Doubler::int_number(Php::Parameters& params) { return double_int((int32_t)params[0]); } Php::Value Doubler::float_number(Php::Parameters& params) { return double_float((double)params[0]); } Php::Value Doubler::str(Php::Parameters& params) { char* s = double_str((char*)params[0].rawValue()); string output = string(s); str_free(s); return output; } 由以上程式碼,可發現撰寫 PHP-CPP 專案時,使用了特別的 Php::Parameters 表示 PHP 參數,回傳值也是特別的 Php::Value。另外,非基本型別要另外釋放記憶體。 其實我們這個 library 沒有物件,都是 static method,用類別只是當成命名空間 PHP-CPP 也支援非物件的函式和 PHP 的命名空間,可自行參考官網的說明 最後,要輸出該物件到 PHP。以下的 get_module 函式是每個 PHP-CPP 專案都有的 extern "C" { PHPCPP_EXPORT void *get_module() { static Php::Extension extension("doubler", "1.0"); // Put your library here Php::Class<Doubler> doubler("Doubler"); doubler.method<&Doubler::int_number>("int_number", { Php::ByVal("x", Php::Type::Numeric) }); doubler.method<&Doubler::float_number>("float_number", { Php::ByVal("x", Php::Type::Float) }); doubler.method<&Doubler::str>("str", { Php::ByVal("x", Php::Type::String) }); extension.add(std::move(doubler)); return extension; } } 撰寫完相關程式碼後,再編譯即可得到 PHP extension。 可以寫一個簡單的 PHP 程式呼叫此 extension <?php // main.php echo Doubler::int_number(2), "\n"; echo Doubler::float_number(1.3), "\n"; echo Doubler::str("Hi"), "\n"; 如果只是要測試,不想安裝 extension,可從命令列呼叫此 extension $ php -dextension=`pwd`/doubler.so main.php 這個範例到這裡算是告一段落了 接下來,我們會用另一個範例繼續展示 PHP-CPP 的使用 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 125.227.36.80 ※ 文章網址: https://www.ptt.cc/bbs/PHP/M.1481079805.A.F1A.html

12/07 13:00, , 1F
純推不下
12/07 13:00, 1F

12/07 13:04, , 2F
離上一次寫extension是6年前作手寫輸入法...
12/07 13:04, 2F

12/07 16:30, , 3F
12/07 16:30, 3F
※ 編輯: Neisseria (60.251.46.166), 12/24/2018 16:06:39
文章代碼(AID): #1OHtlzyQ (PHP)
文章代碼(AID): #1OHtlzyQ (PHP)