C++ 開發 PHP 7 擴展之模塊入口定義

zendAPI 項目不提供任何底層的功能,只是封裝了 zend engine 提供的功能,對上提供一個易用的編程接口。這篇文章中,咱們將介紹 C++ 世界與 C 世界交匯的地方,在這裏也是 zendAPI 的接口與 zend engine 進行整合的地方,很是重要。 每個 PHP 擴展必須有一個描述對象,在 zendAPI 中咱們 zapi::lang::Extension 類主要的做用主要完成這個功能。如今咱們來看一個最簡單的 zendAPI 項目的入口文件長什麼樣子:php

#include "zapi/ZendApi.h"

extern "C" {

ZAPI_DECL_EXPORT void *get_module() 
{
   static zapi::lang::Extension hellozapi("hellozapi", "1.0");
   return hellozapi;
}

}

怎麼樣很簡單吧,一個空的 PHP 擴展就完成了,如今咱們就詳細解釋下每行的做用。html

#include "zapi/ZendApi.h"

在開發基於 zendAPI 的項目時候,咱們只須要包含這個頭文件就能夠了,在這個頭文件中,咱們會引入 zendAPI 平常開發須要的必要的頭文件,您不用本身一個一個本身去引入。編程

extern "C"
{}

CPP 代碼與 C 代碼進行鏈接的時候咱們通常會加上 extern wrapper, 由於若是不加的話 CPP 編譯器會對函數名稱進行 name mangling,這個會致使鏈接的時候提示符號不存在的錯誤。api

ZAPI_DECL_EXPORT void *get_module();

ZAPI_DECL_EXPORT 表示咱們擴展導出符號 get_module 給其餘庫使用。函數 get_module 這個函數很是重要,他是 zendAPIzend engine 進行集成的入口,咱們必須在這個函數中設置好咱們擴展的一切,而後將擴展描述對象的指針返回。 在這裏我先簡單描述下 PHP 加載擴展這部分的過程: 在 PHP 初始化的過程當中調用的函數有:(這裏咱們以 cli SAPI 爲例進行說明)app

  1. php_cli_startup
  2. php_module_startup
  3. php_ini_register_extensions
  4. php_load_extension
  5. get_module = (zend_module_entry ()(void)) DL_FETCH_SYMBOL(handle, "_get_module");
  6. 調用 get_module,獲取zend_module_entry 對象指針

簡單來講咱們能夠這樣理解,在 PHP 模塊初始化的時候,PHP 會去讀取咱們在 php.ini 文件中註冊的擴展, 好比我們的 hellozapi 就在 php.ini 註冊了一行 extension=hellozapi.so。若是相關的擴展文件存在,PHP 使用 dlopen 平臺接口進行動態加載,成功的話, 獲取 _get_module 符號,而後進行調用,最終獲取一個 zend_module_entry 指針。函數

static zapi::lang::Extension hellozapi("hellozapi", "1.0");

這行代碼實例化一個擴展對象,第一個參數是我們的擴展的名稱,通常須要跟在 CMake 腳本中定義的項目名字保持一致,第二個參數指定擴展的版本號,這裏咱們定義爲 1.0,這些信息咱們均可以在 PHP 腳本中經過反射技術獲取同時也會出如今 phpinfo() 函數的輸出中。 特別提醒:這裏的 static 關鍵字不能去掉,去掉了咱們就返回了一個懸空指針。(dangle pointer)指針

return hellozapi;

新手可能會有疑問,咱們的 get_module 明明是返回一個 void *,而咱們這裏返回 zapi::lang::Extension 對象怎麼也能夠啊 ?原理很簡單,由於咱們的 zapi::lang::Extension 定義了一個轉換運算符,C++ 編譯器會自動進行類型轉換。code

到這裏,咱們這個空的 PHP 擴展就完成了,怎麼樣,簡單吧?休息一下咱們繼續。htm

文章使用的編程文檔的引用鏈接

ZAPI_DECL_EXPORT 參考手冊對象

zapi::lang::Extension 參考手冊

原文連接: C++ 開發 PHP 7 擴展之模塊入口定義

相關文章
相關標籤/搜索