PHP內核探索:嵌入式PHP

嵌入式PHP類似CLI
服務器君一共花費了295.155 ms進行了7次數據庫查詢,努力地為您提供了這個頁面。
試試閱讀模式?希望聽取您的建議

從PHP源碼目錄結構的介紹以及PHP生命周期可知:嵌入式PHP類似CLI,也是SAPI接口的另一種實現。 一般情況下,它的一個請求的生命周期也會和其它的SAPI一樣:模塊初始化=>請求初始化=>處理請求=>關閉請求=>關閉模塊。 當然,這只是理想情況。因為特定的應用由自己特殊的需求,只是在處理PHP腳本這個環節基本一致。

對于嵌入式PHP或許我們了解比較少,或者說根本用不到,甚至在網上相關的資料也不多, 例如很多游戲中使用Lua語言作為粘合語言,或者作為擴展游戲的腳本語言,類似的, 瀏覽器中的Javascript語言就是嵌入在瀏覽器中的。只是目前很少有應用將PHP作為嵌入語言來使用, PHP的強項目前還是在Web開發方面。

PHP對于嵌入式PHP的支持以及PHP為嵌入式提供了哪些接口或功能呢?首先我們看下所要用到的示例源碼:

#include <sapi/embed/php_embed.h>
#ifdef ZTS
    void ***tsrm_ls;
#endif
/* Extension bits */
zend_module_entry php_mymod_module_entry = {
    STANDARD_MODULE_HEADER,
    "mymod", /* extension name */
    NULL, /* function entries */
    NULL, /* MINIT */
    NULL, /* MSHUTDOWN */
    NULL, /* RINIT */
    NULL, /* RSHUTDOWN */
    NULL, /* MINFO */
    "1.0", /* version */
    STANDARD_MODULE_PROPERTIES
};
/* Embedded bits */
static void startup_php(void)
{
    int argc = 1;
    char *argv[2] = { "embed5", NULL };
    php_embed_init(argc, argv PTSRMLS_CC);
    zend_startup_module(&php_mymod_module_entry);
}
static void execute_php(char *filename)
{
    zend_first_try {
        char *include_script;
        spprintf(&include_script, 0, "include '%s'", filename);
        zend_eval_string(include_script, NULL, filename TSRMLS_CC);
        efree(include_script);
    } zend_end_try();
}
int main(int argc, char *argv[])
{
    if (argc <= 1) {
        printf("Usage: embed4 scriptfile";);
        return -1;
    }
    startup_php();
    execute_php(argv[1]);
    php_embed_shutdown(TSRMLS_CC);
    return 0;
}

以上的代碼可以在《Extending and Embedding PHP》在第20章找到(原始代碼有一個符號錯誤,有興趣的童鞋可以去圍觀下)。 上面的代碼是一個嵌入式PHP運行器(我們權當其為運行器吧),在這個運行器上我們可以運行PHP代碼。 這段代碼包括了對于PHP嵌入式支持的聲明,啟動嵌入式PHP運行環境,運行PHP代碼,關閉嵌入式PHP運行環境。 下面我們就這段代碼分析PHP對于嵌入式的支持做了哪些工作。 首先看下第一行:

#include <sapi/embed/php_embed.h>

在sapi目錄下的embed目錄是PHP對于嵌入式的抽象層所在。在這里有我們所要用到的函數或宏定義。 如示例中所使用的php_embed_init,php_embed_shutdown等函數。

第2到4行:

#ifdef ZTS
    void ***tsrm_ls;
#endif

ZTS是Zend Thread Safety的簡寫,與這個相關的有一個TSRM(線程安全資源管理)的東東,這個后面的章節會有詳細介紹,這里就不再作闡述。

第6到17行:

zend_module_entry php_mymod_module_entry = {
    STANDARD_MODULE_HEADER,
    "mymod", /* extension name */
    NULL, /* function entries */
    NULL, /* MINIT */
    NULL, /* MSHUTDOWN */
    NULL, /* RINIT */
    NULL, /* RSHUTDOWN */
    NULL, /* MINFO */
    "1.0", /* version */
    STANDARD_MODULE_PROPERTIES
};

以上PHP內部的模塊結構聲明,此處對于模塊初始化,請求初始化等函數指針均為NULL, 也就是模塊在初始化及請求開始結束等事件發生的時候不執行任何操作。 不過這些操作在sapi/embed/php_embed.c文件中的php_embed_shutdown等函數中有體現。 關于模塊結構的定義在zend/zend_modules.h中。

startup_php函數:

static void startup_php(void)
{
    int argc = 1;
    char *argv[2] = { "embed5", NULL };
    php_embed_init(argc, argv PTSRMLS_CC);
    zend_startup_module(&php_mymod_module_entry);
}

這個函數調用了兩個函數php_embed_init和zend_startup_module完成初始化工作。 php_embed_init函數定義在sapi/embed/php_embed.c文件中。它完成了PHP對于嵌入式的初始化支持。 zend_startup_module函數是PHP的內部API函數,它的作用是注冊定義的模塊,這里是注冊mymod模塊。 這個注冊過程僅僅是將所定義的zend_module_entry結構添加到注冊模塊列表中。

