Programming PHP
第5章:配列
Kevin Tatroe、Rasmus Lerdorf著
PHP Programming(2002年3月、O'Reilly & Associates)より抜粋
この書籍のサンプル・コードをダウンロード
第2章で説明したとおり、PHPはスカラー型および複合型の2種類のデータ型をサポートします。 この章では、複合型の一例として配列について説明します。 配列はデータ値の集合であり、順序付けられたキー値のペアの集合として構成されます。
この章では、配列の作成、配列からの要素の追加と削除、および配列のコンテンツのループ・オーバーについて説明します。 配列は一般的かつ有用であるため、PHPには配列に関連する組込み関数が多く存在します。 たとえば、複数のメール・アドレスに電子メールを送信する場合、メール・アドレスは配列に格納され、配列をループして現在のメール・アドレスにメッセージを送信します。 また、複数選択可能な形式の場合、ユーザーが選択した項目は配列に返されます。 索引配列と連想配列
PHPの配列には、次の2種類があります。 索引配列と連想配列です。 索引配列のキーは、0から始まる整数です。索引配列は、位置から識別する場合に使用されます。 連想配列は、文字列をキーとして、2列の表のように機能します。 最初の列がキーであり、値にアクセスするために使用されます。
PHPにおけるすべての配列は、内部的には連想配列として格納されます。索引配列と連想配列の唯一の違いは、キーの扱われ方です。 いくつかの配列の機能は、索引配列で使用することを想定して提供されています。これはキーが0から始まる連続した整数であるか、そうであることを期待されているためです。キーが文字列であるか整数であるかに関わらず、キーは一意であり、2つの要素は同じキーでは扱えません。 PHP配列は内部順序に要素を持ち、それらはキーや値とは独立しています。また、内部順序に基づき、配列をトラバースする関数も存在します。 順序は通常どの値が配列に挿入されたかで決まりますが、後述するソート関数により、キーや値、または任意の設定に基づいて順序を変更することができます。 配列の要素の識別
角括弧で囲われた要素キー(索引)を伴う配列の変数名を使用することで、配列内の特定の値にアクセスできます。
$age['Fred']
$shows[2]
キーには文字列と整数のどちらかが使用できます。 (先行ゼロ列を除く)整数と等しい文字列値は、整数として扱われます。 このため、$array[3]と$array['3']は同じ要素を参照しますが、$array['03']は異なる要素を参照します。 負数も有効なキーとなります。また、Perlとは異なり、配列の最後から位置を特定しません。 1つの単語からなる文字列には、引用符を使用する必要はありません。 たとえば、$age['Fred']は$age[Fred]と同じです。 しかし、引用符を常に使用したPHPのほうが適切です。これは、引用符を伴わないキーは定数と区別できないためです。 引用符を伴わない索引として定数を使用する場合、PHPは定数の値を索引として使用します。
define('index',5);
echo $array[index]; // retrieves $array[5], not $array['index'];
配列索引を作成する際に補間を使用する場合は、引用符を使用する必要があります。
$age["Clone$number"]
ただし、配列参照を補間している場合は、キーに引用符を使用しないでください。
// these are wrong
print "Hello, $person['name']";
print "Hello, $person["name"]";
// this is right
print "Hello, $person[name]";
配列へのデータの格納
配列が存在しない場合に、配列で値を格納すると配列が作成されますが、まだ定義されていない配列から値を取得しようとしても配列は作成されません。 以下に例をあげます。
// $addresses not defined before this point
echo $addresses[0]; // prints nothing
echo $addresses; // prints nothing
$addresses[0] = 'spam@cyberpromo.net';
echo $addresses; // prints "Array"
プログラムで簡単な代入により配列を初期化すると、次のようなコードになります。
$addresses[0] = 'spam@cyberpromo.net';
$addresses[1] = 'abuse@example.com';
$addresses[2] = 'root@example.com';
// ...
上述の配列は、0から始まる整数の索引による索引配列です。下記の配列は連想配列です。
$price['Gasket'] = 15.29;
$price['Wheel'] = 75.25;
$price['Tire'] = 50.00;
// ...
配列を初期化する簡単な方法として、引数から配列を作成するarray( )コンストラクトを使用します。
$addresses = array('spam@cyberpromo.net', 'abuse@example.com',
'root@example.com');
array( )を使用して連想配列を作成するには、=>シンボルを使用して索引と値を分離します。
$price = array('Gasket' => 15.29,
'Wheel' => 75.25,
'Tire' => 50.00);
空白と位置合わせに注意してください。 一列に並べることも可能ですが、読みづらくなります。
$price = array('Gasket'=>15.29,'Wheel'=>75.25,'Tire'=>50.00);
空の配列を構築するには、array( )に引数をわたさないようにします。
$addresses = array( );
初期キーを=>を使用して指定し、その後LOVを指定できます。 値はキーの後に連続して入力されます(キーは1つだけ入力されます)。2つ目以降の値には順次キーが割り当てられます。
$days = array(1 => 'Monday', 'Tuesday', 'Wednesday',
'Thursday', 'Friday', 'Saturday', 'Sunday');
// 2 is Tuesday, 3 is Wednesday, etc.
初期索引が数字列ではない場合、2つ目以降の索引は0から始まる整数となります。そのため、次の例は、高い確率で誤りと言えます。
$whoops = array('Friday' => 'Black', 'Brown', 'Green');
// same as
$whoops = array('Friday' => 'Black', 0 => 'Brown', 1 => 'Green');
配列の最後に値を追加
すでに存在する索引配列の最後にさらに値を追加する場合は、[]構文を使用します。
$family = array('Fred', 'Wilma');
$family[] = 'Pebbles'; // $family[2] is 'Pebbles'
このコンストラクトは、配列の索引が数字であり、次に割当て可能な0から始まる数値索引に要素を代入すると仮定しています。連想配列を追加しようと試みることは、ほとんどの場合プログラムのミスですが、PHPは警告なしで新しい要素の数値索引を追加します。
$person = array('name' => 'Fred');
$person[] = 'Wilma'; // $person[0] is now 'Wilma'
値の範囲の割当て
range( )関数は、引数として入力した2つの値の間で、連続した整数または文字値の配列を作成します。 以下に例をあげます。
$numbers = range(2, 5); // $numbers = array(2, 3, 4, 5);
$letters = range('a', 'z'); // $numbers holds the alphabet
$reversed_numbers = range(5, 2); // $numbers = array(5, 4, 3, 2);
文字列の最初の一文字のみが範囲の割当て時に引数として使用されます。
range('aaa', 'zzz') /// same as range('a','z')
配列のサイズの取得
count( )関数およびsizeof( )関数は使用と効果において全く同じです。 これらの関数は配列の要素の数を返します。 どちらの関数を使用しても違いはありません。 次に例を示します。
$family = array('Fred', 'Wilma', 'Pebbles');
$size = count($family); // $size is 3
これらの関数は、次のような数値索引を参照しません。
$confusion = array( 10 => 'ten', 11 => 'eleven', 12 => 'twelve');
$size = count($confusion); // $size is 3
配列のパディング
同じ値で初期化された配列を作成するには、array_pad( )関数を使用します。 array_pad( )の最初の引数は配列です。2つ目の引数は配列に入力したい要素の最小数です。3つ目の引数は作成される任意の要素の値です。 array_pad( )関数は、引数の配列を残したまま新しいパディング配列を返します。
次にarray_pad( )関数の使用例を示します。
$scores = array(5, 10);
$padded = array_pad($scores, 5, 0); // $padded is now array(5, 10, 0, 0, 0)
新しい値が配列の最後にどのように追加されたかに注目してください。 新しい値を配列の最初に追加したい場合は、2つ目の引数に負数を使用してください。
$padded = array_pad($scores, -5, 0);
変更はそのままで、array_pad( )関数の結果をオリジナルの配列に代入します。
$scores = array_pad($scores, 5, 0);
連想配列をパディングする場合、既存のキーは維持されます。 新しい要素は0から始まる数値キーを持ちます。多次元配列
配列の値自体も配列になりえます。 これにより簡単に多次元配列を作成できます。
$row_0 = array(1, 2, 3);
$row_1 = array(4, 5, 6);
$row_2 = array(7, 8, 9);
$multi = array($row_0, $row_1, $row_2);
複数の[]を使用することで、多次元配列の要素を参照できます。
$value = $multi[2][0]; // row 2, column 0. $value = 7
多次元配列の参照を補完するには、中括弧で配列参照全体を囲う必要があります。
echo("The value at row 2, column 0 is {$multi[2][0]}\n");
中括弧を使用しない場合、次のような出力になります。
The value at row 2, column 0 is Array[0]
複数の値の抽出
すべての配列の値を変数にコピーするには、list( )コンストラクトを使用します。
list($variable, ...) = $array;
配列の値は、配列の内部順序でリストされた変数にコピーされます。 デフォルトでは、挿入された順序になっていますが、後述するソート関数を使用することで変更できます。 次に例を示します。
$person = array('name' => 'Fred', 'age' => 35, 'wife' => 'Betty');
list($n, $a, $w) = $person; // $n is 'Fred', $a is 35, $w is 'Betty'
もし、配列にlist( )内より多くの値が存在する場合、余分な値は無視されます。
$person = array('name' => 'Fred', 'age' => 35, 'wife' => 'Betty');
list($n, $a) = $person; // $n is 'Fred', $a is 35
list( )に配列内より多くの値が存在する場合、余分な値はNULLになります。
$values = array('hello', 'world');
list($a, $b, $c) = $values; // $a is 'hello', $b is 'world', $c is NULL
list( )内の複数の連続的なカンマは配列の値をスキップします。
$values = range('a', 'e');
list($m,,$n,,$o) = $values; // $m is 'a', $n is 'c', $o is 'e'
配列のスライス
配列のサブセットのみを抽出するには、array_slice( )関数を使用します。
$subset = array_slice(array, offset, length);
array_slice( )関数は、オリジナルの配列から、連続した値で構成される新しい配列を返します。 offsetパラメータは初期要素を特定し、コピーします(0は配列の最初の要素を示します)。lengthパラメータはコピーする値の数を特定します。 新しい配列は0から始まる連続した数値キーを持ちます。次に例を示します。
$people = array('Tom', 'Dick', 'Harriet', 'Brenda', 'Jo');
$middle = array_slice($people, 2, 2); // $middle is array('Harriet', 'Brenda')
通常、array_slice( )は、索引配列で使用する場合にのみ意味を持ちます(例:0から始まる連続した整数の索引を持つ配列)。
// this use of array_slice( ) makes no sense
$person = array('name' => 'Fred', 'age' => 35, 'wife' => 'Betty');
$subset = array_slice($person, 1, 2); // $subset is array(0 => 35, 1 => 'Betty')
array_slice( )とlist( )関数を併用し、任意の値のみを変数に抽出します。
$order = array('Tom', 'Dick', 'Harriet', 'Brenda', 'Jo');
list($second, $third) = array_slice($order, 1, 2);
// $second is 'Dick', $third is 'Harriet'
配列のチャンクへの分割
配列を小さく、均一なサイズの配列に分割するには、array_chunk( )関数を使用します。
$chunks = array_chunk(array, size [, preserve_keys]);
この関数は、配列のより小さい配列を返します。 3つ目の引数であるpreserve_keysはブール値です。この値は新しい配列の要素がオリジナルのキーと同じになるか(連想配列で有用)、0から始まる新しい数値キーになるか(索引配列で有用)を決定します。 デフォルトでは、次に示す新しいキーを割り当てます。
$nums = range(1, 7);
$rows = array_chunk($nums, 3);
print_r($rows);
Array
(
[0] => Array
(
[0] => 1
[1] => 2
[2] => 3
)
[1] => Array
(
[0] => 4
[1] => 5
[2] => 6
)
[2] => Array
(
[0] => 7
)
)
キーと値
array_keys( )関数は、内部順序で配列のキーのみで構成される配列を返します。
$array_of_keys = array_keys(array);
次に例を示します。
$person = array('name' => 'Fred', 'age' => 35, 'wife' => 'Wilma');
$keys = array_keys($person); // $keys is array('name', 'age', 'wife')
また、PHPは(比較的有用性の低い)配列内から値の配列を取得するarray_values( )を提供します。
$array_of_values = array_values(array);
array_keys( )と同様に、値は配列の内部順序どおりに返されます。
$values = array_values($person); // $values is array('Fred', 35, 'Wilma');
要素の存在の確認
配列に要素が存在するかを確認するには、array_key_exists( )関数を使用します。
if (array_key_exists(key, array)) { ... }
この関数は、1つ目の引数として提供された配列内で2つ目の引数が有効なキーかどうかを示すブール値を返します。 これは以下を説明するには不十分です。
if ($person['name']) { ... } // this can be misleading
nameというキーを持つ配列に要素があるとしても、対応する値はfalse(たとえば、0、NULL、または空の文字列)である可能性があります。 代わりに、次のようにarray_key_exists( )を使用します。
$person['age'] = 0; // unborn?
if ($person['age']) {
echo "true!\n";
}
if (array_key_exists('age', $person)) {
echo "exists!\n";
}
exists!
PHP 4.0.6以前のバージョンでは、array_key_exists( )関数はkey_exists( )関数と呼ばれていました。 オリジナル名は、新しい名前のエイリアスとして保持されています。 多くのユーザーはisset( )関数を代わりに使用します。この関数は、要素が存在し、かつNULLではない場合にtrueを返します。
$a = array(0,NULL,'');
function tf($v) { return $v ? "T" : "F"; }
for ($i=0; $i < 4; $i++) {
printf("%d: %s %s\n", $i, tf(isset($a[$i])), tf(array_key_exists($i, $a)));
}
0: T T
1: F T
2: T T
3: F F
配列での要素の削除および挿入
array_splice( )関数は、配列で要素の削除および挿入を実行できます。
$removed = array_splice(array, start [, length [, replacement ] ]);
この配列を使用し、array_splice( )関数について説明します。
$subjects = array('physics', 'chem', 'math', 'bio', 'cs', 'drama', 'classics');
array_splice( )に位置2から3つの要素を削除するように指定することで、math、bio、およびcsを削除できます。
$removed = array_splice($subjects, 2, 3);
// $removed is array('math', 'bio', 'cs')
// $subjects is array('physics', 'chem');
長さを省略した場合、array_splice( )は配列の最後まで削除します。
$removed = array_splice($subjects, 2);
// $removed is array('math', 'bio', 'cs', 'drama', 'classics')
// $subjects is array('physics', 'chem');
単に要素を削除したいだけで、その値に配慮する必要がない場合、array_splice( )の結果を代入する必要はありません。
array_splice($subjects, 2);
// $subjects is array('physics', 'chem');
その他を除外し、要素を挿入する場合は4つ目の引数を使用します。
$new = array('law', 'business', 'IS');
array_splice($subjects, 4, 3, $new);
// $subjects is array('physics', 'chem', 'math', 'bio', 'law', 'business', 'IS')
差し替える配列のサイズは、削除する要素の数と同じである必要はありません。 必要に応じて、配列は伸縮します。
$new = array('law', 'business', 'IS');
array_splice($subjects, 2, 4, $new);
// $subjects is array('physics', 'chem', 'math', 'law', 'business', 'IS')
要素を削除せずに、配列に新しい要素を挿入するには、次を実行します。
$subjects = array('physics', 'chem', 'math');
$new = array('law', 'business');
array_splice($subjects, 2, 0, $new);
// $subjects is array('physics', 'chem', 'law', 'business', 'math')
例としては、索引配列を使用しましたが、array_splice( )は連想配列でも使用できます。
$capitals = array('USA' => 'Washington',
'Great Britain' => 'London',
'New Zealand' => 'Wellington',
'Australia' => 'Canberra',
'Italy' => 'Rome');
$down_under = array_splice($capitals, 2, 2); // remove New Zealand and Australia
$france = array('France' => 'Paris');
array_splice($capitals, 1, 0, $france); // insert France between USA and G.B.
配列と変数間での変換
PHPは、配列と変数間で変換するextract( )およびcompact( )という2つの関数を提供します。 配列内のキーに対応する変数の名前と変数の値は、配列の値に変わります。 次の配列の場合の例を示します。
$person = array('name' => 'Fred', 'age' => 35, 'wife' => 'Betty');
この配列は、次の変数に変換されるか、または次の変数から構成されます。
$name = 'Fred';
$age = 35;
$wife = 'Betty';
配列からの変数の作成
extract( )関数は、自動的に配列からローカル変数を作成します。 配列の要素の索引は変数の名前になります。
extract($person); // $name, $age, and $wife are now set
抽出により作成された変数が既存の名前と同じ場合は、抽出された変数が既存の変数を上書きします。 2つ目の引数を入力することで、extract( )の動作を変更できます。 付録Aは2つ目の引数として使用できる値について説明します。 もっとも有用な値は、EXTR_PREFIX_SAMEです。これにより、extract( )の3つ目の引数は、作成される変数名の接頭辞になります。 これは、extract( )を使用する際、一意の変数名の作成を確実にサポートします。 次に示すように、EXTR_PREFIX_SAMEを常に使用するほうが適切です。
$shape = "round";
$array = array("cover" => "bird", "shape" => "rectangular");
extract($array, EXTR_PREFIX_SAME, "book");
echo "Cover: $book_cover, Book Shape: $book_shape, Shape: $shape";
Cover: bird, Book Shape: rectangular, Shape: round
変数からの配列の作成
compact( )関数は、extract( )の補完関数です。 別個のパラメータとして、または配列で、変数名をcompactと入力します。 compact( )関数は、変数名をキーとし、値を変数値とする連想配列を作成します。 実際の変数に対応しない配列内のあらゆる名前はスキップされます。 次にcompact( )関数の使用例を示します。
$color = 'indigo';
$shape = 'curvy';
$floppy = 'none';
$a = compact('color', 'shape', 'floppy');
// or
$names = array('color', 'shape', 'floppy');
$a = compact($names);
配列のトラバース
配列を活用する上での一般的なタスクは、各要素を使用することです。たとえば、アドレスの配列におけるそれぞれの要素への電子メールの送信、ファイル名の配列におけるそれぞれのファイルの更新、または価格の配列におけるそれぞれの要素の加算があげられます。 PHPには、配列をトラバースするいくつかの方法があります。また、その方法はデータまたは実行しているタスクに依存します。
foreachコンストラクト
配列の要素をループ・オーバーするもっとも一般的な方法は、foreachコンストラクトを使用することです。
$addresses = array('spam@cyberpromo.net', 'abuse@example.com');
foreach ($addresses as $value) {
echo "Processing $value\n";
}
Processing spam@cyberpromo.net
Processing abuse@example.com
PHPは、$valueが現在の要素にセットされた状態で、順番に$addressesのそれぞれの要素ごとに、ループの本体(echo文)を一度実行します。 要素はそれらの内部順序で処理されます。 foreachの代替形式は、現在のキーへのアクセスを提供します。
$person = array('name' => 'Fred', 'age' => 35, 'wife' => 'Wilma');
foreach ($person as $k => $v) {
echo "Fred's $k is $v\n";
}
Fred's name is Fred
Fred's age is 35
Fred's wife is Wilma
この場合、それぞれの要素のキーは$kに置かれ、対応する値は$vに置かれます。 foreachコンストラクトは、配列自体ではなく、配列のコピーに対して処理を実行します。 foreachループの本体において、要素の挿入または削除を実行できますが、ループ自体は要素の削除または挿入プロセスを実行しません。 イテレータ関数
すべてのPHP配列は、現在使用している要素を追跡します。また、現在の要素へのポインタはイテレータとして知られています。 PHPには、イテレータをセット、移動、リセットする関数が存在します。 以下にイテレータ関数を示します。
current( )
- 現時点で、イテレータによりポイントされている要素を返す。
reset( )
- イテレータを配列内の最初の要素に移動させ、それを返す。
next( )
- イテレータを配列内の次の要素に移動させ、それを返す。
prev( )
- イテレータを配列内の前の要素に移動させ、それを返す。
end( )
- イテレータを配列内の最後の要素に移動させ、それを返す。
each( )
- 現在の要素のキーと値を配列として返し、イテレータを配列の次の要素に移動させる。
key( )
- 現在の要素のキーを返す。
each( )関数は、配列の要素をループ・オーバーするために使用されます。 これは、内部順序にそって要素を処理します。
reset($addresses);
while (list($key, $value) = each($addresses)) {
echo "$key is $value<BR>\n";
}
0 is spam@cyberpromo.net
1 is abuse@example.com
この方法はforeachとは異なり、配列のコピーを作成しません。 これは、メモリを節約しつつ、大きな配列を扱う際に有用です。 イテレータ関数は、配列の一部を切り離して考える際に有用です。 例 5-1は表を作成するコードを示しています。連想配列の最初の索引および値を表の列ヘッダーとして扱います。
例5-1:イテレータ関数を使用した表の構築
$ages = array('Person' => 'Age',
'Fred' => 35,
'Barney' => 30,
'Tigger' => 8,
'Pooh' => 40);
// start table and print heading
reset($ages);
list($c1, $c2) = each($ages);
echo("<table><tr><th>$c1</th><th>$c2</th></tr>\n");
// print the rest of the values
while (list($c1,$c2) = each($ages)) {
echo("<tr><td>$c1</td><td>$c2</td></tr>\n");
}
// end the table
echo("</table>");
<table><tr><th>Person</th><th>Age</th></tr>
<tr><td>Fred</td><td>35</td></tr>
<tr><td>Barney</td><td>30</td></tr>
<tr><td>Tigger</td><td>8</td></tr>
<tr><td>Pooh</td><td>40</td></tr>
</table>
forループの使用
0から始まる連続した整数キーを持つ索引配列を使用することが分かっている場合、索引を通してカウントするためにforループを使用できます。 forループは配列のコピーではなく、配列自体を操作します。また、内部順序に関わらず、キーの順序で要素を処理します。
次にforループを使用して配列をプリントする方法を示します。
$addresses = array('spam@cyberpromo.net', 'abuse@example.com');
for($i = 0; $i < count($array); $i++) {
$value = $addresses[$i];
echo "$value\n";
}
spam@cyberpromo.net
abuse@example.com
それぞれの配列要素のための関数の呼出し
PHPは、配列の要素ごとに一度ずつユーザー定義の関数を呼び出すメカニズムであるarray_walk( )を提供します。
array_walk(array, function_name);
このユーザー定義の関数は、2つまたはオプションで3つの引数を使用します。 最初の引数は、要素の値であり、2つ目の引数は要素のキーです。また、3つ目の引数は、呼出し時にarray_walk( )に供給される値です。 たとえば、配列の値から成る表列をプリントするための別の方法を示します。
function print_row($value, $key) {
print("<tr><td>$value</td><td>$key</td></tr>\n");
}
$person = array('name' => 'Fred', 'age' => 35, 'wife' => 'Wilma');
array_walk($person, 'print_row');
このサンプルを変更し、array_walk( )のオプションの3つ目の引数を使用することで、背景色を指定します。 このパラメータは、多くの表を、多くの背景色でプリントすることが必要な場合に柔軟性を提供してくれます。
function print_row($value, $key, $color) {
print("<tr><td bgcolor=$color>$value</td><td bgcolor=$color>$key</td></tr>\n");
}
$person = array('name' => 'Fred', 'age' => 35, 'wife' => 'Wilma');
array_walk($person, 'print_row', 'blue');
array_walk( )関数は、内部順序で要素を処理します。 配列の削減
array_walk( )と似た関数として、配列のそれぞれの要素へ順番に関数を適用し、単一の値を作成するarray_reduce( )があります。
$result = array_reduce(array, function_name [, default ]);
この関数は2つの引数を使用します。 ランニング・トータルと現在処理中の値です。 この関数は新しいランニング・トータルを返します。 たとえば、配列の値の2乗の合計を出すには、次のコードを使用します。
function add_up ($running_total, $current_value) {
$running_total += $current_value * $current_value;
return $running_total;
}
$numbers = array(2, 3, 5, 7);
$total = array_reduce($numbers, 'add_up');
// $total is now 87
array_reduce( )行は、これらの関数に以下を呼び出させます。
add_up(2,3)
add_up(13,5)
add_up(38,7)
defaultの引数(存在する場合)は、シード値です。 たとえば、上述の例で、array_reduce( )の呼出しを次のように変更します。
$total = array_reduce($numbers, 'add_up', 11);
その関数呼出しの結果は次のようになります。
add_up(11,2)
add_up(13,3)
add_up(16,5)
add_up(21,7)
配列が空の場合、array_reduce( )はdefault値を返します。 デフォルト値が提供されており、配列が空の場合、array_reduce( )はNULLを返します。 値の検索
in_array( )関数は、trueまたはfalseを返します。これは最初の引数が2つ目の引数として提供されている配列の要素かどうかに依存します。
if (in_array(to_find, array [, strict])) { ... }
オプションである3つ目の引数がtrueの場合、to_findと配列の値のタイプは一致する必要があります。 デフォルトでは、タイプの確認はしません。 次に簡単な例を示します。
$addresses = array('spam@cyberpromo.net', 'abuse@example.com',
'root@example.com');
$got_spam = in_array('spam@cyberpromo.net', $addresses); // $got_spam is true
$got_milk = in_array('milk@tucows.com', $addresses); // $got_milk is false
PHPは配列の値に自動で索引付けを行います。そのため、in_array( )は必要な値を探すためにすべての値を確認するループに比べかなり高速です。 例 5-2は、ユーザーが必須のフィールドすべてに情報を入力したかどうかを確認します。
例5-2: 配列の検索
<?php
function have_required($array , $required_fields) {
foreach($required_fields as $field) {
if(empty($array[$field])) return false;
}
return true;
}
if($submitted) {
echo '<p>You ';
echo have_required($_POST, array('name', 'email_address')) ? 'did' : 'did not';
echo ' have all the required fields.</p>';
}
?>
<form action="<?= $PHP_SELF; ?>" method="POST">
<p>
Name: <input type="text" name="name" /><br />
Email address: <input type="text" name="email_address" /><br />
Age (optional): <input type="text" name="age" />
</p>
<p align="center">
<input type="submit" value="submit" name="submitted" />
</p>
</form>
in_array( )の変化形にarray_search( )関数があります。 値が見つかった場合、in_array( )はtrueを返しますが、array_search( )は見つかった要素のキーを返します。
$person = array('name' => 'Fred', 'age' => 35, 'wife' => 'Wilma');
$k = array_search($person, 'Wilma');
echo("Fred's $k is Wilma\n");
Fred's wife is Wilma
また、array_search( )関数は、オプションで3つ目の引数strictを使用します。この引数を使用するには、検索されている値と配列の値のタイプが一致する必要があります。 ソート
ソートは、配列内の要素の内部順序を変更し、オプションで新しい順序を反映するキーを書き換えます。 たとえば、ソートを利用して、リストのスコアを降順にしたり、リスト名をアルファベット順にしたり、投稿したメッセージの数によりユーザーの集合を並び替えたりできます。
PHPは、配列をソートする3つの方法(キーによるソート、キーの変更を伴わない値によるソート、キーの変更を伴う値によるソート)を提供します。 それぞれのソートは、昇順、降順、またはユーザー定義の関数に定義された順序で実行できます。 1回での単一の配列のソート
PHPにより提供される配列をソートするための関数は、表 5-1に示されています。
表5-1:配列のソートのためのPHP関数
| 効果 |
昇順 |
降順 |
ユーザー定義の順序 |
値による配列のソート後、0から始まる索引の再割当て |
sort( )
|
rsort( )
|
usort( )
|
値による配列のソート |
asort( )
|
arsort( )
|
uasort( )
|
キーによる配列のソート |
ksort( )
|
krsort( )
|
uksort( )
|
sort( )、rsort( )、およびusort( )関数は、索引配列で実行されるように設計されています。これは、これらの関数が順序付けを示すために新しい数値キーを割り当てるためです。 これらの関数は、"スコアのトップ10はなにか"や"アルファベット順で3番目の人物は誰か"といった質問に答える際に有用です。 その他のソート関数は、索引配列で使用できますが、ソート済みの順序付けへのアクセスはforeachやnextといったトラバーサル関数を使用することでのみ実行できます。 名前を昇順のアルファベット順にソートするには、次のコードを使用します。
$names = array('cath', 'angela', 'brad', 'dave');
sort($names); // $names is now 'angela', 'brad', 'cath', 'dave'
アルファベット順を反転させるには、単純にsort( )の代わりにrsort( )を呼び出します。 ユーザー名をログイン時間の記録にマッピングした連想配列がある場合、以下に示すように、arsort( )を使用してトップ3までの表を表示できます。
$logins = array('njt' => 415,
'kt' => 492,
'rl' => 652,
'jht' => 441,
'jj' => 441,
'wt' => 402);
arsort($logins);
$num_printed = 0;
echo("<table>\n");
foreach ($logins as $user => $time ) {
echo("<tr><td>$user</td><td>$time</td></tr>\n");
if (++$num_printed == 3) {
break; // stop after three
}
}
echo("</table>\n");
<table>
<tr><td>rl</td><td>652</td></tr>
<tr><td>kt</td><td>492</td></tr>
<tr><td>jht</td><td>441</td></tr>
</table>
この表をユーザー名で昇順に表示したい場合は、ksort( )を使用します。
ksort($logins);
echo("<table>\n");
foreach ($logins as $user => $time) {
echo("<tr><td>$user</td><td>$time</td></tr>\n");
}
echo("</table>\n");
<table>
<tr><td>jht</td><td>441</td></tr>
<tr><td>jj</td><td>441</td></tr>
<tr><td>kt</td><td>492</td></tr>
<tr><td>njt</td><td>415</td></tr>
<tr><td>rl</td><td>652</td></tr>
<tr><td>wt</td><td>402</td></tr>
</table>
ユーザー定義の順序付けには、ユーザーは2つの値を使用して、ソートされた配列内で2つの値の順序を指定する1つの値を返す関数を提供する必要があります。 この関数は、最初の値が2つ目の値より大きい場合は1を、最初の値が2つ目の値より小さい場合は-1を、値がカスタムのソート順序の目的と同じ場合は0を、それぞれ返します。 例 5-3は同じデータでさまざまなソート関数を使用することができるプログラムです。
例5-3:配列のソート
<?php
function user_sort($a, $b) {
// smarts is all-important, so sort it first
if($b == 'smarts') {
return 1;
}
else if($a == 'smarts') {
return -1;
}
return ($a == $b) ? 0 : (($a < $b) ? -1 : 1);
}
$values = array('name' => 'Buzz Lightyear',
'email_address' => 'buzz@starcommand.gal',
'age' => 32,
'smarts' => 'some');
if($submitted) {
if($sort_type == 'usort' || $sort_type == 'uksort' || $sort_type == 'uasort') {
$sort_type($values, 'user_sort');
}
else {
$sort_type($values);
}
}
?>
<form action="index.php">
<p>
<input type="radio" name="sort_type" value="sort" checked="checked" />
Standard sort<br />
<input type="radio" name="sort_type" value="rsort" /> Reverse sort<br />
<input type="radio" name="sort_type" value="usort" /> User-defined sort<br />
<input type="radio" name="sort_type" value="ksort" /> Key sort<br />
<input type="radio" name="sort_type" value="krsort" /> Reverse key sort<br />
<input type="radio" name="sort_type" value="uksort" /> User-defined key sort<br />
<input type="radio" name="sort_type" value="asort" /> Value sort<br />
<input type="radio" name="sort_type" value="arsort" /> Reverse value sort<br />
<input type="radio" name="sort_type" value="uasort" /> User-defined value sort<br />
</p>
<p align="center">
<input type="submit" value="Sort" name="submitted" />
</p>
<p>
Values <?= $submitted ? "sorted by $sort_type" : "unsorted"; ?>:
</p>
<ul>
<?php
foreach($values as $key=>$value) {
echo "<li><b>$key</b>: $value</li>";
}
?>
</ul>
</form>
自然順序のソート
PHPの組込みソート関数は、正確に文字列および数をソートしますが、数を含む文字列を正確にソートしません。 たとえば、ex10.php、ex5.php、およびex1.phpというファイル名がある場合、通常のソート関数は次のように並び替えます。 ex1.php、ex10.php、ex5.php。 数を含む文字列を正確にソートするには、natsort( )関数およびnatcasesort( )関数を使用します。
$output = natsort(input);
$output = natcasesort(input);
複数の配列の一括ソート
array_multisort( )関数は、複数の索引配列を一度にソートします。
array_multisort(array1 [, array2, ... ]);
一連の配列および(SORT_ASCまたはSORT_DESC制約として知られる)ソート順序を入力し、すべての配列の要素を並び替え、新しい索引を割り当てます。 これはリレーショナル・データベースの結合操作と似ています。 多くの人がいて、それぞれがいくつかのデータを所持していると考えてください。
$names = array('Tom', 'Dick', 'Harriet', 'Brenda', 'Joe');
$ages = array(25, 35, 29, 35, 35);
$zips = array(80522, '02140', 90210, 64141, 80522);
それぞれの配列の最初の要素は、単一のレコードすなわちTomについてわかるすべての情報を表しています。 同様に、2つ目の要素は他のレコードを構成しています。すなわち、Dickについてわかるすべての情報です。 array_multisort( )関数は、配列の要素を並び替え、レコードを保存します。 すなわち、ソート後にDickが$names配列で最初になるとすれば、Dickの残りの情報も他の配列で最初になるということです (Dickの郵便番号には、8進定数と解釈されないように引用符をつける必要がある点に注意してください)。 次に、最初に年齢で昇順にソートし、次に郵便番号で降順にソートする方法について示します。
array_multisort($ages, SORT_ASC, $zips, SORT_DESC, $names, SORT_ASC);
Dickの名前が彼の年齢および郵便番号とともにとどまるよう保証するため、関数の呼出しに$namesを含める必要があります。 データのプリントアウトはソートの結果を示します。
echo("<table>\n");
for ($i=0; $i < count($names); $i++) {
echo("<tr><td>$ages[$i]</td><td>$zips[$i]</td><td>$names[$i]</td>\n");
}
echo("</table>\n");
<table>
<tr><td>25</td><td>80522</td><td>Tom</td>
<tr><td>29</td><td>90210</td><td>Harriet</td>
<tr><td>35</td><td>80522</td><td>Joe</td>
<tr><td>35</td><td>64141</td><td>Brenda</td>
<tr><td>35</td><td>02140</td><td>Dick</td>
</table>
配列の反転
array_reverse( )関数は、配列内で要素の内部順序を反転させます。
$reversed = array_reverse(array);
数値キーは、0から始まる番号を再度割り当てられます。文字列索引は影響を受けません。 一般的に、ソート後に配列の順序を反転させる代わりに、逆順ソート関数を使用する方が適切です。 array_flip( )関数は、それぞれのオリジナルの要素のキー値のペアの順序を反転させた配列を返します。
$flipped = array_flip(array);
すなわち、有効なキーとしての値を持つ配列のそれぞれの要素ごとに、要素の値はそのキーに変わり、要素のキーはその値に変わります。 たとえば、ユーザー名をホーム・ディレクトリにマッピングする配列がある場合、array_flip( )を使用して、ホーム・ディレクトリをユーザー名にマッピングする配列を作成できます。
$u2h = array('gnat' => '/home/staff/nathan',
'rasmus' => '/home/elite/rasmus',
'ktatroe' => '/home/staff/kevin');
$h2u = array_flip($u2h);
$user = $h2u['/home/staff/kevin']; // $user is now 'ktatroe'
オリジナルの値が文字列でも整数でもない要素は、得られる配列にそのまま残ります。 新しい配列により、オリジナルの配列でその値をわたされるキーを発見できます。しかし、この方法が効果的なのは、オリジナルの配列が一意の値を持つ場合のみです。 順序のランダム化
ランダムな順序の配列における要素をトラバースするには、shuffle( )関数を使用します。 すべての既存のキーは、文字列や数に関わらず、0から始まる連続する整数で置き換えられます。
次に、1週間の曜日の順序をランダム化する方法を示します。
$days = array('Monday', 'Tuesday', 'Wednesday',
'Thursday', 'Friday', 'Saturday', 'Sunday');
shuffle($days);
print_r($days);
Array
(
[0] => Tuesday
[1] => Thursday
[2] => Monday
[3] => Friday
[4] => Wednesday
[5] => Saturday
[6] => Sunday
)
各ユーザーのshuffle( )関数の使用後の状態は、次のサンプル出力とは異なる場合があります。 特定の項目を繰り返すことなく、配列から複数のランダム要素を集めることを目的とする場合以外においては、rand( )関数を使用して索引を取得するほうが効率的です。 配列全体への作用
PHPには、配列のすべての要素に対する演算を変更または適用するための、いくつかの有益な関数が存在します。 配列のマージ、差異の検索、合計の計算などは、すべて組込み関数を使用することで実行できます。
配列の合計の計算
array_sum( )関数は、索引配列または連想配列の値を合計します。
$sum = array_sum(array);
以下に例を示します。
$scores = array(98, 76, 56, 80);
$total = array_sum($scores);
// $total = 310
2つの配列マージ
array_merge( )関数は、論理的に複数の配列をマージします。
$merged = array_merge(array1, array2 [, array ... ])
以前の配列の数値キーが繰り返されている場合、その後の配列の値は新しい数値キーを割り当てられます。
$first = array('hello', 'world'); // 0 => 'hello', 1 => 'world'
$second = array('exit', 'here'); // 0 => 'exit', 1 => 'here'
$merged = array_merge($first, $second);
// $merged = array('hello', 'world', 'exit', 'here')
以前の配列の文字列キーが繰り返されている場合、以前の値はその後の値で置き換えられます。
$first = array('bill' => 'clinton', 'tony' => 'danza');
$second = array('bill' => 'gates', 'adam' => 'west');
$merged = array_merge($first, $second);
// $merged = array('bill' => 'gates', 'tony' => 'danza', 'adam' => 'west')
2つの配列間の差異の計算
array_diff( )関数は、その他の配列には存在しない単一の配列から値を識別します。
$diff = array_diff(array1, array2 [, array ... ]);
以下に例を示します。
$a1 = array('bill', 'claire', 'elle', 'simon', 'judy');
$a2 = array('jack', 'claire', 'toni');
$a3 = array('elle', 'simon', 'garfunkel');
// find values of $a1 not in $a2 or $a3
$diff = array_diff($a1, $a2, $a3);
// $diff is array('bill', 'judy');
値は===を使用して比べられます。そのため、1と"1"は異なる値とみなされます。 最初の配列のキーは維持されます。そのため、$diffにおいて'bill'のキーは0であり、'judy'のキーは4となります。配列からの要素のフィルタリング
配列のサブセットをその値に基づいて識別するには、array_filter( )関数を使用します。
$filtered = array_filter(array, callback);
arrayのそれぞれの値は、callback内で指定される関数にわたされます。 返された配列には、関数がtrue値を返すオリジナルの配列の要素のみを含んでいます。 以下に例をあげます。
function is_odd ($element) {
return $element % 2;
}
$numbers = array(9, 23, 24, 27);
$odds = array_filter($numbers, 'is_odd');
// $odds is array(0 => 9, 1 => 23, 3 => 27)
上述のコードに示されるとおり、キーは維持されています。 この関数は、連想配列との使用にもっとも適しています。 配列の使用
配列はほとんどすべてのPHPプログラムで使用されます。 値の集合を格納する通常の使用方法に加え、抽象データ型を実装するためにも使用されます。 この項では、配列を使用して集合とスタックを実装する方法について説明します。
集合
配列により集合論の基本演算(和、積、差)を実装できます。 それぞれの集合は配列によって表されます。また、さまざまなPHP関数は、集合の演算を実装します。 集合の値は配列の値です。キーは使用されませんが、通常演算により維持されます。
2つの集合の和は、重複を除いた両方の集合のすべての要素です。 array_merge( )関数およびarray_unique( )関数により、和集合が計算できます。 次に2つの配列の和集合を求める方法を示します。
function array_union($a, $b) {
$union = array_merge($a, $b); // duplicates may still exist
$union = array_unique($union);
return $union;
}
$first = array(1, 'two', 3);
$second = array('two', 'three', 'four');
$union = array_union($first, $second);
print_r($union);
Array
(
[0] => 1
[1] => two
[2] => 3
[4] => three
[5] => four
)
2つの集合の積は、2つの集合の共通する要素です。 PHPの組込みarray_intersect( )関数は、配列の任意の数を引数として、それらの値の両方に存在する配列を返します。 複数のキーが同じ値を持つ場合は、最初のキーが維持されます。 配列の集合におけるその他の共通の関数には、差、すなわち一方の配列には存在し、もう一方の配列には存在しない値を求めるための関数があげられます。 array_diff( )関数は、2つ目の配列に存在しない最初の配列の値を配列として返します。 次のコードは、2つの配列の差を求めます。
$first = array(1, 'two', 3);
$second = array('two', 'three', 'four');
$difference = array_diff($first, $second);
print_r($difference);
Array
(
[0] => 1
[2] => 3
)
スタック
他のプログラムほどではありませんが、PHPプログラムにおいてもよく使用されるデータ型にLast-In First-Out(LIFO)スタックがあります。 2つのPHP関数array_push( )およびarray_pop( )を使用することで、スタックを作成できます。 array_push( )関数は、$array[]への割当てと同じです。 array_push( )は、スタックを扱っていることを強調するために使用されます。また、array_pop()とともに使用することでコードがより読みやすくなります。 さらに、配列をキューのように扱うためのarray_shift( )関数およびarray_unshift( )関数も存在します。
スタックは特に、ステートを維持するために有用です。 例 5-4は、この時点までにどの関数が呼び出されたかをプリントアウトする簡単なステート・デバッガ(スタック・トレース)を提供します。
例5-4:ステート・デバッガ
$call_trace = array( );
function enter_function($name) {
global $call_trace;
array_push($call_trace, $name); // same as $call_trace[] = $name
echo "Entering $name (stack is now: " . join(' -> ', $call_trace) . ')<br />';
}
function exit_function( ) {
echo 'Exiting<br />';
global $call_trace;
array_pop($call_trace); // we ignore array_pop( )'s return value
}
function first( ) {
enter_function('first');
exit_function( );
}
function second( ) {
enter_function('second');
first( );
exit_function( );
}
function third( ) {
enter_function('third');
second( );
first( );
exit_function( );
}
first( );
third( );
次に例 5-4の出力を示します。
Entering first (stack is now: first)
Exiting
Entering third (stack is now: third)
Entering second (stack is now: third -> second)
Entering first (stack is now: third -> second -> first)
Exiting
Exiting
Entering first (stack is now: third -> first)
Exiting
Exiting
|