PHP Array Iteration(配列の繰り返し)
■配列のポインタ
各々の配列は、現在の要素を示すポインタ(イテレータ)を持っている。
- current()
- 現在のポインタが指している要素
- key()
- 現在の要素のキーを返す
- reset()
- ポインタを先頭に移動
- end()
- ポインタを配列の最後の要素に移動
- next()
- ポインタを1つ次に移動
- prev()
- ポインタを1つ前に移動
- each()
- 現在のキーと値を配列として返し、ポインタを次に移動
以下のように使用する。通常、whileはポインタの移動を行わないので、ポインタを移動させる関数の使用や、ループの終了条件の設定が不可欠である。また、foreachを使わないメリットは、配列のコピーを生成しないのでメモリを節約できる点である。
<?php
$tmpAry = array('a' => 1, 'b' => 2, 'c' => 3);
function display(&$array){
reset($array);
while(key($array) !== null){
echo key($array) . ': ' . current($array) . PHP_EOL;
next($array);
}
}
display($tmpAry);
?>
以下のように配列の後方からループさせることもできる。
<?php
$tmpAry = array('a' => 1, 'b' => 2, 'c' => 3);
end($tmpAry);
while(key($tmpAry) !== null){
echo key($array) . ': ' . current($array) . PHP_EOL;
prev($array);
}
?>
また、以下のようにforeachと同じような表現をすることが可能だ。この方法は大きな配列でメモリーを節約したい場合などに有効である。
<?php
$tmpAry = array('a' => 1, 'b' => 2, 'c' => 3);
reset($tmpAry);
while(list($key, $value) = each($tmpAry)){
print("{$key}: {$value}" . PHP_EOL);
}
?>
■foreach構文
上述のように、whileを使ったループコントロールはメモリ消費を抑制できるかわりに、コードが煩雑になる。従って、個人的には以下のようなforeachでのコントロールをたいていは用いる。
<?php
$tmpAry = array('a' => 1, 'b' => 2, 'c' => 3);
foreach($tmpAry as $key => $value){
echo $key . ': ' . $value;
}
?>
但し、foreach文では配列のコピーが生成されるので、ループ内で配列の要素($tmpAry[$key]ではなく$value)に処理を加えても、元の配列には影響しない。もしも反映させたい場合は、以下のようにリファレンス(参照)を使う。
<?php
$tmpAry = array('a' => 1, 'b' => 2, 'c' => 3);
foreach($tmpAry as $key => &$value){
echo $key . ': ' . $value;
$value++;
}
var_dump($tmpAry);
/*
array(3) {
["a"]=>
∫(2)
["b"]=>
∫(3)
["c"]=>
∫(4)
}
*/
?>
しかし、この方法には後述のような危険性が潜んでいる。
foreach構文におけるリファレンス使用の注意点
以下のように空のループを2回繰り返すと、配列の中身が予想外に変更されてしまう。
<?php
$names = array('Nick', 'John', 'Mike');
foreach($names as $key => &$value){
}
foreach($names as $key => $value){
}
var_dump($names);
/*
array(3) {
[0]=>
string(4) "Nick"
[1]=>
string(4) "John"
[2]=>
&string(4) "John"
}
*/
?>
原因
- 1回目のループ:&$valueは配列の各要素の住所(リファレンス)となる。
- 1回目のループ:&$valueは配列の最終要素のリファレンス(&$names[2])となる。
- 2回目のループ:各要素が既にassignされている$value(&$names[2])に代入されていく。
つまり、$names[2] = $valueがループごとに起こる。
- 2回目のループ(1):$names[2]にNickが代入される。
- 2回目のループ(2):$names[2]にJohnが代入される。
- 2回目のループ(3):$names[2]に既に2回目のループ(2)で代入されているJohnにJohnが代入される。
結果、Johnが重複する。それを防ぐ方法は以下のように、unsetを使って変数の割り当てを解除する事である。
<?php
$names = array('Nick', 'John', 'Mike');
foreach($names as $key => &$value){
}
unset($value)
foreach($names as $key => $value){
}
var_dump($names);
?>
個人的には度々この手法を使用するが、unsetを書き忘れた場合に極めてデバッグしづらい事も考えられる。従って、この手法を使わないという事も選択肢の1つだ。
■for構文
扱う配列のキーが数値のみであると分かっている場合、以下のようにする事ができる。for構文は配列のコピーを生成しない。
<?php
$names = array('Nick', 'John', 'Mike');
for($i = 0; $i < count($names); $i++){
//code
}
?>
■配列の要素に対する処理
以下のように、array_walkやarray_walk_recursive(子配列まで再帰的に処理)を使って各要素に任意の処理を加えることができる。
<?php
$names = array(
array('Nick', 38, 'driver'),
array('John', 25, 'programmer'),
array('Mike', 22, 'student')
);
function setUpper(&$value, &$key){
$value = strtoupper($value);
}
array_walk_recursive($names, 'setUpper');
var_dump($names);
/*
array(3) {
[0]=>
&array(3) {
[0]=>
string(4) "NICK"
[1]=>
string(2) "38"
[2]=>
string(6) "DRIVER"
}
[1]=>
&array(3) {
[0]=>
string(4) "JOHN"
[1]=>
string(2) "25"
[2]=>
string(10) "PROGRAMMER"
}
[2]=>
&array(3) {
[0]=>
string(4) "MIKE"
[1]=>
string(2) "22"
[2]=>
string(7) "STUDENT"
}
}
*/
?>
但し、個人的には関数名を文字列で渡す行為が嫌いなのもあり、イマイチこの方法は使わず単純に(再帰処理する関数を使って)ループさせることが多い。しかも、戻り値としては処理を加えた配列を返さない為、リファレンスを使う必要があり、コードも見づらい。このような点はJavaScriptの方が好きなところだ。
array_combine関数(おまけ)
以下のように、一方の配列をキー、もう一方の配列を値として、新しい配列を生成する。要素数が一致しない場合、エラーが起こる。
<?php
$a = array('php', 'js');
$b = array(
array('print()', 'array()'),
array('document.write()', 'new Array()')
);
$c = array_combine($a, $b);
var_dump($c);
/*
array(2) {
["php"]=>
array(2) {
[0]=>
string(7) "print()"
[1]=>
string(7) "array()"
}
["js"]=>
array(2) {
[0]=>
string(16) "document.write()"
[1]=>
string(11) "new Array()"
}
}
*/
?>
個人的には、この関数の有用性が分からない。PHPは関数が豊富なのが魅力的の一つだが、無駄な関数もあるのではとか思ってしまうような1つである。
各関数について
- bool array_walk(array &$array, string $callbackname[, mixed $user_data])
- 配列の全ての要素にユーザ関数を適用する。ユーザ関数は第一引数に配列の値をとり、第二引数に配列のキーといった形式になる。
- bool array_walk_recursive(array &$array, string $callbackname[, mixed $user_data])
- 配列の全要素にユーザ関数を適用する(配列の)。ユーザ関数は第一引数に配列の値、第二引数に配列のキーといった形式になる。
- array array_combine(array $keys, array $values)
- 一方の配列をキーとし他方を値として配列を生成する。
TrackBack URL :
Comments (0)
コメントはまだありません»
コメントはまだありません。
この投稿へのコメントの RSS フィード。TrackBack URL
コメントする