execute_php函數:

static void execute_php(char *filename)
{
    zend_first_try {
        char *include_script;
        spprintf(&include_script, 0, "include '%s'", filename);
        zend_eval_string(include_script, NULL, filename TSRMLS_CC);
        efree(include_script);
    } zend_end_try();
}

從函數的名稱來看,這個函數的功能是執行PHP代碼的。 它通過調用sprrintf函數構造一個include語句,然后再調用zend_eval_string函數執行這個include語句。 zend_eval_string最終是調用zend_eval_stringl函數,這個函數是流程是一個編譯PHP代碼, 生成zend_op_array類型數據,并執行opcode的過程。 這段程序相當于下面的這段php程序,這段程序可以用php命令來執行,雖然下面這段程序沒有實際意義, 而通過嵌入式PHP中,你可以在一個用C實現的系統中嵌入PHP,然后用PHP來實現功能。

<?php
if($argc < 2) die("Usage: embed4 scriptfile");
 
include $argv[1];
?>

main函數:

int main(int argc, char *argv[])
{
    if (argc <= 1) {
        printf("Usage: embed4 scriptfile";);
        return -1;
    }
    startup_php();
    execute_php(argv[1]);
    php_embed_shutdown(TSRMLS_CC);
    return 0;
}

這個函數是主函數,執行初始化操作,根據輸入的參數執行PHP的include語句,最后執行關閉操作,返回。 其中php_embed_shutdown函數定義在sapi/embed/php_embed.c文件中。它完成了PHP對于嵌入式的關閉操作支持。 包括請求關閉操作,模塊關閉操作等。

以上是使用PHP的嵌入式方式開發的一個簡單的PHP代碼運行器,它的這些調用的方式都基于PHP本身的一些實現, 而針對嵌入式的SAPI定義是非常簡單的,沒有Apache和CGI模式的復雜,或者說是相當簡陋,這也是由其所在環境決定。 在嵌入式的環境下,很多的網絡協議所需要的方法都不再需要。如下所示,為嵌入式的模塊定義。

sapi_module_struct php_embed_module = {
    "embed",                       /* name */
    "PHP Embedded Library",        /* pretty name */
 
    php_embed_startup,              /* startup */
    php_module_shutdown_wrapper,   /* shutdown */
 
    NULL,                          /* activate */
    php_embed_deactivate,           /* deactivate */
 
    php_embed_ub_write,             /* unbuffered write */
    php_embed_flush,                /* flush */
    NULL,                          /* get uid */
    NULL,                          /* getenv */
 
    php_error,                     /* error handler */
 
    NULL,                          /* header handler */
    NULL,                          /* send headers handler */
    php_embed_send_header,          /* send header handler */
 
    NULL,                          /* read POST data */
    php_embed_read_cookies,         /* read Cookies */
 
    php_embed_register_variables,   /* register server variables */
    php_embed_log_message,          /* Log message */
    NULL,                           /* Get request time */
    NULL,                           /* Child terminate */
 
    STANDARD_SAPI_MODULE_PROPERTIES
};
/* }}} */

在這個定義中我們看到了若干的NULl定義,在前面一小節中說到SAPI時,我們是以cookie的讀取為例, 在這里也有讀取cookie的實現——php_embed_read_cookies函數,但是這個函數的實現是一個空指針NULL。

延伸閱讀

