程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> PHP基礎知識 >> Php源碼 — php

Php源碼 — php

編輯:PHP基礎知識
 

今天在詳細介紹下php_module_startup 。

從php module startup 的字面就知道是PHP初始化。

各個SAPI啟動,會調用php_module_startup這個函數,例如之前提到的fast-cig.

php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_modules, uint num_additional_modules)
這個函數的啟動需要傳入

sapi_module_struct
zend_module_entry *additional_modules
uint num_additional_modules

sapi_module_struct 就是每個執行模式內部定義結構。 如果各位有能力寫執行模式,也需要按照這個規則,寫_sapi_module_struct。規則如下:

2014-09-10 08:53:34的屏幕截圖

2014-09-10 08:54:06的屏幕截圖

上面2張圖分別是cli 和fast-cgi 的sapi module struct。

zend_module_entry 這個struct 寫過模塊的朋友就更加熟悉了。直接看代碼:

上面2張圖分別是cli 和fast-cgi 的sapi module struct。
  
zend_module_entry 這個struct 寫過模塊的朋友就更加熟悉了。直接看代碼:

  /* {{{ kerphp_module_entry
   */
  zend_module_entry kerphp_module_entry = {
  #if ZEND_MODULE_API_NO >= 20010901
   STANDARD_MODULE_HEADER,
  #endif
   "kerphp",
   kerphp_functions,
   PHP_MINIT(kerphp),
   PHP_MSHUTDOWN(kerphp),
   PHP_RINIT(kerphp),
   PHP_RSHUTDOWN(kerphp),
   PHP_MINFO(kerphp),
  #if ZEND_MODULE_API_NO >= 20010901
   "0.1",
  #endif
   STANDARD_MODULE_PROPERTIES
  };
  /* }}} */
  
  #ifdef COMPILE_DL_KERPHP
  ZEND_GET_MODULE(kerphp)
  #endif
 
 
順便做下宣傳,kerphp 這個是我在11年寫的PHP框架。簡單解讀下這個module_entry 。
  
一句土話概括:這個框架(或extension)名字叫kerphp,裡面有kerphp_functions定義的一組方法,同時有PHP_MINIT、PHP_MSHUTDOWN、PHP_RINIT、PHP_RSHUTDOWN這幾個生命周期,和PHP_MINFO這個愛在phpinfo裡炫耀 support enable的家伙。
  
接下sapi 就初始化 並且置空請求 —– 強烈建議千萬別理解成清空。

  SAPI_API void sapi_initialize_empty_request(TSRMLS_D)
  {
   SG(server_context) = NULL;
   SG(request_info).request_method = NULL;
   SG(request_info).auth_digest = SG(request_info).auth_user = SG(request_info).auth_password = NULL;
   SG(request_info).content_type_dup = NULL;
  }
繼續 激活 sapi_activate

  SAPI_API void sapi_activate(TSRMLS_D)
  {
   zend_llist_init(&SG(sapi_headers).headers, sizeof(sapi_header_struct), (void (*)(void *)) sapi_free_header, 0);
   SG(sapi_headers).send_default_content_type = 1;
  
   /*
   SG(sapi_headers).http_response_code = 200;
   */
   SG(sapi_headers).http_status_line = NULL;
   SG(sapi_headers).mimetype = NULL;
   SG(headers_sent) = 0;
   SG(callback_run) = 0;
   SG(callback_func) = NULL;
   SG(read_post_bytes) = 0;
   SG(request_info).request_body = NULL;
   SG(request_info).current_user = NULL;
   SG(request_info).current_user_length = 0;
   SG(request_info).no_headers = 0;
   SG(request_info).post_entry = NULL;
   SG(request_info).proto_num = 1000; /* Default to HTTP 1.0 */
   SG(global_request_time) = 0;
   SG(post_read) = 0;
   /* It's possible to override this general case in the activate() callback, if necessary. */
   if (SG(request_info).request_method && !strcmp(SG(request_info).request_method, "HEAD")) {
   SG(request_info).headers_only = 1;
   } else {
   SG(request_info).headers_only = 0;
   }
   SG(rfc1867_uploaded_files) = NULL;
  
   /* Handle request method */
   if (SG(server_context)) {
   if (PG(enable_post_data_reading)
   && SG(request_info).content_type
   && SG(request_info).request_method
   && !strcmp(SG(request_info).request_method, "POST")) {
   /* HTTP POST may contain form data to be processed into variables
   * depending on given content type */
   sapi_read_post_data(TSRMLS_C);
   } else {
   SG(request_info).content_type_dup = NULL;
   }
  
   /* Cookies */
   SG(request_info).cookie_data = sapi_module.read_cookies(TSRMLS_C);
  
   if (sapi_module.activate) {
   sapi_module.activate(TSRMLS_C);
   }
   }
   if (sapi_module.input_filter_init) {
   sapi_module.input_filter_init(TSRMLS_C);
   }
  }
  
