PHPで配列を扱っていると、「末尾に値を追加したい」「先頭から1つ取り出したい」といった操作が頻繁に出てきます。そのときに使うのが array_push()・array_pop()・array_shift()・array_unshift() の4つの関数です。名前が似ていて混同しやすいのですが、「配列の先頭を操作するのか末尾を操作するのか」「追加するのか取り出す(削除)のか」で整理すれば、すぐに使い分けられます。この記事では4つの関数の動作・戻り値・注意点を、実際に動くコードと対応表で解説します。配列にまだ慣れていない初心者〜中級者の方が対象です。
目次
先頭・末尾を操作する4つの関数
4つの関数は、すべて渡した配列そのものを直接書き換える(破壊的な)関数です。新しい配列を返すのではなく、元の配列の中身が変わる点を最初に押さえておいてください。役割は「操作する位置」と「動作」の組み合わせで決まります。まずは全体像を表で確認しましょう。
| 関数 | 操作する位置 | 動作 | 戻り値 |
|---|---|---|---|
array_push() | 末尾 | 1つ以上追加 | 追加後の要素数 |
array_pop() | 末尾 | 1つ取り出す | 取り出した要素(空なら null) |
array_shift() | 先頭 | 1つ取り出す | 取り出した要素(空なら null) |
array_unshift() | 先頭 | 1つ以上追加 | 追加後の要素数 |
「push と pop は末尾」「shift と unshift は先頭」とペアで覚えると混乱しません。また、追加系(push / unshift)は追加後の要素数を返し、取り出し系(pop / shift)は取り出した値そのものを返します。それぞれ具体的に見ていきます。
array_push で末尾に追加する
array_push() は配列の末尾に1つ以上の要素を追加します。呼び出し方は array_push($array, $value1, $value2, ...) で、第1引数は参照渡し(元の配列が書き換わる)です。複数の値をまとめて渡すと、その順番のまま末尾に並びます。戻り値は追加した後の要素数です。
<?php
$stack = ["A", "B"];
// 末尾に2つまとめて追加
$count = array_push($stack, "C", "D");
echo $count . "\n";
// 4 ← 追加後の要素数が返る
print_r($stack);
// Array ( [0] => A [1] => B [2] => C [3] => D )
1つだけ追加するなら $arr[] = の方が速い
末尾に追加する値が1つだけの場合は、array_push() よりも $arr[] = $value; という書き方の方が高速です。array_push() は可変長引数を受け取る関数呼び出しのぶんオーバーヘッドがあるためで、PHPの公式マニュアルでも「要素を1つだけ追加するなら $arr[] = ... を使うとよい」と案内されています。複数の値を一度に追加したいときだけ array_push() を使う、と考えると無駄がありません。
<?php
$list = ["A", "B"];
// 1つだけ追加するなら、こちらの方が速い
$list[] = "C";
print_r($list);
// Array ( [0] => A [1] => B [2] => C )
array_pop で末尾を取り出す
array_pop() は配列の末尾から要素を1つ取り出して返します。取り出した要素は配列から取り除かれるので、配列の長さは1つ短くなります。元の配列が空だった場合は null を返します。
<?php
$stack = ["A", "B", "C"];
// 末尾の要素を取り出す
$last = array_pop($stack);
echo $last . "\n";
// C ← 取り出した値
print_r($stack);
// Array ( [0] => A [1] => B ) ← 配列が短くなる
// 空配列に対して呼ぶと null
$empty = [];
var_dump(array_pop($empty));
// NULL
array_shift で先頭を取り出す
array_shift() は配列の先頭から要素を1つ取り出して返します。動作は array_pop() の先頭版ですが、ひとつ重要な違いがあります。先頭を抜くと残った要素が前にずれるため、数値キーは 0 から振り直されるのです。文字列キー(連想配列のキー)はそのまま保持されます。空配列に対して呼ぶと null を返す点は array_pop() と同じです。
<?php
$queue = ["A", "B", "C"];
// 先頭の要素を取り出す
$first = array_shift($queue);
echo $first . "\n";
// A ← 取り出した値
print_r($queue);
// Array ( [0] => B [1] => C )
// ↑ もともと [1]=>B, [2]=>C だったキーが 0 から振り直される
このキーの振り直しは、要素のインデックスに依存した処理を書いているときに思わぬバグの原因になります。array_shift() を使ったあとは、元のキー番号がもう使えないことを意識しておきましょう。
array_unshift で先頭に追加する
array_unshift() は配列の先頭に1つ以上の要素を追加します。array_push() の先頭版で、戻り値は追加後の要素数です。先頭に差し込むぶん既存の要素が後ろにずれるため、こちらも数値キーは 0 から振り直されます(文字列キーは保持)。
<?php
$list = ["C", "D"];
// 先頭に2つまとめて追加
$count = array_unshift($list, "A", "B");
echo $count . "\n";
// 4 ← 追加後の要素数
print_r($list);
// Array ( [0] => A [1] => B [2] => C [3] => D )
// ↑ 渡した順に先頭へ並び、キーは振り直される
スタックとキューを作ってみる
これらの関数を組み合わせると、データ構造の基本である「スタック」と「キュー」を簡単に表現できます。考え方を理解すると、4つの関数の使い分けがいっそう腑に落ちます。
スタック(LIFO): push と pop
スタックは「最後に入れたものを最初に取り出す」(LIFO=Last In, First Out)データ構造です。お皿を積み上げて上から取るイメージですね。末尾に積む array_push() と、末尾から取る array_pop() を組み合わせれば作れます。
<?php
$stack = [];
array_push($stack, "1冊目");
array_push($stack, "2冊目");
array_push($stack, "3冊目");
// 末尾(最後に入れたもの)から取り出す
echo array_pop($stack) . "\n"; // 3冊目
echo array_pop($stack) . "\n"; // 2冊目
echo array_pop($stack) . "\n"; // 1冊目
キュー(FIFO): push と shift
キューは「最初に入れたものを最初に取り出す」(FIFO=First In, First Out)データ構造です。レジの行列のように、先に並んだ人から順に処理されるイメージです。末尾に追加する array_push() と、先頭から取り出す array_shift() を組み合わせます。
<?php
$queue = [];
array_push($queue, "1人目");
array_push($queue, "2人目");
array_push($queue, "3人目");
// 先頭(最初に入れたもの)から取り出す
echo array_shift($queue) . "\n"; // 1人目
echo array_shift($queue) . "\n"; // 2人目
echo array_shift($queue) . "\n"; // 3人目
意図せず元の配列が変わるときの注意
4つの関数に共通する最大の注意点は、すべて元の配列を直接書き換える破壊的な関数だということです。第1引数は参照渡しで受け取られるため、関数を呼んだ時点で渡した配列の中身が変わります。「結果を別の変数で受け取っているから元データは無事だろう」と思っても、元の配列はすでに書き換わっています。元のデータを残したい場合は、操作する前に配列をコピーしておきましょう。
<?php
$original = ["A", "B", "C"];
// 元を残したいので、コピーしてから操作する
$copy = $original;
array_pop($copy);
print_r($original);
// Array ( [0] => A [1] => B [2] => C ) ← 元はそのまま
print_r($copy);
// Array ( [0] => A [1] => B ) ← コピー側だけ変わる
もうひとつ覚えておきたいのが、先頭を操作する array_shift() と array_unshift() では数値キーが振り直される点です(末尾を操作する push / pop ではこの振り直しは起きません)。キー番号を頼りに要素を参照している処理では、先頭操作のあとにキーがずれていないかを必ず確認してください。
まとめ
4つの関数は「先頭か末尾か」「追加か取り出しか」で整理すれば迷いません。要点を振り返ります。
array_push(): 末尾に1つ以上追加。戻り値は追加後の要素数。1つだけなら$arr[] = ...が速いarray_pop(): 末尾を1つ取り出して返す。配列は短くなり、空ならnullarray_shift(): 先頭を1つ取り出して返す。数値キーは 0 から振り直され、空ならnullarray_unshift(): 先頭に1つ以上追加。戻り値は追加後の要素数で、数値キーは振り直される- いずれも元の配列を直接書き換える破壊的な関数。push と pop でスタック、push と shift でキューが作れる
「末尾=push / pop」「先頭=unshift / shift」というペアと、先頭操作でキーが振り直される点さえ押さえておけば、配列への追加・削除はひととおり安心して扱えます。