intval opcode

intval.php

<?php 
$a = '10';
echo intval($a);

[root@localhost ~]# php -dvld.active=1 intval.php 
Finding entry points
Branch analysis from position: 0
Jump found. (Code = 62) Position 1 = -2
filename:       /root/intval.php
function name:  (null)
number of ops:  6
compiled vars:  !0 = $a
line     #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   2     0  E >   ASSIGN                                                   !0, '10'
   3     1        INIT_FCALL                                               'intval'
         2        SEND_VAR                                                 !0
         3        DO_ICALL                                         $2      
         4        ECHO                                                     $2
         5      > RETURN                                                   1

branch: #  0; line:     2-    3; sop:     0; eop:     5; out1:  -2
path #1: 0, 
10

intval源码

PHP_FUNCTION(intval)
{
    zval **num;
    long arg_base;
    int base;

    switch (ZEND_NUM_ARGS()) {
        case 1:
            if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &num) == FAILURE) {
                return;
            }
            base = 10;
            break;

        case 2:
            if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl", &num, &arg_base) == FAILURE) {
                return;
            }
            base = arg_base;
            break;

        default:
            WRONG_PARAM_COUNT;
    }

    RETVAL_ZVAL(*num, 1, 0);
    convert_to_long_base(return_value, base); //最终调用了此函数
}



ZEND_API void convert_to_long_base(zval *op, int base) /* {{{ */
{
    long tmp;

    switch (Z_TYPE_P(op)) {
        case IS_NULL:
            Z_LVAL_P(op) = 0;
            break;
        case IS_RESOURCE: {
                TSRMLS_FETCH();

                zend_list_delete(Z_LVAL_P(op));
            }
            /* break missing intentionally */
        case IS_BOOL:
        case IS_LONG:
            break;
        case IS_DOUBLE:
            Z_LVAL_P(op) = zend_dval_to_lval(Z_DVAL_P(op));
            break;
        case IS_STRING:
            {
                char *strval = Z_STRVAL_P(op);

                Z_LVAL_P(op) = strtol(strval, NULL, base);
                STR_FREE(strval);
            }
            break;
        case IS_ARRAY:
            tmp = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0);
            zval_dtor(op);
            Z_LVAL_P(op) = tmp;
            break;
        case IS_OBJECT:
            {
                int retval = 1;
                TSRMLS_FETCH();

                convert_object_to_type(op, IS_LONG, convert_to_long);

                if (Z_TYPE_P(op) == IS_LONG) {
                    return;
                }
                zend_error(E_NOTICE, "Object of class %s could not be converted to int", Z_OBJCE_P(op)->name);

                zval_dtor(op);
                ZVAL_LONG(op, retval);
                return;
            }
        default:
            zend_error(E_WARNING, "Cannot convert to ordinal value");
            zval_dtor(op);
            Z_LVAL_P(op) = 0;
            break;
    }

    Z_TYPE_P(op) = IS_LONG;
}

int opcode

int.php

<?php  
$a='10';
echo (int)$a;

[root@localhost ~]# php -dvld.active=1 int.php 
Finding entry points
Branch analysis from position: 0
Jump found. (Code = 62) Position 1 = -2
filename:       /root/int.php
function name:  (null)
number of ops:  4
compiled vars:  !0 = $a
line     #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   2     0  E >   ASSIGN                                                   !0, '10'
   3     1        CAST                                          4  ~2      !0
         2        ECHO                                                     ~2
         3      > RETURN                                                   1

branch: #  0; line:     2-    3; sop:     0; eop:     3; out1:  -2
path #1: 0, 
10

int 定义源码


