@blog.justoneplanet.info

日々勉強

JavaScriptとPHPの配列の扱い

そういえば配列における「参照渡し」と「値渡し」の挙動がJavaScriptとPHPで異なっていたので書き留めておくことにする(・∀・)!!

■JavaScript

以下のようにJavaScriptでは、関数に配列を渡すと参照渡しとなる。

var ary = ['a', 'b', 'c'];
var sample = function(ary){
    ary.pop();
}
console.log(ary);// ['a', 'b', 'c']
alert('sample');
sample(ary);
console.log(ary);// ['a', 'b']

ちなみにalertはconsoleが上手く作動しなかったために使用した。

■PHP

以下のようにPHPでは、関数に配列を渡すとPHP4では値渡しとなる。

$ary = array('a', 'b', 'c');
function sample($ary){
    array_pop($ary);
}
var_dump($ary);
sample($ary);
var_dump($ary);

(関数内で配列を変更したい場合、)JavaScriptと同じ挙動をPHPで再現するには以下のように記述する必要がある。

$ary = array('a', 'b', 'c');
function sample(&$ary){
    array_pop($ary);
}
var_dump($ary);
sample($ary);
var_dump($ary);

リソースを節約するには参照渡しを明示したほうがイイね( ^ω^)

PHP Arrays as Stacks, Queues and Set(スタック・待ち行列・和集合)

■スタック

スタックとは

順列において、最初に挿入されたデータが最後に取り出される。最後に挿入したデータが最初に取り出されるデータ構造。LIFO(last in first out)と呼ばれる。

実際のコード

以下のようにarray_push関数を使用すると、第一引数の配列の最後尾に第二引数以降の値を、配列の要素として追加する。また、array_pop関数を使用すると、配列の最終要素を削除し戻り値として返します。

<?php
$stack = array();
array_push($stack, 'John', 'Jack');
var_dump($stack);
/*
array(2) {
  [0]=>
  string(4) "John"
  [1]=>
  string(4) "Jack"
}
*/
$value = array_pop($stack);
var_dump($value);
var_dump($stack);
/*
string(4) "Jack"
array(1) {
  [0]=>
  string(4) "John"
}
*/
?>

但し、array_pushについては以下のようなコードでも同じようなことができる。そして、関数をコールするオーバーヘッドが発生しない分だけわずかに高速である。

<?php
$stack = array();
$stack[] = 'John';
$stack[] = 'Jack';
?>
各関数について
int array_push(array &$ary, mixed $var[, mixed $var, …])
$aryの最後に、第二引数以降の値を配列の要素として追加する。
mixed array_pop(array &$ary)
配列の最後から要素を取り除き、その値を返す。

ちなみにJavaScriptで以下のように書いてしまうと、シンタックスエラーとなる。

var tmpAry[] = 'test';
//syntax error!!

■キュー(待ち行列)

待ち行列とは

データが順列に挿入された順序で、削除(処理)されていくようなデータ構造。FIFO(first in first out)と呼ばれる。

実際のコード

以下のように、array_shift関数を使うと第一引数で指定した配列の最初の要素を削除できる。また、array_unshift関数を使うと第一引数で指定した配列に、第二引数以降の要素を代入することができる。

<?php
$queue = array('John', 'Ken', 'Mike');
$value = array_shift($queue);
var_dump($value);//John
var_dump($queue);
/*
array(2) {
  [0]=>
  string(3) "Ken"
  [1]=>
  string(4) "Mike"
}
*/
array_unshift($queue, 'Nick', 'Emily');
var_dump($queue);
/*
array(4) {
  [0]=>
  string(4) "Nick"
  [1]=>
  string(5) "Emily"
  [2]=>
  string(3) "Ken"
  [3]=>
  string(4) "Mike"
}
*/
?>

shiftとunshiftを使うとスタックと変わらない。従ってキューの実装にはarray_shift()とarray_push()を用いる。

各関数について
mixed array_shift(array &$ary)
配列の先頭から要素を一つ取り出し、その値を返す。
int array_unshift(array &$ary, mixed $var[, mixed $var])
第一引数の配列に、第二引数以降の値を配列の要素として加える。

■集合と配列の比較

