「配列をクエリ文字列化」で何をしたいのか
まず、ゴールのイメージからいきます。
['q' => 'php', 'sort' => 'desc', 'page' => 2]
→ "q=php&sort=desc&page=2"
['tag' => ['php', 'laravel', 'symfony']]
→ "tag%5B0%5D=php&tag%5B1%5D=laravel&tag%5B2%5D=symfony"
['tag' => ['php', 'laravel'], 'page' => 1]
→ "tag%5B0%5D=php&tag%5B1%5D=laravel&page=1"
やりたいことはシンプルです。
「連想配列(パラメータの集合)」を、
URL の?以降に付けられる「クエリ文字列」に変換したい。
業務だと、こんな場面でよく使います。
検索条件の配列から検索結果ページの URL を組み立てる。
API に送るパラメータをクエリ文字列にする。
既存の URL に、追加のパラメータをマージして新しい URL を作る。
ここを手作業で "q=".$params['q']."&sort=".$params['sort']... とやり始めると、
すぐにバグとメンテ地獄になります。
PHP には、これを一発でやってくれる関数がちゃんと用意されています。
PHP の基本:http_build_query で配列 → クエリ文字列
http_build_query の基本形
クエリ文字列を組み立てる標準関数は http_build_query です。
string http_build_query(
array|object $data,
string $numeric_prefix = "",
?string $arg_separator = null,
int $encoding_type = PHP_QUERY_RFC1738
)
PHP初心者向けに、まずはこう覚えてください。
「配列からクエリ文字列を作りたいときは、とりあえず
http_build_query($params)」
これだけでかなり戦えます。
一番シンプルな例
$params = [
'q' => 'php',
'sort' => 'desc',
'page' => 2,
];
$query = http_build_query($params);
echo $query;
// q=php&sort=desc&page=2
PHPキーと値が key=value の形になり、& でつながった文字列ができます。
値は自動的に URL エンコードされるので、
スペースや日本語が入っていても安全です。
配列パラメータ(tag[]=php みたいなやつ)もそのままいける
PHP 的な「配列のクエリ表現」
フォームから送られてくる「複数選択」の値などは、
だいたいこういう形になります。
tag[]=php&tag[]=laravel&tag[]=symfony
PHPこれを配列で表現すると、こうです。
$params = [
'tag' => ['php', 'laravel', 'symfony'],
];
PHPhttp_build_query にそのまま渡してみます。
$params = [
'tag' => ['php', 'laravel', 'symfony'],
];
$query = http_build_query($params);
echo $query;
// tag%5B0%5D=php&tag%5B1%5D=laravel&tag%5B2%5D=symfony
PHPtag[0] の [ ] が URL エンコードされて %5B %5D になっているだけで、
意味としては「tag[0]=php&tag[1]=laravel…」です。
ブラウザや PHP 側で解釈するときには、
ちゃんと配列として扱えます。
「見た目を tag[]=php にしたい」場合
もし、どうしても
tag[]=php&tag[]=laravel
PHPという形にしたい場合は、
配列のキーを明示的に空文字にしておきます。
$params = [
'tag' => [
'' => 'php',
'' => 'laravel', // 実際は上書きされるので、このやり方は現実的ではない
],
];
PHPただ、これは実用的ではありません。
実務では、
tag%5B0%5D=php&tag%5B1%5D=laravel
PHPのような形でも問題なく動くことがほとんどなので、
「http_build_query に任せる」で割り切ってしまって大丈夫です。
URL と組み合わせて使うユーティリティを作る
ベース URL + パラメータ配列 → 完成 URL
一番よくあるのは、
「ベース URL は決まっていて、そこにパラメータ配列をくっつけたい」
というパターンです。
例えば、
$baseUrl = "https://example.com/search";
$params = ['q' => 'php', 'sort' => 'desc'];
PHPから、
https://example.com/search?q=php&sort=desc
を作りたい。
これを毎回文字列連結でやるのは危険なので、
ユーティリティ関数にしてしまいます。
/**
* ベース URL にクエリパラメータを付けて新しい URL を作る
* すでにクエリが付いている場合はマージする
*/
function buildUrlWithQuery(string $baseUrl, array $params): string
{
$parsed = parse_url($baseUrl);
$existing = [];
if (isset($parsed['query']) && $parsed['query'] !== '') {
parse_str($parsed['query'], $existing);
}
// 既存パラメータと新しいパラメータをマージ(新しい方が優先)
$merged = array_merge($existing, $params);
$query = http_build_query($merged);
// クエリなしなら、そのまま返す
if ($query === '') {
return $baseUrl;
}
// ベース URL から既存のクエリとフラグメントを取り除いて再構築
$scheme = $parsed['scheme'] ?? null;
$host = $parsed['host'] ?? null;
$port = $parsed['port'] ?? null;
$path = $parsed['path'] ?? '';
$fragment = $parsed['fragment'] ?? null;
$url = '';
if ($scheme !== null) {
$url .= $scheme . '://';
}
if ($host !== null) {
$url .= $host;
}
if ($port !== null) {
$url .= ':' . $port;
}
$url .= $path;
$url .= '?' . $query;
if ($fragment !== null) {
$url .= '#' . $fragment;
}
return $url;
}
PHP使い方の例です。
$base = "https://example.com/search";
$params = ['q' => 'php', 'sort' => 'desc'];
echo buildUrlWithQuery($base, $params);
// https://example.com/search?q=php&sort=desc
PHPすでにクエリが付いている場合も、マージしてくれます。
$base = "https://example.com/search?page=2";
$params = ['q' => 'php'];
echo buildUrlWithQuery($base, $params);
// https://example.com/search?page=2&q=php
PHP同じキーがある場合は、新しい方が優先されます。
$base = "https://example.com/search?page=2";
$params = ['page' => 5, 'q' => 'php'];
echo buildUrlWithQuery($base, $params);
// https://example.com/search?page=5&q=php
PHPここまでできると、「URL+配列」の組み立てがかなり楽になります。
エンコードの話を少しだけ深掘りする
http_build_query は自動で URL エンコードしてくれる
http_build_query は、値を自動的に URL エンコードしてくれます。
$params = [
'q' => 'PHP & URL encode テスト',
];
echo http_build_query($params);
// q=PHP+%26+URL+encode+%E3%83%86%E3%82%B9%E3%83%88
PHP& やスペース、日本語などがちゃんとエンコードされています。
自分で rawurlencode などをかけてから http_build_query に渡すと、
二重エンコードになってしまうので注意してください。
「配列 → クエリ文字列」のときは、
基本的に http_build_query に丸投げで OK です。
区切り文字を変えたい場合(& 以外)
デフォルトでは & で区切られますが、arg_separator を指定すると変えられます。
$params = ['a' => 1, 'b' => 2];
echo http_build_query($params, '', '&'); // a=1&b=2
echo http_build_query($params, '', '&'); // a=1&b=2
PHPHTML の中に直接埋め込むときに & を使いたい場合などに使います。
ただし、初心者のうちは「デフォルトの & のまま」で十分です。
まとめ:今日からの「配列をクエリ文字列化」ユーティリティ
押さえておきたいポイントをコンパクトにまとめると、こうなります。
配列 → クエリ文字列は http_build_query 一択でよい。
値は自動で URL エンコードされるので、自分でエンコードを重ねない。
URL 全体を組み立てたいときは、「ベース URL」と「パラメータ配列」を分けて考え、parse_url+http_build_query で組み立てる。
既存のクエリとマージしたいときは、parse_str で既存クエリを配列にしてから array_merge する。
核になるコードは、この2つです。
// 純粋に「配列 → クエリ文字列」
$query = http_build_query($params);
// ベース URL + パラメータ配列 → 完成 URL
function buildUrlWithQuery(string $baseUrl, array $params): string
{
$parsed = parse_url($baseUrl);
$existing = [];
if (isset($parsed['query']) && $parsed['query'] !== '') {
parse_str($parsed['query'], $existing);
}
$merged = array_merge($existing, $params);
$query = http_build_query($merged);
if ($query === '') {
return $baseUrl;
}
$scheme = $parsed['scheme'] ?? null;
$host = $parsed['host'] ?? null;
$port = $parsed['port'] ?? null;
$path = $parsed['path'] ?? '';
$fragment = $parsed['fragment'] ?? null;
$url = '';
if ($scheme !== null) {
$url .= $scheme . '://';
}
if ($host !== null) {
$url .= $host;
}
if ($port !== null) {
$url .= ':' . $port;
}
$url .= $path;
$url .= '?' . $query;
if ($fragment !== null) {
$url .= '#' . $fragment;
}
return $url;
}
PHPもし、あなたのコードの中で「? 以降を手書きで連結しているところ」があれば、そこがこのユーティリティの差し替えポイントです。