此文章所在專題列表如下:

  1. PHP內核探索:從SAPI接口開始
  2. PHP內核探索:一次請求的開始與結束
  3. PHP內核探索:一次請求生命周期
  4. PHP內核探索:單進程SAPI生命周期
  5. PHP內核探索:多進程/線程的SAPI生命周期
  6. PHP內核探索:Zend引擎
  7. PHP內核探索:再次探討SAPI
  8. PHP內核探索:Apache模塊介紹
  9. PHP內核探索:通過mod_php5支持PHP
  10. PHP內核探索:Apache運行與鉤子函數
  11. PHP內核探索:嵌入式PHP
  12. PHP內核探索:PHP的FastCGI
  13. PHP內核探索:如何執行PHP腳本
  14. PHP內核探索:PHP腳本的執行細節
  15. PHP內核探索:操作碼OpCode
  16. PHP內核探索:PHP里的opcode
  17. PHP內核探索:解釋器的執行過程
  18. PHP內核探索:變量概述
  19. PHP內核探索:變量存儲與類型
  20. PHP內核探索:PHP中的哈希表
  21. PHP內核探索:理解Zend里的哈希表
  22. PHP內核探索:PHP哈希算法設計
  23. PHP內核探索:翻譯一篇HashTables文章
  24. PHP內核探索:哈希碰撞攻擊是什么?
  25. PHP內核探索:常量的實現
  26. PHP內核探索:變量的存儲
  27. PHP內核探索:變量的類型
  28. PHP內核探索:變量的值操作
  29. PHP內核探索:變量的創建
  30. PHP內核探索:預定義變量
  31. PHP內核探索:變量的檢索
  32. PHP內核探索:變量的類型轉換
  33. PHP內核探索:弱類型變量的實現
  34. PHP內核探索:靜態變量的實現
  35. PHP內核探索:變量類型提示
  36. PHP內核探索:變量的生命周期
  37. PHP內核探索:變量賦值與銷毀
  38. PHP內核探索:變量作用域
  39. PHP內核探索:詭異的變量名
  40. PHP內核探索:變量的value和type存儲
  41. PHP內核探索:全局變量Global
  42. PHP內核探索:變量類型的轉換
  43. PHP內核探索:內存管理開篇
  44. PHP內核探索:Zend內存管理器
  45. PHP內核探索:PHP的內存管理
  46. PHP內核探索:內存的申請與銷毀
  47. PHP內核探索:引用計數與寫時復制
  48. PHP內核探索:PHP5.3的垃圾回收機制
  49. PHP內核探索:內存管理中的cache
  50. PHP內核探索:寫時復制COW機制
  51. PHP內核探索:數組與鏈表
  52. PHP內核探索:使用哈希表API
  53. PHP內核探索:數組操作
  54. PHP內核探索:數組源碼分析
  55. PHP內核探索:函數的分類
  56. PHP內核探索:函數的內部結構
  57. PHP內核探索:函數結構轉換
  58. PHP內核探索:定義函數的過程
  59. PHP內核探索:函數的參數
  60. PHP內核探索:zend_parse_parameters函數
  61. PHP內核探索:函數返回值
  62. PHP內核探索:形參return value
  63. PHP內核探索:函數調用與執行
  64. PHP內核探索:引用與函數執行
  65. PHP內核探索:匿名函數及閉包
  66. PHP內核探索:面向對象開篇
  67. PHP內核探索:類的結構和實現
  68. PHP內核探索:類的成員變量
  69. PHP內核探索:類的成員方法
  70. PHP內核探索:類的原型zend_class_entry
  71. PHP內核探索:類的定義
  72. PHP內核探索:訪問控制
  73. PHP內核探索:繼承,多態與抽象類
  74. PHP內核探索:魔術函數與延遲綁定
  75. PHP內核探索:保留類與特殊類
  76. PHP內核探索:對象
  77. PHP內核探索:創建對象實例
  78. PHP內核探索:對象屬性讀寫
  79. PHP內核探索:命名空間
  80. PHP內核探索:定義接口
  81. PHP內核探索:繼承與實現接口
  82. PHP內核探索:資源resource類型
  83. PHP內核探索:Zend虛擬機
  84. PHP內核探索:虛擬機的詞法解析
  85. PHP內核探索:虛擬機的語法分析
  86. PHP內核探索:中間代碼opcode的執行
  87. PHP內核探索:代碼的加密與解密
  88. PHP內核探索:zend_execute的具體執行過程
  89. PHP內核探索:變量的引用與計數規則
  90. PHP內核探索:新垃圾回收機制說明

本文地址:http://www.zqhthc.tw/librarys/veda/detail/1318,歡迎訪問原出處。

不打個分嗎?

轉載隨意,但請帶上本文地址:

http://www.zqhthc.tw/librarys/veda/detail/1318

如果你認為這篇文章值得更多人閱讀,歡迎使用下面的分享功能。
小提示:您可以按快捷鍵 Ctrl + D,或點此 加入收藏

大家都在看

閱讀一百本計算機著作吧,少年

很多人覺得自己技術進步很慢,學習效率低,我覺得一個重要原因是看的書少了。多少是多呢?起碼得看3、4、5、6米吧。給個具體的數量,那就100本書吧。很多人知識結構不好而且不系統,因為在特定領域有一個足夠量的知識量+足夠良好的知識結構,系統化以后就足以應對大量未曾遇到過的問題。

奉勸自學者:構建特定領域的知識結構體系的路徑中再也沒有比學習該專業的專業課程更好的了。如果我的知識結構體系足以囊括面試官的大部分甚至吞并他的知識結構體系的話,讀到他言語中的一個詞我們就已經知道他要表達什么,我們可以讓他坐“上位”畢竟他是面試官,但是在知識結構體系以及心理上我們就居高臨下。

所以,閱讀一百本計算機著作吧,少年!

《UNIX編程藝術》 姜宏 (作者)

《UNIX編程藝術》主要介紹了Unix系統領域中的設計和開發哲學、思想文化體系、原則與經驗,由公認的Unix編程大師、開源運動領袖人物之一Eric S. Raymond傾力多年寫作而成。包括Unix設計者在內的多位領域專家也為本書貢獻了寶貴的內容。《UNIX編程藝術》內容涉及社群文化、軟件開發設計與實現,覆蓋面廣、內容深邃,完全展現了作者極其深厚的經驗積累和領域智慧。

更多計算機寶庫...

英超直播吻球网