集合とは、いくつかの要素の集まったデータ構造。配列を使用すると、集合論の基本となる和集合や積集合、対象差といった演算を実装できる。

和集合

集合Aと集合Bを結合し、重複を取り除いた集合。

<?php
$a = array(1, 5, 3, 9);
$b = array(2, 5, 9, 7);
$tmpAry = array_merge($a, $b);
$set = array_unique($tmpAry);
var_dump($set);
/*
array(6) {
  [0]=>
  int(1)
  [1]=>
  int(5)
  [2]=>
  int(3)
  [3]=>
  int(9)
  [4]=>
  int(2)
  [7]=>
  int(7)
}
*/
?>

配列(集合)の差分

array_diff関数を使うと配列の差を計算することができる。以下のような場合、第一引数の配列の要素で、第二引数以降の配列に含まれて居ない要素を配列として返す。

<?php
$a = array(1, 3, 9, 27);
$b = array(1, 9, 2, 7);
var_dump(array_diff($a, $b));
/*
array(2) {
  [1]=>
  int(3)
  [3]=>
  int(27)
}
*/
?>

また、配列の比較においてキーまで含める場合は以下のように、array_diff_assoc関数を使用する。

<?php
$a = array(1, 3, 9, 27);
$b = array(1, 9, 2, 7);
var_dump(array_diff_assoc($a, $b));
/*
array(3) {
  [1]=>
  int(3)
  [2]=>
  int(9)
  [3]=>
  int(27)
}
*/
?>

配列(集合)の共通項

array_intersect関数は以下のように、配列の共通項のリストを返す。

<?php
$a = array(1, 3, 9, 27);
$b = array(1, 9, 2, 7);
var_dump(array_intersect($a, $b));
/*
array(2) {
  [0]=>
  int(1)
  [2]=>
  int(9)
}
*/
?>

各関数について

array array_merge(array $ary[, array $ary2])
複数の配列をマージし結果を返す。但し、連想配列の文字列が重複している場合は値が上書きされる。
array array_unique(array $ary[, int $sort_flags=SORT_REGULAR])
配列から重複を取り除いた配列を返す。
array array_diff(array $ary1, array $ary2)
$ary1の要素のうち$ary2に含まれないものを配列として返す。
array array_intersect(array $ary1, array $ary2)
配列の共通項を配列として返す。

PHP Sorting Arrays(配列のソート)

■配列の値によるソート(0から始まる数値インデックスに直す)

以下のように、sort関数を使うと値をアルファベット順にソートし、インデックスを振りなおす。また第二引数にはSORT_REGULAR、SORT_NUMERIC、SORT_STRINGなどを取り、型を変換する事もできる。

<?php
$tmpAry = array(
    'person1' => 'Emily',
    'person2' => 'Dennis',
    'person3' => 'Andy'
);
sort($tmpAry);
var_dump($tmpAry);
/*
array(3) {
  [0]=>
  string(4) "Andy"
  [1]=>
  string(6) "Dennis"
  [2]=>
  string(5) "Emily"
}
*/
?>

逆順にソートするには

以下のようにrsort関数を使用すると、sort関数を使った時とは逆順に並ぶ。

<?php
$tmpAry = array(
    'person1' => 'Andy',
    'person2' => 'Dennis',
    'person3' => 'Emily'
);
rsort($tmpAry);
var_dump($tmpAry);
/*
array(3) {
  [0]=>
  string(5) "Emily"
  [1]=>
  string(6) "Dennis"
  [2]=>
  string(4) "Andy"
}
*/
?>

戻り値について

以下の例のようにsort関数は配列自身を変換し、戻り値は処理の成否についてのbool値が格納されるだけである。基本的に配列ソート関数は全て配列自身を変換し、戻り値は処理の成否としてのbool値となる。

<?php
var_dump(sort($tmpAry));//true or false
?>

ユーザー指定関数での並び替え

以下のようにusort関数を使用する。第二引数には文字列で関数名を指定する。(但し、以下の例はグローバル空間が汚れないように、create_function関数を使っての匿名関数を利用している。)

