zoukankan      html  css  js  c++  java
  • php 连接字符串. ZEND_ASSIGN_CONCAT/ZEND_CONCAT原理

    0.php代码

    <?php
    $a='abc';
    $b='def';
    $c='ghi';
    $d='jkl';
    $a.=$b.$c.$d;

    1.BNF范式(语法规则)

    expr_without_variable:
    |    variable T_CONCAT_EQUAL expr    { zend_check_writable_variable(&$1); zend_do_end_variable_parse(&$1, BP_VAR_RW, 0 TSRMLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_CONCAT, &$$, &$1, &$3 TSRMLS_CC); }
    
    |    expr '.' expr     { zend_do_binary_op(ZEND_CONCAT, &$$, &$1, &$3 TSRMLS_CC); }

    2.生成opcode

    void zend_do_binary_assign_op(zend_uchar op, znode *result, const znode *op1, const znode *op2 TSRMLS_DC) /* {{{ */
    {
        int last_op_number = get_next_op_number(CG(active_op_array));
        zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
    
        if (last_op_number > 0) { //这一段不知道什么意思
            zend_op *last_op = &CG(active_op_array)->opcodes[last_op_number-1];
    
            switch (last_op->opcode) {
                case ZEND_FETCH_OBJ_RW:
                    last_op->opcode = op;
                    last_op->extended_value = ZEND_ASSIGN_OBJ;
    
                    zend_do_op_data(opline, op2 TSRMLS_CC);
                    SET_UNUSED(opline->result);
                    GET_NODE(result, last_op->result);
                    return;
                case ZEND_FETCH_DIM_RW:
                    last_op->opcode = op;
                    last_op->extended_value = ZEND_ASSIGN_DIM;
    
                    zend_do_op_data(opline, op2 TSRMLS_CC);
                    opline->op2.var = get_temporary_variable(CG(active_op_array));
                    opline->op2_type = IS_VAR;
                    SET_UNUSED(opline->result);
                    GET_NODE(result,last_op->result);
                    return;
                default:
                    break;
            }
        }
    
        opline->opcode = op;
        SET_NODE(opline->op1, op1);
        SET_NODE(opline->op2, op2);
        opline->result_type = IS_VAR;
        opline->result.var = get_temporary_variable(CG(active_op_array));
        GET_NODE(result, opline->result);
    }
    #define SET_NODE(target, src) do { 
            target ## _type = (src)->op_type; 
            if ((src)->op_type == IS_CONST) { 
                target.constant = zend_add_literal(CG(active_op_array), &(src)->u.constant TSRMLS_CC); 
            } else { 
                target = (src)->u.op; 
            } 
        } while (0)

    3.执行opcode

    static int ZEND_FASTCALL  ZEND_ASSIGN_CONCAT_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
    {
        return zend_binary_assign_op_helper_SPEC_CV_TMP(concat_function, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
    }
    
    static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_CV_TMP(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS)
    {
        USE_OPLINE
        zend_free_op free_op2, free_op_data2, free_op_data1;
        zval **var_ptr;
        zval *value;
    
        SAVE_OPLINE();
        switch (opline->extended_value) {
            case ZEND_ASSIGN_OBJ:
                ..........break;
            case ZEND_ASSIGN_DIM: {
                 .........
                }
                break;
            default:
                value = _get_zval_ptr_tmp(opline->op2.var, EX_Ts(), &free_op2 TSRMLS_CC);
                var_ptr = _get_zval_ptr_ptr_cv_BP_VAR_RW(EX_CVs(), opline->op1.var TSRMLS_CC);
                /* do nothing */
                break;
        }
    
        if (UNEXPECTED(var_ptr == NULL)) {
            zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets");
        }
    
        if (UNEXPECTED(*var_ptr == &EG(error_zval))) {
            ...........
            ZEND_VM_NEXT_OPCODE();
        }
    
        SEPARATE_ZVAL_IF_NOT_REF(var_ptr);
    
        if (UNEXPECTED(Z_TYPE_PP(var_ptr) == IS_OBJECT)
           && Z_OBJ_HANDLER_PP(var_ptr, get)
           && Z_OBJ_HANDLER_PP(var_ptr, set)) {
            /* proxy object */
           //对象的操作
        } else {
            binary_op(*var_ptr, *var_ptr, value TSRMLS_CC);//故意设置第一个参数与第二个参数一样
        }
    
        ...........
        zval_dtor(free_op2.var);
        ...........
        ZEND_VM_NEXT_OPCODE();
    }
    typedef int (*binary_op_type)(zval *, zval *, zval * TSRMLS_DC);

     

    执行$a.$b时,执行concat_function,第一个参数为一个临时变量(类型为zval), 执行函数后,这个临时变量即保存了concat后的字符串的首地址,然后这个临时变量会放到yyvsp这个数组里,当再移进.$c后,归约成exp.exp,取出这个临时变量作为函数concat_function的第二个参数,$c作为第三个参数 , 执行concat_funcion,将第一个参数的值放回yyvsp

    static int ZEND_FASTCALL  ZEND_CONCAT_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
    {
        USE_OPLINE
    
    
        SAVE_OPLINE();
        concat_function(&EX_T(opline->result.var).tmp_var,
            opline->op1.zv,
            _get_zval_ptr_cv_BP_VAR_R(EX_CVs(), opline->op2.var TSRMLS_CC) TSRMLS_CC);
    
    
        CHECK_EXCEPTION();
        ZEND_VM_NEXT_OPCODE();
    }
    ZEND_API int concat_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
    {
        zval op1_copy, op2_copy;
        int use_copy1 = 0, use_copy2 = 0;
    
        if (Z_TYPE_P(op1) != IS_STRING) {
            zend_make_printable_zval(op1, &op1_copy, &use_copy1);
        }
        if (Z_TYPE_P(op2) != IS_STRING) {
            zend_make_printable_zval(op2, &op2_copy, &use_copy2);
        }
    
        if (use_copy1) {
            /* We have created a converted copy of op1. Therefore, op1 won't become the result so
             * we have to free it.
             */
            if (result == op1) {
                zval_dtor(op1);
            }
            op1 = &op1_copy;
        }
        if (use_copy2) {
            op2 = &op2_copy;
        }
        if (result==op1 && !IS_INTERNED(Z_STRVAL_P(op1))) {    /* special case, perform operations on result */
            uint res_len = Z_STRLEN_P(op1) + Z_STRLEN_P(op2);
    
            if (Z_STRLEN_P(result) < 0 || (int) (Z_STRLEN_P(op1) + Z_STRLEN_P(op2)) < 0) {
                efree(Z_STRVAL_P(result));
                ZVAL_EMPTY_STRING(result);
                zend_error(E_ERROR, "String size overflow");
            }
    
            Z_STRVAL_P(result) = erealloc(Z_STRVAL_P(result), res_len+1);//realloc在紧接原来内存后面,开僻一块内存,如果没有足够内存,重新找一块内存
    
            memcpy(Z_STRVAL_P(result)+Z_STRLEN_P(result), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
            Z_STRVAL_P(result)[res_len]=0;
            Z_STRLEN_P(result) = res_len;
        } else {
            int length = Z_STRLEN_P(op1) + Z_STRLEN_P(op2);
            char *buf = (char *) emalloc(length + 1);//重新malloc分配内存
    
            memcpy(buf, Z_STRVAL_P(op1), Z_STRLEN_P(op1));
            memcpy(buf + Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
            buf[length] = 0;
            ZVAL_STRINGL(result, buf, length, 0);
        }
        if (use_copy1) {
            zval_dtor(op1);
        }
        if (use_copy2) {
            zval_dtor(op2);
        }
        return SUCCESS;
    }
  • 相关阅读:
    PHP 实现无限极栏目分类
    CI 中css样式或者js样式加载不进来的情况
    php 写model层
    Struts1 中$ 没有解析的问题
    App设计相关网站
    如何知道 win10 的激活到期时间和期限等
    dev XtraMessageBox按钮显示中文
    静电的ui教程
    从零开始做UI-静电的sketch设计教室 视频教程
    SQL Server2005作业执行失败的解决办法
  • 原文地址:https://www.cnblogs.com/taek/p/4120910.html
Copyright © 2011-2022 走看看