1.词法分析 <ST_IN_SCRIPTING>"("{TABS_AND_SPACES}("int"|"integer"){TABS_AND_SPACES}")" { return T_INT_CAST; } 2.词法分析 %token T_INT_CAST "(int) (T_INT_CAST)" expr_without_variable: T_LIST '(' { zend_do_list_init(TSRMLS_C); } assignment_list ')' '=' expr { zend_do_list_end(&$$, &$7 TSRMLS_CC); } | variable '=' expr { zend_check_writable_variable(&$1); zend_do_assign(&$$, &$1, &$3 TSRMLS_CC); } | variable '=' '&' variable { zend_check_writable_variable(&$1); zend_do_end_variable_parse(&$4, BP_VAR_W, 1 TSRMLS_CC); zend_do_end_variable_parse(&$1, BP_VAR_W, 0 TSRMLS_CC); zend_do_assign_ref(&$$, &$1, &$4 TSRMLS_CC); } | variable '=' '&' T_NEW class_name_reference { zend_error(E_DEPRECATED, "Assigning the return value of new by reference is deprecated"); zend_check_writable_variable(&$1); zend_do_extended_fcall_begin(TSRMLS_C); zend_do_begin_new_object(&$4, &$5 TSRMLS_CC); } ctor_arguments { zend_do_end_new_object(&$3, &$4, &$7 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); zend_do_end_variable_parse(&$1, BP_VAR_W, 0 TSRMLS_CC); $3.EA = ZEND_PARSED_NEW; zend_do_assign_ref(&$$, &$1, &$3 TSRMLS_CC); } | T_CLONE expr { zend_do_clone(&$$, &$2 TSRMLS_CC); } | variable T_PLUS_EQUAL expr { zend_check_writable_variable(&$1); | expr '|' expr { zend_do_binary_op(ZEND_BW_OR, &$$, &$1, &$3 TSRMLS_CC); } | expr '&' expr { zend_do_binary_op(ZEND_BW_AND, &$$, &$1, &$3 TSRMLS_CC); } | expr '^' expr { zend_do_binary_op(ZEND_BW_XOR, &$$, &$1, &$3 TSRMLS_CC); } | expr '.' expr { zend_do_binary_op(ZEND_CONCAT, &$$, &$1, &$3 TSRMLS_CC); } | expr '+' expr { zend_do_binary_op(ZEND_ADD, &$$, &$1, &$3 TSRMLS_CC); } | expr '-' expr { zend_do_binary_op(ZEND_SUB, &$$, &$1, &$3 TSRMLS_CC); } | expr '*' expr { zend_do_binary_op(ZEND_MUL, &$$, &$1, &$3 TSRMLS_CC); } | expr '/' expr { zend_do_binary_op(ZEND_DIV, &$$, &$1, &$3 TSRMLS_CC); } | '+' expr %prec T_INC { ZVAL_LONG(&$1.u.constant, 0); if ($2.op_type == IS_CONST) { add_function(&$2.u.constant, &$1.u.constant, &$2.u.constant TSRMLS_CC); $$ = $2; } else { $1.op_type = IS_CONST; INIT_PZVAL(&$1.u.constant); zend_do_binary_op(ZEND_ADD, &$$, &$1, &$2 TSRMLS_CC); } } | '-' expr %prec T_INC { ZVAL_LONG(&$1.u.constant, 0); if ($2.op_type == IS_CONST) { sub_function(&$2.u.constant, &$1.u.constant, &$2.u.constant TSRMLS_CC); $$ = $2; } else { $1.op_type = IS_CONST; INIT_PZVAL(&$1.u.constant); zend_do_binary_op(ZEND_SUB, &$$, &$1, &$2 TSRMLS_CC); } } | '!' expr { zend_do_unary_op(ZEND_BOOL_NOT, &$$, &$2 TSRMLS_CC); } | expr '?' { zend_do_begin_qm_op(&$1, &$2 TSRMLS_CC); } expr ':' { zend_do_qm_true(&$4, &$2, &$5 TSRMLS_CC); } expr { zend_do_qm_false(&$$, &$7, &$2, &$5 TSRMLS_CC); } | expr '?' ':' { zend_do_jmp_set(&$1, &$2, &$3 TSRMLS_CC); } expr { zend_do_jmp_set_else(&$$, &$5, &$2, &$3 TSRMLS_CC); } | internal_functions_in_yacc { $$ = $1; } //(int)$a 的语法分析 ,调用了 zend_do_cast | T_INT_CAST expr { zend_do_cast(&$$, &$2, IS_LONG TSRMLS_CC); } | T_DOUBLE_CAST expr { zend_do_cast(&$$, &$2, IS_DOUBLE TSRMLS_CC); } | T_STRING_CAST expr { zend_do_cast(&$$, &$2, IS_STRING TSRMLS_CC); } | T_ARRAY_CAST expr { zend_do_cast(&$$, &$2, IS_ARRAY TSRMLS_CC); } | T_OBJECT_CAST expr { zend_do_cast(&$$, &$2, IS_OBJECT TSRMLS_CC); } | T_BOOL_CAST expr { zend_do_cast(&$$, &$2, IS_BOOL TSRMLS_CC); } | T_UNSET_CAST expr { zend_do_cast(&$$, &$2, IS_NULL TSRMLS_CC); } | T_EXIT exit_expr { zend_do_exit(&$$, &$2 TSRMLS_CC); } | T_OBJECT_CAST expr { zend_do_cast(&$$, &$2, IS_OBJECT TSRMLS_CC); } 3.设置opcode void zend_do_cast(znode *result, const znode *expr, int type TSRMLS_DC) /* {{{ */ { zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_CAST; opline->result_type = IS_TMP_VAR; opline->result.var = get_temporary_variable(CG(active_op_array)); SET_NODE(opline->op1, expr); SET_UNUSED(opline->op2); opline->extended_value = type; GET_NODE(result, opline->result); } 4. ZEND_CAST opcode 映射函数 static int ZEND_FASTCALL ZEND_CAST_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zval *expr; zval *result = &EX_T(opline->result.var).tmp_var; SAVE_OPLINE(); expr = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC); if (opline->extended_value != IS_STRING) { ZVAL_COPY_VALUE(result, expr); if (!0) { zendi_zval_copy_ctor(*result); } } switch (opline->extended_value) { case IS_NULL: convert_to_null(result); break; case IS_BOOL: convert_to_boolean(result); break; case IS_LONG: convert_to_long(result); //调用了此函数 break; case IS_DOUBLE: convert_to_double(result); break; case IS_STRING: { zval var_copy; int use_copy; zend_make_printable_zval(expr, &var_copy, &use_copy); if (use_copy) { ZVAL_COPY_VALUE(result, &var_copy); if (0) { } } else { ZVAL_COPY_VALUE(result, expr); if (!0) { zendi_zval_copy_ctor(*result); } } break; } case IS_ARRAY: convert_to_array(result); break; case IS_OBJECT: convert_to_object(result); break; } CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } 5. ZEND_API void convert_to_long(zval *op) /* {{{ */ { if (Z_TYPE_P(op) != IS_LONG) { convert_to_long_base(op, 10); //发现最后也调用了convert_to_long_base } }

Comments are closed.

Post Navigation