<?php
$ary = array(1, 5, 2);
usort(
    $ary,
    create_function(
        '$a,$b',
        'if($a < $b){return 1;}if($a === $b){return 0;}if($a > $b){return -1;}'
    )
);
var_dump($ary);
/*
array(3) {
  [0]=>
  int(5)
  [1]=>
  int(2)
  [2]=>
  int(1)
}
*/
?>

■配列の値によるソート(キーとの関係は維持)

以下のようにasort関数を使うとキーとの関係は維持されつつ、値によるソートが行われる。

<?php
$tmpAry = array(
    'person1' => 'Emily',
    'person2' => 'Dennis',
    'person3' => 'Andy'
);
asort($tmpAry);
var_dump($tmpAry);
/*
array(3) {
  ["person3"]=>
  string(4) "Andy"
  ["person2"]=>
  string(6) "Dennis"
  ["person1"]=>
  string(5) "Emily"
}
*/
?>

逆順にしたい時にはarsort関数を使用し、ユーザー定義関数でソートしたいときにはuasort関数を使用する。但し、今考える限りではキーとの関係を維持したままソートする有用なシチュエーションは思い浮かばない。

■配列のキーによるソート

以下のようにksort関数を使うと、配列のキーによってソートされる。

<?php
$tmpAry = array(
    'Naomi' => 'student',
    'Dennis' => 'driver',
    'Emily' => 'traveler'
);
ksort($tmpAry);
var_dump($tmpAry);
/*
array(3) {
  ["Dennis"]=>
  string(6) "driver"
  ["Emily"]=>
  string(8) "traveler"
  ["Naomi"]=>
  string(7) "student"
}
*/
?>

また、逆順にしたい時はkrsort関数を使い、ユーザー定義関数でソートしたい時はuksort関数を使う。

PHPは内部的に配列のキーとは別に順序を持っている。内部順序とキーの順序が違う場合、json_encode関数を使うと変換が異なるので注意しなくてはならない。

<?php
$tmpAry = array(
    2 => 'Naomi',
    1 => 'Dennis',
    0 => 'Emily'
);
var_dump($tmpAry);
ksort($tmpAry);
var_dump($tmpAry);
/*
array(3) {
  [2]=>
  string(5) "Naomi"
  [1]=>
  string(6) "Dennis"
  [0]=>
  string(5) "Emily"
}
string(38) "{"2":"Naomi","1":"Dennis","0":"Emily"}"
array(3) {
  [0]=>
  string(5) "Emily"
  [1]=>
  string(6) "Dennis"
  [2]=>
  string(5) "Naomi"
}
string(26) "["Emily","Dennis","Naomi"]"
*/
?>

■まとめ

一覧にまとめると以下のようになる。

処理 昇順 降順 ユーザー定義
値によるソート、インデックスの再ラベリング sort rsort usort
値によるソート asort arsort uasort
キーによるソート ksort krsort uksort

個人的な考えだが「昇順と降順」は引数でコントロールできるようにしてもイイと思う。

ユーザー定義関数について

<?php
$ary = array(1, 5, 2);
usort(
    $ary,
    create_function(
        '$a,$b',
        'if($a < $b){return 1;}if($a === $b){return 0;}if($a > $b){return -1;}'
    )
);
var_dump($ary);
/*
array(3) {
  [0]=>
  int(5)
  [1]=>
  int(2)
  [2]=>
  int(1)
}
*/
?>
  • 引数を2つとる
  • 「if($a < $b){return 1;}」は「$a<$b」の時、そのままの順序である事を意味する。
  • 「if($a > $b){return -1;}」は「$a>$b」の時、前後を入れ替える事を意味する。
  • 「if($a === $b){return 0;}」は「$a === $b」の時、特に何もしない事を意味する。

つまり、比較関数は最初の引数が2番目の引数より小さいか、等しいか、大きい場合に、 それぞれゼロ未満、ゼロに等しい、ゼロより大きい整数を返す。

■自然順ソート

通常のソート関数を使うと、以下のように不自然な結果となる。

<?php
$tmpAry = array('10km', '5km', '7km');
sort($tmpAry);
var_dump($tmpAry);
/*
array(3) {
  [0]=>
  string(4) "10km"
  [1]=>
  string(3) "5km"
  [2]=>
  string(3) "7km"
}
*/
?>

