【PHP入門講座】 配列

### [目次に戻る](http://qiita.com/mpyw/items/752e19a578cf7d96fc5f)

# 配列の生成

## <ins>一般的に</ins>配列とは何か

例えば次のような要望があったとします。

「1ヵ月間の毎日の起床時刻を記録したデータがあります。これをPHPにて変数に格納してください。」

|  **日** | **時刻** |
|----:|----:|
| 1 | 7 |
| 2 | 8 |
| 3 | 7 |
| … | … |
| 31 | 7 |

さあ、あなたならどうしますか？
(以降は簡単のため、1～3日までのデータを扱います。)

```php
$d1 = 7;
$d2 = 8;
$d3 = 7;
```

のように連番を振った変数を作りますか？31個作った時に扱うの大変そうですね。

ここで **配列** の出番です。配列生成には **`array()`** 構文を使います。関数ではなく言語構文です。PHP5.4以降では `array()` の代わりに `[ ]` を使うことができますが、(後で説明する) **キー** を指定する `[ ]` と慣れるまでは紛らわしいので、この講座では `array()` で統一することにします。

以下のコードを実行してみましょう。

```php:PHPコード
<?php
$data = array(7, 8, 7);
var_dump($data);
```

```text:実行結果
array(3) {
  [0]=>
  int(7)
  [1]=>
  int(8)
  [2]=>
  int(7)
}
```

配列とは何かを理解するためには、やっぱり `var_dump` するのが一番分かりやすいです。

```text
array(3)
```

これは、配列の要素が合計 `3` 個であることを示しています。

```text
[0]=>
int(7)
```

これは、`0` 番目の値が整数の `7` であることを示しています。

```text
[1]=>
int(8)
```

これは、`1` 番目の値が整数の `8` であることを示しています。

`0` 番目から始まることに違和感を覚える人もいるかもしれませんが、 基本的に <ins>どのプログラミング言語でもこの考え方は共通</ins> となっています。徐々に慣れていきましょう。

なお、今回は整数を扱いましたが、実は<ins>配列はどんな型でも扱うことが出来ます</ins>。配列の中に配列を入れることも可能です ( **多次元配列** と呼ばれる ) 。

## <ins>PHP言語における</ins>配列とは何か(導入)

さて、ついさっき

> ```text
> [0]=>
> int(7)
> ```
> 
> これは、`0` 番目の値が整数の `7` であることを示しています。

と書きましたが、これは<ins>間違っています</ins>。正しくはこうです。

> ```text
> [0]=>
> int(7)
> ```
> 
> これは、キー `0` に対応する値が整数の `7` であることを示しています。

ここで **連想配列** という考え方を導入する必要が出てきます。

## 連想配列とは何か

「マジカルバナナ」というゲームを思い出してください。 **『バナナといったら黄色、黄色といったら信号機』** のように思いつく限りリレーのように連想する内容を繋げていく内容です。このゲームが行われていた1990年代のテレビ番組「マジカル頭脳パワー」を知らない若い世代の人は適当にWikipediaとか見てください(笑)

さて、この内容を連想配列で表してみます。

```php:PHPコード
$data = array(
    'バナナ' => '黄色',
    '黄色' => '信号機'
);
var_dump($data);
```

```text:実行結果
array(2) {
  ["バナナ"]=>
  string(6) "黄色"
  ["黄色"]=>
  string(9) "信号機"
}
```

連想配列とは、このように **「 `A` に対応する値は `B` , `C` に対応する値は `D` , ...」** といったデータ構造を意味します。PHPにおける実装は上記の結果の通りです。

この `A` `C` のことを **キー** または **添字** 、 `B` `D` のことを **値** と呼びます。鍵付きの箱があって、それを開けるために必要なのが「鍵(キー)」で、中に入っているのが「値」というイメージでいいでしょう。

また、配列の生成に使われる演算子 **`=>`** は **ダブルアロー演算子** と呼ばれます。アローは **矢印** という意味です。「クラスとオブジェクト」で学習する **`->`** は **アロー演算子** と呼ばれますが、これが2重(ダブル)になったものと考えてください。これらは似て非なるものです。

## 連想配列のキーに使えるもの

先ほど値はどんなものでも扱えると述べましたが、対照的にキーには大きな制約があります。

