php 連接字串. ZEND_ASSIGN_CONCAT/ZEND_CONCAT原理

來源:互聯網
上載者:User

標籤:des   style   blog   io   ar   color   sp   for   strong   

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 連接字串. ZEND_ASSIGN_CONCAT/ZEND_CONCAT原理

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.