はじめに
PHPに関する話題の中では、
そこで、
をもとに、
PHPソースコードの入手
やはり、
こちらから最新版のソースコードが入手できます。現在の最新バージョンは5.
echoのほうがprintより速い
まずはじめに検証を行うのは、
それでは実際に下記のコードを用いてベンチマークをとってみます。用意したコードは1000回ループを回して、
<?php
ob_start();
$t = microtime(true);
while($i < 1000) {
echo '';
++$i;
}
$tmp = microtime(true) - $t;
ob_end_clean();
var_dump($tmp);
?>
<?php
ob_start();
$t = microtime(true);
while($i < 1000) {
print '';
++$i;
}
$tmp = microtime(true) - $t;
ob_end_clean();
var_dump($tmp);
?>
$ php benchmark_echo.php float(0.000132083892822) $ php benchmark_print.php float(0.000159978866577)
わずかではありますが、
それでは、
printの実体はZend/
void zend_do_print(znode *result, znode *arg TSRMLS_DC)
{
zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
opline->result.op_type = IS_TMP_VAR;
opline->result.u.var = get_temporary_variable(CG(active_op_array));
opline->opcode = ZEND_PRINT;
opline->op1 = *arg;
SET_UNUSED(opline->op2);
*result = opline->result;
}
echoの実体はZend/
void zend_do_echo(znode *arg TSRMLS_DC)
{
zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
opline->opcode = ZEND_ECHO;
opline->op1 = *arg;
SET_UNUSED(opline->op2);
}
結果を返さない分、
1. Speed. There is a difference between the two, but speed-wise it should be irrelevant which one you use. echo is marginally faster since it doesn't set a return value if you really want to get down to the nitty gritty.
http://
PHPの生みの親でもあるRasmusらが書いたこのエントリには、
@によるエラー制御は遅い
PHPではエラー制御演算子として@を使用することができます。PHPの式の前に付けることで、
新たにprintに@を付けたコードを用意し、
<?php
ob_start();
$t = microtime(true);
while($i < 1000) {
@print '';
++$i;
}
$tmp = microtime(true) - $t;
ob_end_clean();
var_dump($tmp);
?>
$ php benchmark_print.php float(0.000159025192261) $ php benchmark_use_atmark.php float(0.000759124755859)
@を付けたほうが遅くなりました。遅い原因を探ってみましょう。
616 |@' { zend_do_begin_silence(&$1 TSRMLS_CC); } expr { zend_do_end_silence(&$1 TSRMLS_CC); $$ = $3; }
“@”
次にzend_
void zend_do_begin_silence(znode *strudel_token TSRMLS_DC)
{
zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
opline->opcode = ZEND_BEGIN_SILENCE;
opline->result.op_type = IS_TMP_VAR;
opline->result.u.var = get_temporary_variable(CG(active_op_array));
SET_UNUSED(opline->op1);
SET_UNUSED(opline->op2);
*strudel_token = opline->result;
}
void zend_do_end_silence(znode *strudel_token TSRMLS_DC)
{
zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
opline->opcode = ZEND_END_SILENCE;
opline->op1 = *strudel_token;
SET_UNUSED(opline->op2);
}
zend_
30753 return zend_opcode_handlers[opcode * 25 + zend_vm_decode[op-.op_type] * 5 + zend_vm_decode[op-.op_type]];
その結果、
次にZEND_
static int ZEND_BEGIN_SILENCE_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
zend_op *opline = EX(opline);
Z_LVAL(EX_T(opline->result.u.var).tmp_var) = EG(error_reporting);
Z_TYPE(EX_T(opline->result.u.var).tmp_var) = IS_LONG; /* shouldn't be necessary */
if (EX(old_error_reporting) == NULL) {
EX(old_error_reporting) = &EX_T(opline->result.u.var).tmp_var;
}
if (EG(error_reporting)) { zend_alter_ini_entry_ex("error_reporting", sizeof("error_reporting"), "0", 1, ZEND_INI_USER, ZEND_INI_STAGE_RUNTIME, 1);
}
ZEND_VM_NEXT_OPCODE();
}
static int ZEND_END_SILENCE_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
zend_op *opline = EX(opline);
zval restored_error_reporting;
if (!EG(error_reporting) && Z_LVAL(EX_T(opline->op1.u.var).tmp_var) != 0) {
Z_TYPE(restored_error_reporting) = IS_LONG;
Z_LVAL(restored_error_reporting) = Z_LVAL(EX_T(opline->op1.u.var).tmp_var); convert_to_string(&restored_error_reporting);
zend_alter_ini_entry_ex("error_reporting", sizeof("error_reporting"), Z_STRVAL(restored_error_reporting), Z_STRLEN(restored_error_reporting), ZEND_INI_USER, ZEND_INI_STAGE_RUNTIME, 1);
zendi_zval_dtor(restored_error_reporting); }
if (EX(old_error_reporting) == &EX_T(opline->op1.u.var).tmp_var) {
EX(old_error_reporting) = NULL;
}
ZEND_VM_NEXT_OPCODE();
}
二つのhandler間でzend_
echo '文','字'; (カンマ区切り)のほうが、'文'.'字' (ドット連結)より速い
こちらのtipsについても、
<?php
ob_start();
$t = microtime(true);
while($i < 1000) {
echo 'a', 'b', 'c';
++$i;
}
$tmp = microtime(true) - $t;
ob_end_clean();
var_dump($tmp);
?>
<?php
ob_start();
$t = microtime(true);
while($i < 1000) {
echo 'a' . 'b' . 'c';
++$i;
}
$tmp = microtime(true) - $t;
ob_end_clean();
var_dump($tmp);
?>
$ php benchmark_comma.php float(0.000305891036987) $ php benchmark_dot.php float(0.000324964523315)
実行してみると、
これについてもコードを追ってみます。
536 echo_expr_list:
537 echo_expr_list ',' expr { zend_do_echo(&$3 TSRMLS_CC); }
538 | expr { zend_do_echo(&$1 TSRMLS_CC); }
539 ;
カンマ区切りでは、
582 | expr '.' expr { zend_do_binary_op(ZEND_CONCAT, &$$, &$1, &$3 TSRMLS_CC); }
ドット連結の場合は、
また定数と定数の連結の場合には下記の関数が呼ばれます。concat_
static int ZEND_CONCAT_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS){
zend_op *opline = EX(opline);
concat_function(&EX_T(opline->result.u.var).tmp_var,
&opline->op1.u.constant,
&opline->op2.u.constant TSRMLS_CC);
ZEND_VM_NEXT_OPCODE();
}
echo 'a','b','c';
echo 'a'.'b'.'c';
上記のようなコードを例に考えると、
まとめ
PHP最適化tipsについて検証を行いました。あれが速いこれが遅いと言ってきましたが、
次回も引き続き検証を進めるとともに、