typedef struct _zval_struct zval;
typedef struct _zend_class_entry zend_class_entry;
typedef union _zvalue_value {
long lval; /* long value */
double dval; /* double value */
struct {
char *val;
int len;
} str;
HashTable *ht; /* hash table value */
struct {
zend_class_entry *ce;
HashTable *properties;
} obj;
} zvalue_value;
struct _zval_struct {
/* Variable information */
zvalue_value value; /* value */
zend_uchar type; /* active type 見3*/
zend_uchar is_ref; /*是否為引用*/
zend_ushort refcount;
};
(zend.h 208行)
上面的union _zvalue_value就是定義的聯合體。它里面包含了常見的long、double,字符串型(以結構體的方式,分別有字符串首地址,字符串長度)、哈希表、類結構體(object)根據用戶不同的賦值,該容器對處理的外部變量呈現不同的類型。zend將外部變量的值,type,是否被引用,引用計數等信息就存儲在封裝的_zval_struct結構體中。這就是為什么php可以不用在需要使用變量的時候,不用先定義可以直接用的原因。
好,現在回來繼續看xhprof.c文件。
PHP_FUNCTION(xhprof_enable) {
long xhprof_flags = 0; /* XHProf flags */
zval *optional_array = NULL; /* optional array arg: for future use */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
"|lz", &xhprof_flags, &optional_array) == FAILURE) {
return;
}
hp_get_ignored_functions_from_arg(optional_array);
hp_begin(XHPROF_MODE_HIERARCHICAL, xhprof_flags TSRMLS_CC);
}在這個函數定義中,執行完需要ignore的函數的邏輯之后,進入hp_begin的執行,這個函數的原型為:
static void hp_begin(long level, long xhprof_flags TSRMLS_DC) {
if (!hp_globals.enabled) {
int hp_profile_flag = 1;
hp_globals.enabled = 1;
hp_globals.xhprof_flags = (uint32)xhprof_flags;
/* Replace zend_compile with our proxy */
_zend_compile_file = zend_compile_file;
zend_compile_file = hp_compile_file;
/* Replace zend_execute with our proxy */
_zend_execute = zend_execute;
zend_execute = hp_execute;
/* Replace zend_execute_internal with our proxy */
_zend_execute_internal = zend_execute_internal;
if (!(hp_globals.xhprof_flags & XHPROF_FLAGS_NO_BUILTINS)) {
/* if NO_BUILTINS is not set (i.e. user wants to profile builtins),
* then we intercept internal (builtin) function calls.
*/
zend_execute_internal = hp_execute_internal;
}
/* Initialize with the dummy mode first Having these dummy callbacks saves
* us from checking if any of the callbacks are NULL everywhere. */
hp_globals.mode_cb.init_cb = hp_mode_dummy_init_cb;
hp_globals.mode_cb.exit_cb = hp_mode_dummy_exit_cb;
hp_globals.mode_cb.begin_fn_cb = hp_mode_dummy_beginfn_cb;
hp_globals.mode_cb.end_fn_cb = hp_mode_dummy_endfn_cb;
/* Register the appropriate callback functions Override just a subset of
* all the callbacks is OK. */
switch(level) {
case XHPROF_MODE_HIERARCHICAL:
hp_globals.mode_cb.begin_fn_cb = hp_mode_hier_beginfn_cb;
hp_globals.mode_cb.end_fn_cb = hp_mode_hier_endfn_cb;
break;
case XHPROF_MODE_SAMPLED:
...(后面的函數內容都大同小異,就不再全部貼上來了,有興趣的可以到xhprof/extension里面去查看xhprof.c)
這里可以看到
if (!hp_globals.enabled) {...如果xhprof的enable為打開的狀態,則進入該分支流程,下面做了對應的對zend的處理方法的replace,比如,zend_compile_file,zend_execute,zend_execute_internal etc。而這些zend的方法作用分別是完成文件的compile和execute、后面帶有internal的是對內部函數的執行。xhprof就是通過對zend的內部函數的replace,然后在對應的zend處理函數中進行所需要的數據的抓取和存儲,這個可以在被replace之后的hp_execute (zend_op_array *ops TSRMLS_DC) 里面看到
BEGIN_PROFILING(&hp_globals.entries, func, hp_profile_flag);之后就是進入了xhprof本身的自定義的一些任務的開始了,比如初始化一些內存空間來做好后面需要抓取的數據的存儲,對于抓取到的profiling data的數據的處理等
在最后結束的時候(也就是disable的時候)
xhprof通過
/* Remove proxies, restore the originals */
zend_execute = _zend_execute;
zend_execute_internal = _zend_execute_internal;
zend_compile_file = _zend_compile_file;
對清理掉xhprof對zend的相關三個函數的proxies,從而關閉了xhprof對php代碼執行的數據的收集工作。大體上就是這么多
由于本身能力有限,所以當中不免會引入一些錯誤和不足,誠邀您對當中的不足、錯誤之處進行補充和指出,謝謝
原文轉自:http://blog.csdn.net/yzongyu/article/details/8457209