• php脚本cli 模式运行


    参考文章 http://rapheal.sinaapp.com/2013/11/20/php_zend_hello_world/

        http://www.douban.com/note/337885681/

     5.3 与以前版本的不同 http://my.oschina.net/mickelfeng/blog/201382

    php添加新语法  http://www.it165.net/pro/html/201208/3477.html

            http://nikic.github.io/2012/07/27/How-to-add-new-syntactic-features-to-PHP.html

            http://zsong.me/posts/1

            http://www.laruence.com/2009/02/21/662.html

            http://www.verydemo.com/cm.jsp?c=14&u=shen-ru-li-jie-php-yuan-li-zhi

            http://bbs.phpchina.com/thread-100825-1-1.html

     

    static http://www.nowamagic.net/librarys/veda/detail/1402

    cli方式运行php脚本

     

    $PHPSRC/sapi/cli/php_cli.c中的do_cli函数里边接收了命令行的参数输入

    zend_execute_scripts()  $PHPSRC/main/main.c里边有定义

     EG(active_op_array) = zend_compile_file(file_handle, type TSRMLS_CC);
    zend_execute(EG(active_op_array) TSRMLS_CC);

     

    通过zend_compile_file(实际上为compile_file()<定义在Zend/zend_language_scanner.c的555行>)把脚本文件编译出opcode,

    ZEND_API int zend_execute_scripts(int type TSRMLS_DC, zval **retval, int file_count, ...) /* {{{ */
    {
        va_list files;
        int i;
        zend_file_handle *file_handle;
        zend_op_array *orig_op_array = EG(active_op_array);
        zval **orig_retval_ptr_ptr = EG(return_value_ptr_ptr);
        long orig_interactive = CG(interactive);
    
        va_start(files, file_count);
        for (i = 0; i < file_count; i++) {
            file_handle = va_arg(files, zend_file_handle *);
            if (!file_handle) {
                continue;
            }
    
            if (orig_interactive) {
                if (file_handle->filename[0] != '-' || file_handle->filename[1]) {
                    CG(interactive) = 0;
                } else {
                    CG(interactive) = 1;
                }
            }
           
            EG(active_op_array) = zend_compile_file(file_handle, type TSRMLS_CC);
            if (file_handle->opened_path) {
                int dummy = 1;
                zend_hash_add(&EG(included_files), file_handle->opened_path, strlen(file_handle->opened_path) + 1, (void *)&dummy, sizeof(int), NULL);
            }
            zend_destroy_file_handle(file_handle TSRMLS_CC);
            if (EG(active_op_array)) {
                EG(return_value_ptr_ptr) = retval ? retval : NULL;
                zend_execute(EG(active_op_array) TSRMLS_CC);
                zend_exception_restore(TSRMLS_C);
                if (EG(exception)) {
                    if (EG(user_exception_handler)) {
                        zval *orig_user_exception_handler;
                        zval **params[1], *retval2, *old_exception;
                        old_exception = EG(exception);
                        EG(exception) = NULL;
                        params[0] = &old_exception;
                        orig_user_exception_handler = EG(user_exception_handler);
                        if (call_user_function_ex(CG(function_table), NULL, orig_user_exception_handler, &retval2, 1, params, 1, NULL TSRMLS_CC) == SUCCESS) {
                            if (retval2 != NULL) {
                                zval_ptr_dtor(&retval2);
                            }
                            if (EG(exception)) {
                                zval_ptr_dtor(&EG(exception));
                                EG(exception) = NULL;
                            }
                            zval_ptr_dtor(&old_exception);
                        } else {
                            EG(exception) = old_exception;
                            zend_exception_error(EG(exception), E_ERROR TSRMLS_CC);
                        }
                    } else {
                        zend_exception_error(EG(exception), E_ERROR TSRMLS_CC);
                    }
                }
                destroy_op_array(EG(active_op_array) TSRMLS_CC);
                efree(EG(active_op_array));
            } else if (type==ZEND_REQUIRE) {
                va_end(files);
                EG(active_op_array) = orig_op_array;
                EG(return_value_ptr_ptr) = orig_retval_ptr_ptr;
                CG(interactive) = orig_interactive;
                return FAILURE;
            }
        }
        va_end(files);
        EG(active_op_array) = orig_op_array;
        EG(return_value_ptr_ptr) = orig_retval_ptr_ptr;
        CG(interactive) = orig_interactive;
    
        return SUCCESS;
    }
    
    
    zend_compile_file = compile_file;

     

    ZEND_API zend_op_array *compile_file(zend_file_handle *file_handle, int type TSRMLS_DC)
    {
        zend_lex_state original_lex_state;
        zend_op_array *op_array = (zend_op_array *) emalloc(sizeof(zend_op_array));
        zend_op_array *original_active_op_array = CG(active_op_array);
        zend_op_array *retval=NULL;
        int compiler_result;
        zend_bool compilation_successful=0;
        znode retval_znode;
        zend_bool original_in_compilation = CG(in_compilation);
    
        retval_znode.op_type = IS_CONST;
        retval_znode.u.constant.type = IS_LONG;
        retval_znode.u.constant.value.lval = 1;
        Z_UNSET_ISREF(retval_znode.u.constant);
        Z_SET_REFCOUNT(retval_znode.u.constant, 1);
    
        zend_save_lexical_state(&original_lex_state TSRMLS_CC);
    
        retval = op_array; /* success oriented */
    
        if (open_file_for_scanning(file_handle TSRMLS_CC)==FAILURE) {
            if (type==ZEND_REQUIRE) {
                zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename TSRMLS_CC);
                zend_bailout();
            } else {
                zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, file_handle->filename TSRMLS_CC);
            }
            compilation_successful=0;
        } else {
            init_op_array(op_array, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE TSRMLS_CC); //初始化op_array
            CG(in_compilation) = 1;
            CG(active_op_array) = op_array;
            zend_stack_push(&CG(context_stack), (void *) &CG(context), sizeof(CG(context)));
            zend_init_compiler_context(TSRMLS_C);
            compiler_result = zendparse(TSRMLS_C);//对于非函数,都是设置opline的各个属性,对于函数,要额外分配一个op_array
            zend_do_return(&retval_znode, 0 TSRMLS_CC);
            CG(in_compilation) = original_in_compilation;
            if (compiler_result==1) { /* parser error */
                zend_bailout();
            }
            compilation_successful=1;
        }
    
        if (retval) {
            CG(active_op_array) = original_active_op_array;
            if (compilation_successful) {
                pass_two(op_array TSRMLS_CC);//循环遍历op_array中的opcodes,设置每一个opline中的属性hanlder
                zend_release_labels(TSRMLS_C);
            } else {
                efree(op_array);
                retval = NULL;
            }
        }
        zend_restore_lexical_state(&original_lex_state TSRMLS_CC);
        return retval;
    }

     

    ZEND_API void execute(zend_op_array *op_array TSRMLS_DC)
    {
        zend_execute_data *execute_data;
        zend_bool nested = 0;
        zend_bool original_in_execution = EG(in_execution);
    
    
        if (EG(exception)) {
            return;
        }
    
        EG(in_execution) = 1;
    
    zend_vm_enter:
        /* Initialize execute_data */
        execute_data = (zend_execute_data *)zend_vm_stack_alloc(
            ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data)) +
            ZEND_MM_ALIGNED_SIZE(sizeof(zval**) * op_array->last_var * (EG(active_symbol_table) ? 1 : 2)) +
            ZEND_MM_ALIGNED_SIZE(sizeof(temp_variable)) * op_array->T TSRMLS_CC);
    
        EX(CVs) = (zval***)((char*)execute_data + ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data)));
        memset(EX(CVs), 0, sizeof(zval**) * op_array->last_var);
        EX(Ts) = (temp_variable *)(((char*)EX(CVs)) + ZEND_MM_ALIGNED_SIZE(sizeof(zval**) * op_array->last_var * (EG(active_symbol_table) ? 1 : 2)));
        EX(fbc) = NULL;
        EX(called_scope) = NULL;
        EX(object) = NULL;
        EX(old_error_reporting) = NULL;
        EX(op_array) = op_array;
        EX(symbol_table) = EG(active_symbol_table);
        EX(prev_execute_data) = EG(current_execute_data);
        EG(current_execute_data) = execute_data;
        EX(nested) = nested;
        nested = 1;
    
        if (op_array->start_op) {
            ZEND_VM_SET_OPCODE(op_array->start_op);
        } else {
            ZEND_VM_SET_OPCODE(op_array->opcodes);
        }
    
        if (op_array->this_var != -1 && EG(This)) {
            Z_ADDREF_P(EG(This)); /* For $this pointer */
            if (!EG(active_symbol_table)) {
                EX(CVs)[op_array->this_var] = (zval**)EX(CVs) + (op_array->last_var + op_array->this_var);
                *EX(CVs)[op_array->this_var] = EG(This);
            } else {
                if (zend_hash_add(EG(active_symbol_table), "this", sizeof("this"), &EG(This), sizeof(zval *), (void**)&EX(CVs)[op_array->this_var])==FAILURE) {
                    Z_DELREF_P(EG(This));
                }
            }
        }
    
        EG(opline_ptr) = &EX(opline);
    
        EX(function_state).function = (zend_function *) op_array;
        EX(function_state).arguments = NULL;
        
        while (1) {
            int ret;
    #ifdef ZEND_WIN32
            if (EG(timed_out)) {
                zend_timeout(0);
            }
    #endif
    
            if ((ret = EX(opline)->handler(execute_data TSRMLS_CC)) > 0) {
                switch (ret) {
                    case 1:
                        EG(in_execution) = original_in_execution;
                        return;
                    case 2:
                        op_array = EG(active_op_array);
                        goto zend_vm_enter;
                    case 3:
                        execute_data = EG(current_execute_data);
                    default:
                        break;
                }
            }
    
        }
        zend_error_noreturn(E_ERROR, "Arrived at end of main loop which shouldn't happen");
    }

     zendparse (LALR1 将代码分隔成token,再解析后存放在opcode的数组中)

    pass_two解析opcode的每一行,将其handler绑定到op上

    complie之后会得到一个op_array,在execute之前创建一个zend_execute_data的数据结构

    struct _zend_execute_data {
            struct _zend_op *opline;
            zend_function_state function_state;
            zend_op_array *op_array;
            zval *object;
            HashTable *symbol_table;
            struct _zend_execute_data *prev_execute_data;
            zval *old_error_reporting;
            zend_bool nested;
            zval **original_return_value;
            zend_class_entry *current_scope;
            zend_class_entry *current_called_scope;
            zval *current_this;
            struct _zend_op *fast_ret; /* used by FAST_CALL/FAST_RET (finally keyword) */
            call_slot *call_slots;
            call_slot *call;
    };

    在zend_execute中最重要的一句
    ret = OPLINE->handler(execute_data TSRMLS_CC)

    调用在op上绑定的handler,完成对opcode的执行

    //zend_opcode.c

    ZEND_API int pass_two(zend_op_array *op_array TSRMLS_DC)
    {
    zend_op *opline, *end;

    if (op_array->type!=ZEND_USER_FUNCTION && op_array->type!=ZEND_EVAL_CODE) {
    return 0;
    }
    if (CG(compiler_options) & ZEND_COMPILE_EXTENDED_INFO) {
    zend_update_extended_info(op_array TSRMLS_CC);
    }
    if (CG(compiler_options) & ZEND_COMPILE_HANDLE_OP_ARRAY) {
    zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_handler, op_array TSRMLS_CC);
    }

    if (!(op_array->fn_flags & ZEND_ACC_INTERACTIVE) && CG(context).vars_size != op_array->last_var) {
    op_array->vars = (zend_compiled_variable *) erealloc(op_array->vars, sizeof(zend_compiled_variable)*op_array->last_var);
    CG(context).vars_size = op_array->last_var;
    }
    if (!(op_array->fn_flags & ZEND_ACC_INTERACTIVE) && CG(context).opcodes_size != op_array->last) {
    op_array->opcodes = (zend_op *) erealloc(op_array->opcodes, sizeof(zend_op)*op_array->last);
    CG(context).opcodes_size = op_array->last;
    }
    if (!(op_array->fn_flags & ZEND_ACC_INTERACTIVE) && CG(context).literals_size != op_array->last_literal) {
    op_array->literals = (zend_literal*)erealloc(op_array->literals, sizeof(zend_literal) * op_array->last_literal);
    CG(context).literals_size = op_array->last_literal;
    }

    opline = op_array->opcodes;
    end = opline + op_array->last;
    while (opline < end) {
    if (opline->op1_type == IS_CONST) {
    opline->op1.zv = &op_array->literals[opline->op1.constant].constant;
    }
    if (opline->op2_type == IS_CONST) {
    opline->op2.zv = &op_array->literals[opline->op2.constant].constant;
    }
    switch (opline->opcode) {
    case ZEND_GOTO:
    if (Z_TYPE_P(opline->op2.zv) != IS_LONG) {
    zend_resolve_goto_label(op_array, opline, 1 TSRMLS_CC);
    }
    /* break omitted intentionally */
    case ZEND_JMP:
    opline->op1.jmp_addr = &op_array->opcodes[opline->op1.opline_num];
    break;
    case ZEND_JMPZ:
    case ZEND_JMPNZ:
    case ZEND_JMPZ_EX:
    case ZEND_JMPNZ_EX:
    case ZEND_JMP_SET:
    case ZEND_JMP_SET_VAR:
    opline->op2.jmp_addr = &op_array->opcodes[opline->op2.opline_num];
    break;
    }
    ZEND_VM_SET_OPCODE_HANDLER(opline);
    opline++;
    }

    op_array->fn_flags |= ZEND_ACC_DONE_PASS_TWO;
    return 0;
    }

     

    //zend_vm_execute.h

    ZEND_API void zend_vm_set_opcode_handler(zend_op* op)
    {
    op->handler = zend_vm_get_opcode_handler(zend_user_opcodes[op->opcode], op);
    }

     

  • 相关阅读:
    从实验室走向世界:HSP90抑制剂,一种新的癌症药物
    RabbitMQ整合Spring Booot【消费者应答模式】
    RabbitMQ整合Spring Booot【点对点模式】
    Mac删除自带的abc输入法
    Docker搭建Kafka
    IK分词器
    Docker搭建ES集群
    Logstash配置同步mysql到es配置
    ELK分布式日志收集搭建和使用
    Docker安装ES和Kibana
  • 原文地址:https://www.cnblogs.com/taek/p/3844483.html
Copyright © 2020-2023  润新知