以下のようにnatsort関数を使用すると、数字+単位のように扱われ、自然な並び順となる。また、大文字と小文字を区別しないnatcasesort関数もある。

<?php
$tmpAry = array('10km', '5km', '7km');
natsort($tmpAry);
var_dump($tmpAry);
/*
array(3) {
  [1]=>
  string(3) "5km"
  [2]=>
  string(3) "7km"
  [0]=>
  string(4) "10km"
}
*/
?>

各関数について

bool natsort(array &$ary)
自然順で配列をソートする。
bool natcasesort(array &$ary)
大文字と小文字を区別しない自然順アルゴリズムでソートする。

■配列のシャッフル

以下のようにshuffle関数を使うと、配列をランダムに並び替えることができる。以下の結果は実行ごとに異なるが、キーは必ず削除され数値のインデックスが割り当てられる。

<?php
$tmpAry = array(
    'person1' => 'Emily',
    'person2' => 'Dennis',
    'person3' => 'Andy'
);
shuffle($tmpAry);
/*
array(3) {
  [0]=>
  string(6) "Dennis"
  [1]=>
  string(5) "Emily"
  [2]=>
  string(4) "Andy"
}
*/
?>

各巻数について

bool shuffle(array &$ary)
配列をシャッフルする。但し、既存のキーは削除される。

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. 1回目のループ:&$valueは配列の各要素の住所(リファレンス)となる。
  2. 1回目のループ:&$valueは配列の最終要素のリファレンス(&$names[2])となる。
  3. 2回目のループ:各要素が既にassignされている$value(&$names[2])に代入されていく。

つまり、$names[2] = $valueがループごとに起こる。

  1. 2回目のループ(1):$names[2]にNickが代入される。
  2. 2回目のループ(2):$names[2]にJohnが代入される。
  3. 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)
一方の配列をキーとし他方を値として配列を生成する。

PHP Array Operations(配列における演算子)

多くの演算子は、配列かどうかで異なった振る舞いをする。

<?php
$a = array(1, 2, 3);
$b = array('a' => 1, 'b' => 2, 'c' => 3);
var_dump($a + $b);
/*
array(6) {
  [0]=>
  int(1)
  [1]=>
  int(2)
  [2]=>
  int(3)
  ["a"]=>
  int(1)
  ["b"]=>
  int(2)
  ["c"]=>
  int(3)
}
*/
?>

但し、配列のキーに重複が存在する場合は結果が異なる。

<?php
$a = array(1, 2, 3);
$b = array('a' => 1, 2, 3);
var_dump($a + $b);
/*
array(4) {
  [0]=>
  int(1)
  [1]=>
  int(2)
  [2]=>
  int(3)
  ["a"]=>
  int(1)
}
*/
?>

■配列の比較

配列は以下のように、演算子(==、===)を使って比較することができる。

<?php
$a = array(1, 2, 3);
$b = array(0 => 1, 1 => 2, 2 => 3);
$c = array('a' => 1, 'b' => 2, 'c' => 3);
$d = array(2 => 3, 0 => 1, 1 => 2);
var_dump($a == $b);//true
var_dump($a === $b);//true
var_dump($a === $d);//false
var_dump($a == $c);//false
var_dump($a === $c);//false
?>

基本的には、キーと値のペアが同じように存在していればtrueを返す。注目するべきなのは、$bと$dの違いである。キーと値のペアは同様に存在しているが、順序が異なっているとPHP内部では異なった配列として扱われている。その結果、2番目と3番目の表示が異なっている。

■配列の要素

要素数

以下の例が示すとおり(JavaScriptのlengthと同様)count関数は、スカラー値が引数に指定された時に常に1を返すため、配列かどうかの判定には使えない。

<?php
$tmAry = array(1, 4, 16);
print(count($tmpAry));//3
$tmpStr = 'sample';
print(count($tmpStr));//1
?>

配列かどうかの判定をするには、以下のようにis_array関数を使う。

<?php
if(is_array($tmpAry)){
    //code
}
?>

任意の要素が存在するかテストする

以下のようにin_array関数を使う。またデフォルトでは型のチェックは行われないが、3番目の引数にtrueをセットすることにより、型のチェックまで行うことができる。

<?php
$tmpAry = array(1, 4, 16);
if(in_array(4, $tmpAry)){//true
    //code
}
?>

要素の削除

要素を削除するには、以下のようにunset関数を使用する。

<?php
$tmpAry = array(1, 4, 16);
unset($tmpAry[1]);
if(in_array(4, $tmpAry)){//false
    //code
}
?>

ランダムに要素を取得する

array_rand関数を使用すると、第二引数で指定した数だけランダムに配列から要素を取り出す。第二引数のデフォルトは1である。また、第二引数が2以上の場合だけ、戻り値も配列となる。

<?php
$tmpAry = array('a' => 'sample', 'b' => 'test', 'c' => 'prototype');
$value = array_rand($tmpAry);//string(1) "b"
$values = array_rand($tmpAry, 2);
/*
array(2) {
  [0]=>
  string(1) "a"
  [1]=>
  string(1) "b"
}
*/
?>
各関数について
bool in_array(mixed $needle, array $haystack[, bool $strict=false])
$needleが配列$haystackに存在するかを返す。第三引数で「true」を指定すると型の整合性まで調べる。
mixed array_rand(array $input[, int $num_request=1])
ランダムに配列のキーを選び、その値を返す。第二引数に2以上の値を設定した場合は、配列のキーの配列が返る。
void unset(mixed $var[, …])
指定した変数の割り当てを解除する。但し、実際には関数ではなく言語構造である。

■配列のキーを取得

以下のようにarray_keys関数を使用すると、配列のキーが配列として返される。

<?php
$tmpAry = array('a' => 'sample', 'b' => 'test', 'c' => 'prototype');
$keys = array_keys($tmpAry);
var_dump($keys);
/*
array(3) {
  [0]=>
  string(1) "a"
  [1]=>
  string(1) "b"
  [2]=>
  string(1) "c"
}
*/
?>

各関数について

array array_keys(array $input)
配列のキーを全て返す。

■配列の反転

キーと値の反転

<?php
$tmpAry = array('a' => 'sample', 'b' => 'test', 'c' => 'prototype');
var_dump(array_flip($tmpAry));
/*
array(3) {
  ["sample"]=>
  string(1) "a"
  ["test"]=>
  string(1) "b"
  ["prototype"]=>
  string(1) "c"
}
*/
?>

順序の反転

以下のようにarray_reverse関数は順序を逆にした配列を返す。但し、キーが文字列のペアの関係性は保持され、キーが数値の要素のみ順序が逆になる。また以下の例を見ての通り、array()で指定した順序と逆の結果が出力される。

<?php
$tmpAry = array(0 => 'sample', 1 => 'test', 'c' => 'prototype');
var_dump(array_reverse($tmpAry));
/*
array(3) {
  ["c"]=>
  string(9) "prototype"
  [0]=>
  string(4) "test"
  [1]=>
  string(6) "sample"
}
*/
?>

個人的には、この手の関数は殆ど使用した事はない。

各関数について
array array_flip(array $ary)
配列$aryのキーが値に、値がキーになった配列を返す。但し、キーに重複が出た場合は最後の値で上書きされる。また、値にオブジェクトなどがあった場合は、警告を発し処理が飛ばされる。
array array_reverse(array $ary[, bool $preserve_keys=false])
要素を逆順にした配列を返す。第二引数が「true」の場合は、キーが保持される。

PHP Array Basics(配列の基本)

■配列の種類

インデックス配列

キーが数字の、いわゆる普通の配列。

<?php
$ary = array(10, 20, 30);
?>

連想配列

キーが文字列。特に連想配列の場合は以下のように記述して縦の列を揃えると、コードが見やすくなる。

<?php
$ary = array(
    'a' => 'John',
    'b' => 'Nick',
    'c' => 'Michel'
);
?>

■配列の生成方法

関数を使う

<?php
$ary = array(1, 3, 7);
?>

[]を使う

存在しない配列にデータを代入しようとすると、その時点で配列が生成される。その原理を利用する方法。

<?php
$ary[0] = 1;
$ary[1] = 3;
$ary[2] = 7;
?>
各関数について
array array([mixed $var, …])
配列を生成する。但し、実際には関数ではなく言語構造である。

