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
}
}