- **整数** か **文字列** しか使えません。
- 「配列」「オブジェクト」「リソース」がキーとして使われようとするとWarningが発生します。

```php:PHPコード
$data = array(
    array('foo') => 'bar'
);
```

```text:実行結果
PHP Warning:  Illegal offset type in ...
```

- 整数に変換可能な形式の文字列がきたとき、整数に変換されることがあります。

「ことがあります」と述べたのは、それら全てが該当するわけではないからです。

```php:PHPコード
$data = array(
    '0' => 'A',
    '+1' => 'B',
    '-1' => 'C',
    '00' => 'D',
    '01' => 'E',
    '1e1' => 'F',
    '2147483647' => 'G',
    '2147483648' => 'H'
);
var_dump($data);
```

```text:32ビット環境での実行結果
array(8) {
  [0]=>
  string(1) "A"
  ["+1"]=>
  string(1) "B"
  [-1]=>
  string(1) "C"
  ["00"]=>
  string(1) "D"
  ["01"]=>
  string(1) "E"
  ["1e1"]=>
  string(1) "F"
  [2147483647]=>
  string(1) "G"
  ["2147483648"]=>
  string(1) "H"
}
```

`0` と `-1` と `2147483647` だけが整数に変換されていますね。これからPHPの挙動を推察すると、変換される条件として<ins>「文字列を整数に変換したものをまた文字列に変換し直しても、元のデータが復元できる」</ins>ということが導かれます。加えて、整数の範囲外にある数値は無視されることも言えます。

- 整数は **オーバーフロー** を起こします。

通常PHPの整数がオーバーフローを起こしたときは自動的に浮動小数点数に変換されて補正されますが、<ins>配列のキーに関してはオーバーフローしたまま放置される仕様</ins>のようです。

```php:PHPコード
$data = array(
    2147483647 => 'A',
    2147483648 => 'B'
);
var_dump($data);
```

```text:32ビット環境での実行結果
array(2) {
  [2147483647]=>
  string(1) "A"
  [-2147483648]=>
  string(1) "B"
}
```

- 浮動小数点数は<ins>切り捨て</ins>られます。
- `TRUE` は整数の **`1`** に変換されます。
- `FALSE` は整数の **`0`** に変換されます。
- `NULL` は **空文字列** に変換されます。

```php:PHPコード
$data = array(
    2.5 => 'A',
    true => 'B',
    false => 'C',
    null => 'D'
);
var_dump($data);
```

```text:実行結果
array(4) {
  [2]=>
  string(1) "A"
  [1]=>
  string(1) "B"
  [0]=>
  string(1) "C"
  [""]=>
  string(1) "D"
}
```

- 同じキーが複数セットされようとしたとき、 <ins>後から出現したものが優先されます</ins>。

```php:PHPコード
$data = array(
    1 => 'A',
    1 => 'B'
);
var_dump($data);
```

```text:実行結果
array(2) {
  [1]=>
  string(1) "B"
}
```

## PHPの配列は全て連想配列？

最初に示した

> ```php
> $data = array(7, 8, 7);
> ```

この例ですが、実は以下の省略形となっています。

```php
$data = array(
    0 => 7,
    1 => 8,
    2 => 7
);
```

実装上は<ins>PHPの配列は全て連想配列</ins>であると言えるでしょう。但し便宜的に、上記のように<ins>0から始まる連続した整数でキーが構成される連想配列</ins>のみ、単純に「配列」と呼ぶことが一般的です。それ以外は全て「連想配列」と呼ばれます。

## 連想配列を書くときの心がけ

`array()` は関数ではなく言語構文であるが故に、<ins>末尾の値の後ろにカンマを入れても正しく動作する</ins>ようになっています。実は、こちらの方が推奨されています。連想配列というよりは、配列の要素を改行して縦に書き並べるとき、と言うべきでしょうか。

```php
$data = array(
    'バナナ' => '黄色',
    '黄色' => '信号機',
);
```

どうしてかというと、この方がソースコードを編集して配列の要素を入れ替えるとき、書き換えがラクになるからです。

```php
$data = array(
    '黄色' => '信号機',
    'バナナ' => '黄色',
);
```

末尾にカンマをつけていれば単純に1行を切り取って貼り付けるだけで出来ますね。今後は基本的にこれに従って書くことが多くなると思います。

# 配列要素の表し方

