Home > PHP > PHPのちょっとしたコツ

PHPのちょっとしたコツ

  • 2006-10-27 (金) 19:05
  • PHP
この記事の所要時間: 1115

ウノウラボ Unoh Labs: PHPのちょっとしたコツに興味深い内容が書かれています。

1. array_pushは遅い
いくつかのBlogで語られてることですが、array_pushは、次のような書き方のほうが早いそうです。

	//array_puth($array, \'arraydata\');
	$array[] = \'arraydata\';

ウノウラボ Unoh Labs: PHPのちょっとしたコツ

これはほんとあちこちで言われていますね。実際にどの程度違うかベンチマークを取ってみました。

< ?php
require_once 'Benchmark/Timer.php';

$max = 10000;

$timer = new Benchmark_Timer();
$timer->start();

$array = array();
for ($i = 0 ; $i < $max ; $i++) {
  $array&#91;&#93; = $i;
}
$timer->setMarker('statement');

$array = array();
for ($i = 0 ; $i < $max ; $i++) {
  array_push($array, $i);
}
$timer->setMarker('array_push');

$timer->stop();
$timer->display();
?>

予想通りarray_pushの方が遅く、PHP4で約1.3倍、PHP5で1.6倍遅い結果になりました。

■PHP 4.4.4 (cli)
--------------------------------------------------------
statement   1161939536.23285200   0.012247085571289  43.97%
--------------------------------------------------------
array_push  1161939536.24843900   0.015587091445923  55.97%
--------------------------------------------------------
■PHP 5.1.6 (cli)
--------------------------------------------------------
statement   1161939530.12842400   0.0053808689117432  37.91%
--------------------------------------------------------
array_push  1161939530.13722100   0.0087971687316895  61.97%
--------------------------------------------------------

2. array_key_existsよりハッシュを使え
array_searchは、毎回全データを検索するので遅いです。
データに配列の順序が関係ないなら、連想配列 + issetを使うほうが高速です。

ウノウラボ Unoh Labs: PHPのちょっとしたコツ

こちらもベンチマークを取ってみました。

< ?php
require_once 'Benchmark/Timer.php';

$max = 10000;
$array = array('abc' => 'abc', 'null' => null);

$timer = new Benchmark_Timer();
$timer->start();

for ($i = 0 ; $i < $max ; $i++) {
  isset($array&#91;'abc'&#93;);
  isset($array&#91;'null'&#93;);
  isset($array&#91;'none'&#93;);
}
$timer->setMarker('isset');

for ($i = 0 ; $i < $max ; $i++) {
  array_key_exists('abc', $array);
  array_key_exists('null', $array);
  array_key_exists('none', $array);
}
$timer->setMarker('array_key_exists');

$timer->stop();
$timer->display();
?>

やはりarray_key_existsの方が遅いです。こちらはarray_pushより速度差がの方が大きく、PHP4で約2倍、PHP5で約4倍(!)遅い結果になりました。

■PHP 4.4.4 (cli)
---------------------------------------------------------------
isset              1161938594.14881000   0.014264822006226  33.43%
---------------------------------------------------------------
array_key_exists   1161938594.17719700   0.028387069702148  66.53%
---------------------------------------------------------------
■PHP 5.1.6 (cli)
---------------------------------------------------------------
isset              1161938597.88852400   0.0043120384216309  19.44%
---------------------------------------------------------------
array_key_exists   1161938597.90638100   0.01785683631897  80.50%
--------------------------------------------------------

ただarray_key_existsとissetは全く同じ挙動を示すわけではなく、配列にキーが定義されているかを厳密に調べるにはarray_key_existsを使わざるを得ないようです。(@see PHPマニュアル-isset

4. if文は「===」を使う

ウノウラボ Unoh Labs: PHPのちょっとしたコツ

これは趣味の問題かもしれませんが、odz buffer – PHPのイテレーションの話とかでodzさんが書かれている形が自然だと思います。特に

 if (is_null($null) === false) {

はis_null()がtrue or false以外の値を返すようで引っかかりました。(マニュアルを見直しました。:-))

5. countは配列数を毎回数えてる これを知ったのは、Pukiwkiのクリーンアップの記事を見たときなのですが。 countは配列の件数を数えるらしいので次のような書き方に直したほうが無難です。

ウノウラボ Unoh Labs: PHPのちょっとしたコツ

count()が実行毎に件数を数えるわけではないのはエントリで触れられているのですが、このtips自体が無意味なわけではありません。

count()の値をループ前に取得しておくのとループ内で呼ぶのとでベンチマークを取ってみると以下のようにやはり差が出ました。

※ソースはodzさんのを編集させていただきました。

< ?php
require_once 'Benchmark/Timer.php';

function test_count_loop($array, $iterate) {
    for ($j = 0; $j < $iterate; $j++) {
        $n = 0;
        $count = count($array);
        for ($i = 0; $i < $count; $i++) {
            $n = $array&#91;$i&#93;;
        }
    }
}

function test_count_loop_count($array, $iterate) {
    for ($j = 0; $j < $iterate; $j++) {
        $n = 0;
        for ($i = 0; $i < count($array); $i++) {
            $n = $array&#91;$i&#93;;
        }
    }
}

function test_foreach($array, $iterate) {
    for ($j = 0; $j < $iterate; $j++) {
        foreach ($array as $i) {
            $n = $i;
        }
    }
}

$a = range(0, 9999);
$b = range(0, 9999);
$c = range(0, 9999);

$timer = new Benchmark_Timer;

$timer->start();

test_count_loop($a, 1000);
$timer->setMarker('count_loop');

test_count_loop_count($b, 1000);
$timer->setMarker('count_loop_count');

test_foreach($c, 1000);
$timer->setMarker('test_foreach');

$timer->stop();
$timer->display();
?>
■PHP 4.4.4 (cli)
---------------------------------------------------------------
count_loop         1161943146.86602700   10.211816072464  34.91%
---------------------------------------------------------------
count_loop_count   1161943160.60222800   13.736200809479  46.95%
---------------------------------------------------------------
test_foreach       1161943165.90888800   5.3066601753235  18.14%
---------------------------------------------------------------
■PHP 5.1.6 (cli)
---------------------------------------------------------------
count_loop         1161943103.61103900   2.0879490375519  24.69%
---------------------------------------------------------------
count_loop_count   1161943108.41284200   4.80180311203   56.79%
---------------------------------------------------------------
test_foreach       1161943109.97873100   1.5658888816833  18.52%
---------------------------------------------------------------

以前はforよりforeachの方が速い遅いという話を聞いた事があったのですが、いつのまにかforeachの方が速くなってますね。普段は多少のオーバーヘッドは気にせずforeachを使っていたのですが、これで大手を振って使えます。;-)

Pocket

follow us in feedly

トラックバック:0

このエントリーのトラックバックURL
/blog/2006/10/php_source_tips.html/trackback
Listed below are links to weblogs that reference
PHPのちょっとしたコツ from Shin x blog

Home > PHP > PHPのちょっとしたコツ

検索
フィード
メタ情報

Return to page top