php-echo原理

1.語法分析php

 

unticked_statement:
|    T_ECHO echo_expr_list ';'
;
echo_expr_list:
        echo_expr_list ',' expr { zend_do_echo(&$3 TSRMLS_CC); }
    |    expr                    { zend_do_echo(&$1 TSRMLS_CC); }
;
expr:
        r_variable                    { $$ = $1; }
    |    expr_without_variable        { $$ = $1; }
;
r_variable:
    variable { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); $$ = $1; }
;
variable:
        base_variable_with_function_calls
;
base_variable_with_function_calls:
        base_variable                { $$ = $1; }
;
base_variable:
        reference_variable { $$ = $1; $$.EA = ZEND_PARSED_VARIABLE; }
;
reference_variable:
    |    compound_variable            { zend_do_begin_variable_parse(TSRMLS_C); fetch_simple_variable(&$$, &$1, 1 TSRMLS_CC); }
;

compound_variable:
        T_VARIABLE            { $$ = $1; }
    |    '$' '{' expr '}'    { $$ = $3; }
;
    |    compound_variable            { zend_do_begin_variable_parse(TSRMLS_C); fetch_simple_variable(&$$, &$1, 1 TSRMLS_CC); }
;
compound_variable:
        T_VARIABLE            { $$ = $1; }

 

2.編譯生成opcodehtml

void zend_do_echo(const znode *arg TSRMLS_DC) /* {{{ */ { zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_ECHO; SET_NODE(opline->op1, arg); SET_UNUSED(opline->op2); }

 

3.執行已經生成的opcodenode

static int ZEND_FASTCALL ZEND_ECHO_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zval *z; SAVE_OPLINE(); z = _get_zval_ptr_cv_BP_VAR_R(EX_CVs(), opline->op1.var TSRMLS_CC); //這個z已是值了 if (IS_CV == IS_TMP_VAR && Z_TYPE_P(z) == IS_OBJECT) { INIT_PZVAL(z); } zend_print_variable(z); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); }

 

static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_R(zval ***CVs, zend_uint var TSRMLS_DC) { zval ***ptr = &CV(var); //EG(active_op_array).vars[key]該結果是個zend_compile_variable ,其中key爲znod_op的變量var,是個數字,可理解爲第幾個變量,最終在EG(active_sysbole_table)中取出數據,放到EX(CVs)[key]中 if (UNEXPECTED(*ptr == NULL)) { return *_get_zval_cv_lookup_BP_VAR_R(ptr, var TSRMLS_CC); } return **ptr; } static zend_never_inline zval **_get_zval_cv_lookup_BP_VAR_R(zval ***ptr, zend_uint var TSRMLS_DC) { zend_compiled_variable *cv = &CV_DEF_OF(var); if (!EG(active_symbol_table) || zend_hash_quick_find(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, (void **)ptr)==FAILURE) { zend_error(E_NOTICE, "Undefined variable: %s", cv->name); return &EG(uninitialized_zval_ptr); } return *ptr; }

 

ZEND_API int zend_print_variable(zval *var) { return zend_print_zval(var, 0); } ZEND_API int zend_print_zval(zval *expr, int indent) /* {{{ */ { return zend_print_zval_ex(zend_write, expr, indent); } ZEND_API int zend_print_zval_ex(zend_write_func_t write_func, zval *expr, int indent) /* {{{ */ { zval expr_copy; int use_copy; zend_make_printable_zval(expr, &expr_copy, &use_copy); if (use_copy) { expr = &expr_copy; } if (Z_STRLEN_P(expr) == 0) { /* optimize away empty strings */
        if (use_copy) { zval_dtor(expr); } return 0; } write_func(Z_STRVAL_P(expr), Z_STRLEN_P(expr)); if (use_copy) { zval_dtor(expr); } return Z_STRLEN_P(expr); } int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_modules, uint num_additional_modules) { zend_utility_functions zuf; zend_utility_values zuv; int retval = SUCCESS, module_number=0;    /* for REGISTER_INI_ENTRIES() */ 。。。。。。。。。。。。。。 sapi_module = *sf; php_output_startup(); zuf.error_function = php_error_cb; zuf.printf_function = php_printf; zuf.write_function = php_output_wrapper; zuf.fopen_function = php_fopen_wrapper_for_zend; zuf.message_handler = php_message_handler_for_zend; zuf.block_interruptions = sapi_module.block_interruptions; zuf.unblock_interruptions = sapi_module.unblock_interruptions; zuf.get_configuration_directive = php_get_configuration_directive_for_zend; zuf.ticks_function = php_run_ticks; zuf.on_timeout = php_on_timeout; zuf.stream_open_function = php_stream_open_for_zend; zuf.vspprintf_function = vspprintf; zuf.getenv_function = sapi_getenv; zuf.resolve_path_function = php_resolve_path_for_zend; zend_startup(&zuf, NULL TSRMLS_CC);

 

static int php_output_wrapper(const char *str, uint str_length) { TSRMLS_FETCH(); return php_output_write(str, str_length TSRMLS_CC); } PHPAPI int php_output_write(const char *str, size_t len TSRMLS_DC) { if (OG(flags) & PHP_OUTPUT_DISABLED) { return 0; } if (OG(flags) & PHP_OUTPUT_ACTIVATED) { php_output_op(PHP_OUTPUT_HANDLER_WRITE, str, len TSRMLS_CC); return (int) len; } return php_output_direct(str, len); } static int (*php_output_direct)(const char *str, size_t str_len) = php_output_stderr; static int php_output_stderr(const char *str, size_t str_len) { fwrite(str, 1, str_len, stderr); //可知道echo 是用fwrite輸出的 /* See http://support.microsoft.com/kb/190351 */ #ifdef PHP_WIN32 fflush(stderr); #endif
    return str_len; }

 

 參考:http://wenku.baidu.com/view/b7d2d4335a8102d276a22fb1.htmlapi

相關文章
相關標籤/搜索