8.PHP核心探索:再次探討SAPI

來源:互聯網
上載者:User

標籤:http   io   os   使用   ar   檔案   div   art   on   

在PHP的生命週期的各個階段,一些與服務相關的操作都是通過SAPI介面實現。 這些內建實現的物理位置在PHP源碼的SAPI目錄。這個目錄存放了PHP對各個伺服器抽象層的代碼, 例如命令列程式的實現,Apache的mod_php模組實現以及fastcgi的實現等等。

在各個伺服器抽象層之間遵守著相同的約定,這裡我們稱之為SAPI介面。 每個SAPI實現都是一個_sapi_module_struct結構體變數。(SAPI介面)。 在PHP的源碼中,當需要調用伺服器相關資訊時,全部通過SAPI介面中對應方法調用實現, 而這對應的方法在各個伺服器抽象層實現時都會有各自的實現。

下面是為SAPI的簡單:

以cgi模式和apache2伺服器為例,它們的啟動方法如下:

cgi_sapi_module.startup(&cgi_sapi_module)   //  cgi模式 cgi/cgi_main.c檔案 apache2_sapi_module.startup(&apache2_sapi_module); //  apache2伺服器  apache2handler/sapi_apache2.c檔案

這裡的cgi_sapi_module是sapi_module_struct結構體的靜態變數。 它的startup方法指向php_cgi_startup函數指標。在這個結構體中除了startup函數指標,還有許多其它方法或欄位。 其部分定義如下:

struct _sapi_module_struct {    char *name;         //  名字(標識用)    char *pretty_name;  //  更好理解的名字(自己翻譯的)     int (*startup)(struct _sapi_module_struct *sapi_module);    //  啟動函數    int (*shutdown)(struct _sapi_module_struct *sapi_module);   //  關閉方法     int (*activate)(TSRMLS_D);  // 啟用    int (*deactivate)(TSRMLS_D);    //  停用     int (*ub_write)(const char *str, unsigned int str_length TSRMLS_DC);     //  不緩衝的寫操作(unbuffered write)    void (*flush)(void *server_context);    //  flush    struct stat *(*get_stat)(TSRMLS_D);     //  get uid    char *(*getenv)(char *name, size_t name_len TSRMLS_DC); //  getenv     void (*sapi_error)(int type, const char *error_msg, ...);   /* error handler */     int (*header_handler)(sapi_header_struct *sapi_header, sapi_header_op_enum op,        sapi_headers_struct *sapi_headers TSRMLS_DC);   /* header handler */      /* send headers handler */    int (*send_headers)(sapi_headers_struct *sapi_headers TSRMLS_DC);     void (*send_header)(sapi_header_struct *sapi_header,            void *server_context TSRMLS_DC);   /* send header handler */     int (*read_post)(char *buffer, uint count_bytes TSRMLS_DC); /* read POST data */    char *(*read_cookies)(TSRMLS_D);    /* read Cookies */     /* register server variables */    void (*register_server_variables)(zval *track_vars_array TSRMLS_DC);     void (*log_message)(char *message);     /* Log message */    time_t (*get_request_time)(TSRMLS_D);   /* Request Time */    void (*terminate_process)(TSRMLS_D);    /* Child Terminate */     char *php_ini_path_override;    //  覆蓋的ini路徑     ...    ...};

以上的這些結構在各伺服器的介面實現中都有定義。如Apache2的定義:

static sapi_module_struct apache2_sapi_module = {    "apache2handler",    "Apache 2.0 Handler",     php_apache2_startup,                /* startup */    php_module_shutdown_wrapper,            /* shutdown */     ...}

目前PHP內建的很多SAPI實現都已不再維護或者變的有些非主流了,PHP社區目前正在考慮將一些SAPI移出程式碼程式庫。 社區對很多功能的考慮是除非真的非常必要,或者某些功能已近非常通用了,否則就在PECL庫中, 例如非常流行的APC緩衝擴充將進入核心程式碼程式庫中。

整個SAPI類似於一個物件導向中的模板方法模式的應用。 SAPI.c和SAPI.h檔案所包含的一些函數就是模板方法模式中的抽象模板, 各個伺服器對於sapi_module的定義及相關實現則是一個個具體的模板。

這樣的結構在PHP的源碼中有多處使用, 比如在PHP擴充開發中,每個擴充都需要定義一個zend_module_entry結構體。 這個結構體的作用與sapi_module_struct結構體類似,都是一個類似模板方法模式的應用。 在PHP的生命週期中如果需要調用某個擴充,其調用的方法都是zend_module_entry結構體中指定的方法, 如在上一小節中提到的在執行各個擴充的請求初始化時,都是統一調用request_startup_func方法, 而在每個擴充的定義時,都通過宏PHP_RINIT指定request_startup_func對應的函數。 以VLD擴充為例:其請求初始化為PHP_RINIT(vld),與之對應在擴充中需要有這個函數的實現:

PHP_RINIT_FUNCTION(vld) {}

所以, 我們在寫擴充時也需要實現擴充的這些介面,同樣,當實現各伺服器介面時也需要實現其對應的SAPI。

8.PHP核心探索:再次探討SAPI

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.