- array_push で配列の要素足すのと、$array[] = $val で配列の要素足すのと何が違うのかわからんので調べた
- http://pecl.php.net/package/vld を入れると処理系の OPコードを見れる
[vagrant@localhost ~]$ rpm -q php
php-5.3.3-23.el6_4.x86_64
[vagrant@localhost ~]$ php -v
PHP 5.3.3 (cli) (built: Jul 12 2013 20:35:47)
Copyright (c) 1997-2010 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies
<?php
$numbers = array();
array_push($numbers, 100);
array_push($numbers, 200);
array_push($numbers, 300);
$ php -dvld.active=1 test.php
Finding entry points
Branch analysis from position: 0
Return found
filename: /home/vagrant/test.php
function name: (null)
number of ops: 12
compiled vars: !0 = $numbers
line # * op fetch ext return operands
---------------------------------------------------------------------------------
3 0 > INIT_ARRAY ~0
1 ASSIGN !0, ~0
4 2 SEND_REF !0
3 SEND_VAL 100
4 DO_FCALL 2 'array_push'
5 5 SEND_REF !0
6 SEND_VAL 200
7 DO_FCALL 2 'array_push'
6 8 SEND_REF !0
9 SEND_VAL 300
10 DO_FCALL 2 'array_push'
7 11 > RETURN 1
branch: # 0; line: 3- 7; sop: 0; eop: 11
path #1: 0,
- SEND_REF, SEND_VAL, DO_FCALL で 'array_push' を関数呼び出しする
- function_table ハッシュテーブルから関数名探したりとかしてる
ZEND_VM_HANDLER(60, ZEND_DO_FCALL, CONST, ANY)
{
zend_op *opline = EX(opline);
zend_free_op free_op1;
zval *fname = GET_OP1_ZVAL_PTR(BP_VAR_R);
zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
if (zend_hash_quick_find(EG(function_table), fname->value.str.val, fname->value.str.len+1, Z_LVAL(opline->op2.u.constant), (void **) &EX(function_state).function)==FAILURE) {
zend_error_noreturn(E_ERROR, "Call to undefined function %s()", fname->value.str.val);
}
EX(object) = NULL;
FREE_OP1();
ZEND_VM_DISPATCH_TO_HELPER(zend_do_fcall_common_helper);
さらに ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY) に続く様子
<?php
$numbers = array();
$numbers[] = 100;
$numbers[] = 200;
$numbers[] = 300;
Finding entry points
Branch analysis from position: 0
Return found
filename: /home/vagrant/test.php
function name: (null)
number of ops: 9
compiled vars: !0 = $numbers
line # * op fetch ext return operands
---------------------------------------------------------------------------------
3 0 > INIT_ARRAY ~0
1 ASSIGN !0, ~0
4 2 ASSIGN_DIM !0
3 OP_DATA 100, $3
5 4 ASSIGN_DIM !0
5 OP_DATA 200, $5
6 6 ASSIGN_DIM !0
7 OP_DATA 300, $7
7 8 > RETURN 1
branch: # 0; line: 3- 7; sop: 0; eop: 8
path #1: 0,
- ASSIGN_DIM という OPコードで処理されてる
ZEND_VM_HANDLER(147, ZEND_ASSIGN_DIM, VAR|CV, CONST|TMP|VAR|UNUSED|CV)
{
zend_op *opline = EX(opline);
zend_op *op_data = opline+1;
zend_free_op free_op1;
zval **object_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W);
if (OP1_TYPE == IS_VAR && !object_ptr) {
zend_error_noreturn(E_ERROR, "Cannot use string offset as an array");
}
if (Z_TYPE_PP(object_ptr) == IS_OBJECT) {
zend_free_op free_op2;
zval *property_name = GET_OP2_ZVAL_PTR(BP_VAR_R);
if (IS_OP2_TMP_FREE()) {
MAKE_REAL_ZVAL_PTR(property_name);
}
zend_assign_to_object(&opline->result, object_ptr, property_name, &op_data->op1, EX(Ts), ZEND_ASSIGN_DIM TSRMLS_CC);
if (IS_OP2_TMP_FREE()) {
zval_ptr_dtor(&property_name);
} else {
FREE_OP2();
}
} else {
zend_free_op free_op2, free_op_data1, free_op_data2;
zval *value;
zval *dim = GET_OP2_ZVAL_PTR(BP_VAR_R);
zval **variable_ptr_ptr;
zend_fetch_dimension_address(&EX_T(op_data->op2.u.var), object_ptr, dim, IS_OP2_TMP_FREE(), BP_VAR_W TSRMLS_CC);
FREE_OP2();
value = get_zval_ptr(&op_data->op1, EX(Ts), &free_op_data1, BP_VAR_R);
variable_ptr_ptr = _get_zval_ptr_ptr_var(&op_data->op2, EX(Ts), &free_op_data2 TSRMLS_CC);
if (!variable_ptr_ptr) {
if (zend_assign_to_string_offset(&EX_T(op_data->op2.u.var), value, op_data->op1.op_type TSRMLS_CC)) {
if (!RETURN_VALUE_UNUSED(&opline->result)) {
EX_T(opline->result.u.var).var.ptr_ptr = &EX_T(opline->result.u.var).var.ptr;
ALLOC_ZVAL(EX_T(opline->result.u.var).var.ptr);
INIT_PZVAL(EX_T(opline->result.u.var).var.ptr);
ZVAL_STRINGL(EX_T(opline->result.u.var).var.ptr, Z_STRVAL_P(EX_T(op_data->op2.u.var).str_offset.str)+EX_T(op_data->op2.u.var).str_offset.offset, 1, 1);
}
} else if (!RETURN_VALUE_UNUSED(&opline->result)) {
AI_SET_PTR(EX_T(opline->result.u.var).var, EG(uninitialized_zval_ptr));
PZVAL_LOCK(EG(uninitialized_zval_ptr));
}
} else {
value = zend_assign_to_variable(variable_ptr_ptr, value, IS_TMP_FREE(free_op_data1) TSRMLS_CC);
if (!RETURN_VALUE_UNUSED(&opline->result)) {
AI_SET_PTR(EX_T(opline->result.u.var).var, value);
PZVAL_LOCK(value);
}
}
FREE_OP_VAR_PTR(free_op_data2);
FREE_OP_IF_VAR(free_op_data1);
}
FREE_OP1_VAR_PTR();
/* assign_dim has two opcodes! */
ZEND_VM_INC_OPCODE();
ZEND_VM_NEXT_OPCODE();
}
👀