以下のような配列があるとします。

```php
$data = array(
    0 => 'X',
    'A' => 'Y',
);
```

## 整数のキー

この `X` を出力したいときは、次のように書きます。

```php
echo $data[0];
```

こちらも配列生成時と同じように整数変換のルールが適用されるので、

```php
echo $data['0'];
```

としても同じ結果が得られます。

## 文字列のキー

`Y` を出力したいときは次のように書きます。

```php
echo $data['A'];
```

こちらに関して、初心者の方が

```php
echo $data[A];
```

とされるケースが多く見受けられますが、こうすると **定数 `A`** を表すようになってしまいます。もしこの定数が存在しなかった場合には **Notice** を発生しながらも動作するようになっていますが、これは ***歴史的な理由*** によるものであり、この書き方をするのは強く非推奨とさせていただきます。

だからと言って変数で指定するときにも下記のようにしてしまうのは誤りです。

```php:これでも動作しますが、こうする必要はありません
$k = 'A';
echo $data["$k"];
```

```php:こうするとキー「$k」となってしまうので誤りです
$k = 'A';
echo $data['$k'];
```

以下で十分です。

```php
$k = 'A';
echo $data[$k];
```

# 配列の操作

## 要素の書き換え

キーを指定して代入し直します。

```php:PHPコード
$data = array(
    'バナナ' => '黄色',
    '黄色' => '信号機',
);
$data['黄色'] = 'レモン';
var_dump($data);
```

```text:実行結果
array(2) {
  ["バナナ"]=>
  string(6) "黄色"
  ["黄色"]=>
  string(9) "レモン"
}
```

## 要素の追加

### 文字列のキー

キーを指定して代入します。要素は配列の末尾に追加されます。

```php:PHPコード
$data = array(
    'バナナ' => '黄色',
    '黄色' => '信号機',
);
$data['信号機'] = '交差点';
var_dump($data);
```

```text:実行結果
array(3) {
  ["バナナ"]=>
  string(6) "黄色"
  ["黄色"]=>
  string(9) "信号機"
  ["信号機"]=>
  string(9) "交差点"
}
```

### 整数のキー

こちらも文字列と同様の代入を行えます。

```php:PHPコード
$data = array('A', 'B', 'C');
$data[5] = 'F';
var_dump($data);
```

```text:実行結果
array(4) {
  [0]=>
  string(1) "A"
  [1]=>
  string(1) "B"
  [2]=>
  string(1) "C"
  [5]=>
  string(1) "F"
}
```

<ins>現在の最大のキーの次に追加する場合にはキーを省略することが可能</ins>です。

```php:PHPコード
$data = array('A', 'B', 'C');
$data[] = 'D';
var_dump($data);
```

```text:実行結果
array(4) {
  [0]=>
  string(1) "A"
  [1]=>
  string(1) "B"
  [2]=>
  string(1) "C"
  [3]=>
  string(1) "D"
}
```

ここで少し注意点があります。

- **負の数** の次はどんな場合でも `0` となります。

```php:PHPコード
$data = array(-3 => 'A');
$data[] = 'B';
var_dump($data);
```

```text:実行結果
array(4) {
  [-3]=>
  string(1) "A"
  [0]=>
  string(1) "B"
}
```

- 文字列キーと整数キーが混在した配列の場合、次の値は **最大の整数キー + `1`** となります。

```php:PHPコード
$data = array(
    0 => 'X',
    'A' => 'Y',
);
$data[] = 'Z';
var_dump($data);
```

```text:実行結果
array(4) {
  [0]=>
  string(1) "X"
  ["A"]=>
  string(1) "Y"
  [1]=>
  string(1) "Z"
}
```

- 最大の整数キー + `1` が整数の範囲を超える場合、 **Warning** が発生します。

```php:PHPコード
$data = array(2147483647 => 'A');
$data[] = 'B';
```

```text:32ビット環境での実行結果
PHP Warning:  Cannot add element to the array as the next element is already occupied in ...
```

## 要素の削除

**`unset`** 構文を用います。この構文の詳細については後ほどまた触れ直します。

```php:PHPコード
$data = array('A', 'B', 'C');
unset($data[1]);
var_dump($data);
```

```text:実行結果
array(4) {
  [0]=>
  string(1) "A"
  [2]=>
  string(1) "C"
}
```