天天看點

十一、PHP核心探索:嵌入式PHP ☞ 嵌入式PHP類似CLI

從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(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(include_script, NULL, filename TSRMLS_CC);
        efree(include_script);
    } zend_end_try();
}      

從函數的名稱來看,這個函數的功能是執行PHP代碼的。 它通過調用sprrintf函數構造一個include語句,然後再調用zend_eval(232, 232, 232); background: rgb(249, 249, 249);">

<?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
};
/* }}} */