看這個的結構體 要配合 下面的一起看

typedef struct _sapi_globals_struct {
void *server_context;
sapi_request_info request_info;
sapi_headers_struct sapi_headers;
int64_t read_post_bytes;
unsigned char post_read;
unsigned char headers_sent;
struct stat global_stat;
char *default_mimetype;
char *default_charset;
HashTable *rfc1867_uploaded_files;
long post_max_size;
int options;
zend_bool sapi_started;
double global_request_time;
HashTable known_post_content_types;
zval *callback_func;
zend_fcall_info_cache fci_cache;
zend_bool callback_run;} sapi_globals_struct;
SG(sapi_headers) 就是 sapi_globals_struct 裡的 sapi_headers_struct sapi_headers;

以此類推。

提供下 sapi_activate(TSRMLS_D) 這個過程,每次http requrest請求 都會執行。

這個函數裡面還有一個重要的地方需要解讀,
 

&& !strcmp(SG(request_info).request_method, "POST")) {
  sapi_read_post_data(TSRMLS_C);
 
就是如果http請求是post方法的話 那麼回去執行 單獨的獲取post數據。

哈哈,那麼你是不是覺得post從理論源頭回比get慢一些呢?

好像有點,當然可以胡率不計。

總之這個函數內會進行http 的數據構造 如請求方法、get/post數據獲取、cookie、header等等。

接著回到 php_module_startup 。

開始系列的注冊常量
 

REGISTER_MAIN_STRINGL_CONSTANT/REGISTER_MAIN_LONG_CONSTANT
 
例如:
 

REGISTER_MAIN_STRINGL_CONSTANT("PHP_VERSION", PHP_VERSION, sizeof(PHP_VERSION)-1, CONST_PERSISTENT | CONST_CS);
REGISTER_MAIN_LONG_CONSTANT("PHP_MAJOR_VERSION", PHP_MAJOR_VERSION, CONST_PERSISTENT | CONST_CS);
 
這個就是為什麼你能輸出PHP內置常量的原因
 

<?php
echo PHP_MAJOR_VERSION;?>
 
接著是我認為在中國面試很無聊的一個問題:

說說PHP在何時讀取php.ini/或何時載入php.ini?

這個其實是在小小面試桌前很無趣的一道題目,考官估計也半知半解抄來的。

/main/php_ini.c

int php_init_config(TSRMLS_D)

這時候開始進行php.ini 的讀取

讀取過程
1 定義php_ini_file_name 名稱
2 定義 php_ini_search_path 搜索路徑
3 通過 zend_parse_ini_file 解析ini文件

載入擴展的2個宏定義
 

#define PHP_EXTENSION_TOKEN "extension"#define ZEND_EXTENSION_TOKEN "zend_extension"
 
這就是為什麼php.ini 裡面要這麼寫的加載擴展原因
(回頭在詳細php.ini的解析過程)

接著 通過 php_register_extensions_bc 注冊cig-fcgi。
 

static int php_register_extensions_bc(zend_module_entry *ptr, int count TSRMLS_DC){
while (count--) {
if (zend_register_internal_module(ptr++ TSRMLS_CC) == NULL) {
return FAILURE;
}
}
return SUCCESS;}
 
大家可以用如下代碼測試
 

FILE *fhd;static int php_register_extensions_bc(zend_module_entry *ptr, int count TSRMLS_DC){
  fhd=fopen("/log/php_register_extensions_bc.txt","a");
while (count--) {
  fwrite(ptr->name,strlen(ptr->name),1,fhd);
if (zend_register_internal_module(ptr++ TSRMLS_CC) == NULL) {
return FAILURE;
}
} fclose(fhd);
return SUCCESS;}
 
唠叨下:

源碼閱讀我建議用fwrite寫文件的方式來做跟蹤。

接著注冊ini裡定義的php 擴展

php_ini_register_extensions(TSRMLS_C);
 

void php_ini_register_extensions(TSRMLS_D){
zend_llist_apply(&extension_lists.engine, php_load_zend_extension_cb TSRMLS_CC);
zend_llist_apply(&extension_lists.functions, php_load_php_extension_cb TSRMLS_CC);

zend_llist_destroy(&extension_lists.engine);
zend_llist_destroy(&extension_lists.functions);}
 
主要通過 , php_load_php_extension_cb 回掉函數挨個加載
 

static void php_load_php_extension_cb(void *arg TSRMLS_DC){#ifdef HAVE_LIBDL
php_load_extension(*((char **) arg), MODULE_PERSISTENT, 0 TSRMLS_CC);#endif}
 
接著根據php.ini 啟動禁用的配置
 

php_disable_functions(TSRMLS_C);
php_disable_classes(TSRMLS_C);
 

 
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved