皆さんこんにちは。暑い日が続いて、配列……もとい、扇風機をぶん回す毎日ですね。
「PHPerは配列ばっかり回している」なんて良く皮肉られたりしますが、実際PHPは配列を良く使う言語です。連載の第2回は、そんな「配列」についてお話します。
PHPのマニュアルで配列の項目を見てみると、以下のように書いてあります。
「PHPの配列は、実際には順番付けられたマップです。マップは型の一種で、 値をキーに関連付けます。 この型は、さまざまな使い道にあわせて最適化されます。 配列としてだけでなく、リスト(ベクター)、 ハッシュテーブル(マップの実装の一つ)、辞書、コレクション、スタック、 キュー等として使用することが可能です。PHPの配列には他のPHP配列を値として保持することができるため、 非常に簡単にツリー構造を表現することが可能です。」
[PHPマニュアル]
http://php.net/manual/ja/language.types.array.php
他の言語では多階層の情報を扱うために、マップを明示的に使用したり、コレクションを用いる必要がありますが、PHPでは配列一つで色々できてしまいます。
1.1 配列の基本
まずは基本からです。
図1: 配列の基本
source2_1.php
2 | $colors = array('red', 'blue', 'green'); |
5 | foreach($colors as $color){ |
一般的な配列の使い方のサンプルですね。以下のように書いても、同様の結果が得られます。
source2_2.php
09 | foreach($colors as $color){ |
1.2 要素の順序について
では、ちょっと応用編です。以下のコードを実行すると、出力される順序はどのようになるでしょうか?
source2_3.php
09 | foreach($colors as $color){ |
添字の数字に合わせて「green」「red」「blue」の順で出ると思いますか?残念ながら違います。
配列に入れた順序に出ました。なぜでしょうか?その理由は、PHPの配列が添字とは別に内部順序を持っているからです。
source2_3.phpのようなプログラムの場合、記述された順番に
- $colors[1]は1番目
- $colors[2]は2番目
- $colors[0]は3番目
と内部的に順番が振られており、出力の際には添字の順番ではなく、この内部順序に従います。
図2: source2_3.phpの実行結果
添字順に出力して欲しい場合は、sort系関数を使うことで添字順にすることができます。
source2_4.php
10 | foreach($colors as $color){ |
1.3 添字のつけ方
配列の添字を指定しない場合、PHPはどのように添字をつけていくのでしょうか。次の例では、最初だけ添字を「3」に指定しています。
source2_5.php
09 | foreach($colors as $color){ |
このように、最後に指定した添字の次の数字から代入されていきます。
では、「マイナス」から始めた場合はどうでしょう?同様に-2、-1、0……と続くのでしょうか?添字がマイナスである場合は、次に振られる数字は0になります。PHPのマニュアルにも以下のように記述されています。
「警告 PHP 4.3.0 以降、上記のような添字生成動作は変更されました。 現在では、配列に追加する際に、 その配列の最大添字が負である場合は次の添え字はゼロ(0)となります。 以前は、正の添字の場合と同様に新しい添字は最大添字に +1 したものがセットされました。」
[PHPマニュアル]
http://www.php.net/manual/ja/language.types.array.php
以下の例で確認してみましょう。
source2_6.php
09 | foreach($colors as $color){ |
このようにマイナスの添字から始めた場合、次は0になります。
1.4 配列操作の関数
「配列をぶん回す言語」の呼び名にふさわしく、PHPにはソート関数をはじめとする配列を操作するための関数が非常にたくさん備えられています。ですがそれらの関数は、歴史的な経緯から引数の順番が一定ではなかったり、似たような名前があるので注意が必要です。
例えば、以下のような関数があります。
1. array_search('key name', array);2.arraypush(array, 'value');
それぞれ(1)は配列arrayの中から「keyname」というキー名の要素を検索する関数、(2)は配列arrayの最後に「value」を要素として追加する関数です。見てお分かりのように、(1)では対象の配列を第2引数で指定するのに対し、(2)では対象の配列が第1引数に来ています。この例のように、機能が近い関数の間でも引数の渡し方があまり統一されていません。この辺りは関数によって違いますので、注意しておきましょう。ただ配列操作の関数は数が多すぎるので、全部を覚える必要はないかと思います。
1.5 文字列への配列としてのアクセス
このように、PHPは添字での文字列へのアクセスをサポートしているので、文字列の各文字を要素として配列に見立てた利用が可能です。
1.6 array_key_existsとisset(array[key])のパフォーマンス的違い
そのキーの要素が配列内に存在するかどうかを調べてくれる関数として「array_key_exists」がありますが、「isset($array['key'])」とすることで代用できます。
source2_8.php
02 | $time_start = microtime(true); |
05 | for($i = 0; $i < 100000; $i++){ |
11 | for($i = 0; $i < 300000; $i++){ |
12 | if(array_key_exists($i, $colors)){ |
13 | $result = $colors[$i]; |
18 | $time_end = microtime(true); |
19 | $time = $time_end - $time_start; |
source2_9.php
02 | $time_start = microtime(true); |
05 | for($i = 0; $i < 100000; $i++){ |
11 | for($i = 0; $i < 300000; $i++){ |
12 | if(isset($colors[$i])){ |
13 | $result = $colors[$i]; |
18 | $time_end = microtime(true); |
19 | $time = $time_end - $time_start; |
それぞれの実行結果は、以下のようになりました。
array_key_exists
- 1回目の実行時間:0.18406081199646秒
- 2回目の実行時間:0.17879796028137秒
- 3回目の実行時間:0.18822693824768秒
isset
- 1回目の実行時間:0.13841509819031秒
- 2回目の実行時間:0.13023519515991秒
- 3回目の実行時間:0.13298797607422秒
上記のことからパフォーマンス的に見ると「isset(array[′key′])」と書く方が効率が良いことがわかります。この差は、arraykeyexistsが線形探索を行っているのに対し、isset(array[key])はハッシュを利用しているためと考えられます。ただし両者は、array[$key]がNULLの場合の挙動が異なります。その違いをきちんと理解して利用する必要があります。
ということで、今回はPHPの基本中の基本である配列についてのお話しでした。基本というものは大切です。基本的なことなので普段なにげなく扱っていたりしますが、実は注意点がいっぱいあるので覚えておくと良いでしょう。
次回は文字列操作についてお話ししていきます。