■配列の表示

デバッグなどを目的として配列の構造と要素を表示したい時、以下の2つの関数は各要素を再帰的に表示する。

print_r()

第2引数にtrueを設定する事により戻り値を発生させ、変数に値を格納させる事ができる。また配列のポインタは末端に移動する。

<?php
$ary = array(
    1 => 'sample',
    'a' => array(1,5,9),
    2 => 5
);
print_r($ary);
/*
Array
(
    [1] => sample
    [a] => Array
        (
            [0] => 1
            [1] => 5
            [2] => 9
        )

    [2] => 5
)
*/
?>

var_dump()

引数に1つ以上の変数をとり、複数の変数を表示させる事ができる。より詳細なデータが見れるので、デバッグ目的ではコチラの関数を個人的には多用している。

<?php
$ary = array(
    1 => 'sample',
    'a' => array(1,5,9),
    2 => 5
);
var_dump($ary);
/*
array(3) {
  [1]=>
  string(6) "sample"
  ["a"]=>
  array(3) {
    [0]=>
    int(1)
    [1]=>
    int(5)
    [2]=>
    int(9)
  }
  [2]=>
  int(5)
}
*/
?>
各関数について
mixed print_r(mixed $expression[, bool $return=false])
指定した変数の詳細を型に合わせて表示する。但し、第二引数に「true」を設定すると値を返す。
void var_dump(mixed $expression[, mixed $expression])
指定した変数の詳細を型に合わせて表示する。複数の変巣を一度に表示することができる。

■配列末尾への値の追加

以下のコードは、0から始まる数値のうち、最初に見つかった空きインデックスに要素を追加する方法。連想配列に対しても使用が可能であり、0から数値が割り当てられていくが、通常ではそのような使用はしない。

<?php
$person[0] = 'Mike';
$person[] = 'Nick';//1が割り当てられる
?>

但し、0から始まる数値のうち任意の正の数字インデックスが使用されている場合は、以下のようにそのインデックスの次の数字から値が格納されていく。

<?php
$tmpAry = array();
$tmpAry[10] = '1';
$tmpAry[] = 'test';//11が割り当てられる
var_dump($tmpAry);
/*
array(2) {
  [10]=>
  string(1) "1"
  [11]=>
  string(4) "test"
}
*/
?>

■Multi-dimentional Arrays(多次元配列)

<?php
$ary = array();
$ary[] = array(
    'Nick',
    'John'
);
$ary[] = array(
    'Emily',
    'Naomi'
);
print("Hello, {$ary[0][1]} and {$ary[1][1]}");
?>

活用例

$tmpAry = array();
foreach($ary as $key => $value){
    if(!is_array($tmpAry[$key])){
        $tmpAry[$key] = array();
    }
    $tmpAry[$key]['id'] = $value['id'];
    $tmpAry[$key]['value'] = $value['value'];
}

よりも以下のコードの方が美しいと思う。

$tmpAry = array();
foreach($ary as $key => $value){
    $tmpAry[] = array(
        'id' => $value['id'],
        'value' => $value['value'],
    );
}

■配列の展開

listは実際には言語の構成要素であり戻り値を発生させない。また左辺のlistの引数が多い場合、余った変数にnullが代入される。右辺の配列の要素数が多い場合、特に問題は発生しない。

<?php
$peple = array('John', 'Mike', 'Nick');
list($person1, $person2, $person3) = $people;
?>

以下のような場合に有用かもしれない。

<?php
$sql = "SELECT `name`, `age`, `job` FROM `data`";
$result = mysql_query($sql);
while(list($name, $age, $job) = $mysql_fetch_row($result)){
    echo "{$name}({$age}) - {$job}";
}
?>

但し、個人的には以下のようにループを使って処理するタイプなのでlistを使うことは少ない。

<?php
$sql = "SELECT `name`, `age`, `job` FROM `data`";
$result = mysql_query($sql);
while($row = mysql_fetch_array($result)){
    echo "{$row['name']}({$row['age']}) - {$row['job']}";
}
?>

各関数について

void list(mixed $var[, …])
複数の変数に配列の値を格納する。実際には関数ではなく言語構造である。