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
這個函數很是重要,他是 zendAPI
與 zend engine
進行集成的入口,咱們必須在這個函數中設置好咱們擴展的一切,而後將擴展描述對象的指針返回。 在這裏我先簡單描述下 PHP
加載擴展這部分的過程: 在 PHP
初始化的過程當中調用的函數有:(這裏咱們以 cli SAPI
爲例進行說明)app
簡單來講咱們能夠這樣理解,在 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