PHPの変数展開とは、文字列の中に記述した変数を、その変数が持つ値に置き換える仕組みです。
$name = '山田';
echo "こんにちは、{$name}さん";
出力結果は次のとおりです。
こんにちは、山田さん
PHPでは、主にダブルクォート文字列とヒアドキュメントで変数展開が行われます。
一方、シングルクォート文字列とNowdocでは、基本的に変数展開は行われません。
ダブルクォートでは変数展開される
基本的な書き方
ダブルクォートで囲まれた文字列では、変数が自動的に展開されます。
$name = '佐藤';
echo "私の名前は{$name}です";
出力結果は次のとおりです。
私の名前は佐藤です
単純な変数であれば、波括弧を省略することもできます。
echo "私の名前は$nameです";
ただし、変数の直後に文字が続く場合は、波括弧を使ったほうが安全です。
シングルクォートでは変数展開されない
変数名がそのまま出力される
シングルクォートで囲まれた文字列では、変数展開は行われません。
$name = '佐藤';
echo '私の名前は{$name}です';
出力結果は次のとおりです。
私の名前は{$name}です
固定文字列を扱う場合や、変数展開を必要としない場合は、シングルクォートが適しています。
変数名の境界には波括弧を使う
日本語が直後に続く場合
次の書き方は、意図したとおりに動作しない可能性があります。
$name = '佐藤';
echo "$nameさん";
PHPは、$nameとさんを分けず、$nameさんという変数名として解釈しようとします。
そのため、変数名の境界を波括弧で明示します。
echo "{$name}さん";
出力結果は次のとおりです。
佐藤さん
英数字が直後に続く場合
日本語だけでなく、英数字が続く場合も同様です。
$color = 'red';
echo "$colorBox";
この場合、PHPは$colorBoxという変数を参照します。
意図した出力にするには、次のように記述します。
echo "{$color}Box";
変数の直後に文字が続く場合は、{$変数名}の形式を使うと安全です。
配列要素を変数展開する
数値添字配列
配列の要素も文字列内で展開できます。
$colors = ['赤', '青', '緑'];
echo "選択された色は{$colors[0]}です";
出力結果は次のとおりです。
選択された色は赤です
連想配列
連想配列の値も展開できます。
$user = [
'name' => '山田',
'age' => 30,
];
echo "名前は{$user['name']}です";
echo "年齢は{$user['age']}歳です";
出力結果は次のとおりです。
名前は山田です
年齢は30歳です
基本構文による配列アクセス
PHPでは、次のような書き方も可能です。
echo "名前は$user[name]です";
ただし、通常の配列アクセス構文とは見た目が異なります。
実務では、次の書き方のほうが分かりやすく、安全です。
echo "名前は{$user['name']}です";
オブジェクトのプロパティを変数展開する
プロパティの展開
オブジェクトのプロパティも文字列内で展開できます。
class User
{
public string $name = '高橋';
}
$user = new User();
echo "ユーザー名は{$user->name}です";
出力結果は次のとおりです。
ユーザー名は高橋です
単純なプロパティであれば、波括弧なしでも動作する場合があります。
echo "ユーザー名は$user->nameです";
ただし、可読性と構文の明確さを考えると、波括弧を付ける書き方が適しています。
echo "ユーザー名は{$user->name}です";
オブジェクトのメソッドを変数展開する
メソッドの戻り値を展開する
オブジェクトのメソッドは、波括弧内で呼び出せます。
class User
{
public function getName(): string
{
return '伊藤';
}
}
$user = new User();
echo "名前は{$user->getName()}です";
出力結果は次のとおりです。
名前は伊藤です
メソッドチェーンも使用できる
メソッドの戻り値がオブジェクトであれば、メソッドチェーンも使用できます。
class Profile
{
public function getDisplayName(): string
{
return '山田太郎';
}
}
class User
{
public function getProfile(): Profile
{
return new Profile();
}
}
$user = new User();
echo "表示名は{$user->getProfile()->getDisplayName()}です";
出力結果は次のとおりです。
表示名は山田太郎です
ただし、長いメソッドチェーンを文字列内に記述すると読みにくくなることがあります。
その場合は、先に変数へ代入します。
$profile = $user->getProfile();
$displayName = $profile->getDisplayName();
echo "表示名は{$displayName}です";
通常の関数呼び出しは直接展開できない
関数名をそのまま書く方法は使えない
次の書き方では、strtoupper()は関数として実行されません。
$name = 'yamada';
echo "大文字:{strtoupper($name)}";
波括弧を使った変数展開では、通常の関数名をそのまま記述することはできません。
先に関数を実行する
関数の戻り値を文字列内に含める場合は、先に変数へ代入します。
$name = 'yamada';
$upperName = strtoupper($name);
echo "大文字:{$upperName}";
または、文字列連結を使います。
echo '大文字:' . strtoupper($name);
可変関数は変数展開内で呼び出せる
関数名を変数に格納する
関数名を変数へ格納した可変関数であれば、文字列内から呼び出せます。
$formatter = 'strtoupper';
$name = 'yamada';
echo "大文字:{$formatter($name)}";
出力結果は次のとおりです。
大文字:YAMADA
無名関数を呼び出す
無名関数を変数へ代入した場合も同様です。
$formatter = function (string $value): string {
return strtoupper($value);
};
$name = 'yamada';
echo "大文字:{$formatter($name)}";
ただし、可読性を優先する場合は、先に戻り値を変数へ代入する方法が適しています。
$upperName = strtoupper($name);
echo "大文字:{$upperName}";
計算式は直接展開できない
四則演算は波括弧内に書けない
次のように、計算式を直接記述することはできません。
$price = 1000;
$quantity = 3;
echo "合計は{$price * $quantity}円です";
波括弧構文は、任意のPHP式を評価する仕組みではありません。
先に計算する
計算結果を文字列へ含める場合は、先に計算します。
$total = $price * $quantity;
echo "合計は{$total}円です";
文字列連結を使うこともできます。
echo '合計は' . ($price * $quantity) . '円です';
実務では、先に計算結果を変数へ代入したほうが、コードを理解しやすくなります。
定数はそのまま変数展開できない
定数名は文字列として扱われる
次のコードでは、SITE_NAMEは定数として評価されません。
const SITE_NAME = 'サンプルサイト';
echo "サイト名はSITE_NAMEです";
出力結果は次のとおりです。
サイト名はSITE_NAMEです
定数を文字列内で使用する場合は、文字列連結を使います。
echo 'サイト名は' . SITE_NAME . 'です';
または、一度変数へ代入します。
$siteName = SITE_NAME;
echo "サイト名は{$siteName}です";
配列キーとして定数を使う
定数そのものを変数のように展開することはできませんが、配列キーとして使用できます。
const DATA_KEY = 'name';
$user = [
'name' => '山田',
];
echo "名前は{$user[DATA_KEY]}です";
出力結果は次のとおりです。
名前は山田です
${name}形式はPHP 8.2以降で非推奨
非推奨の書き方
次の形式は、PHP 8.2以降で非推奨です。
$name = '山田';
echo "こんにちは、${name}さん";
推奨される書き方
単純な変数であれば、次のように記述します。
echo "こんにちは、{$name}さん";
変数名の境界が明確な場合は、次の書き方も可能です。
echo "こんにちは、$name";
新しいコードでは、${name}ではなく、{$name}を使用するのが安全です。
可変変数の場合
可変変数でも、古い形式は避けます。
echo "${$variableName}";
推奨される書き方は次のとおりです。
echo "{${$variableName}}";
ヒアドキュメントでは変数展開される
複数行の文字列を扱う
ヒアドキュメントでは、ダブルクォート文字列と同様に変数展開が行われます。
$name = '山田';
$age = 30;
$message = <<<TEXT
ユーザー情報
名前:{$name}
年齢:{$age}歳
TEXT;
echo $message;
出力結果は次のとおりです。
ユーザー情報
名前:山田
年齢:30歳
HTMLメールや複数行のテンプレートなどで便利です。
Nowdocでは変数展開されない
変数をそのまま文字として扱う
Nowdocでは、シングルクォート文字列と同様に変数展開されません。
$name = '山田';
$message = <<<'TEXT'
こんにちは、{$name}さん
TEXT;
echo $message;
出力結果は次のとおりです。
こんにちは、{$name}さん
変数展開したくない複数行文字列を扱う場合に適しています。
エスケープシーケンスの扱い
ダブルクォートで使用できる主な記述
ダブルクォート文字列では、変数展開だけでなく、エスケープシーケンスも解釈されます。
$name = '山田';
echo "名前:{$name}\n年齢:30";
主なエスケープシーケンスは次のとおりです。
| 記述 | 意味 |
|---|---|
\n | 改行 |
\r | キャリッジリターン |
\t | タブ |
\\ | バックスラッシュ |
\" | ダブルクォート |
\$ | ドル記号 |
変数名をそのまま表示したい場合は、$をエスケープします。
$name = '山田';
echo "変数名は\$nameです";
出力結果は次のとおりです。
変数名は$nameです
シングルクォートで解釈される記述
シングルクォート文字列では、基本的に次の2つだけが特別に扱われます。
\\
\'
例は次のとおりです。
echo 'It\'s PHP.';
出力結果は次のとおりです。
It's PHP.
シングルクォート内の\nは改行として扱われません。
echo '1行目\n2行目';
出力結果は次のとおりです。
1行目\n2行目
真偽値とnullの変数展開
trueは1として出力される
$value = true;
echo "値:{$value}";
出力結果は次のとおりです。
値:1
falseは空文字として出力される
$value = false;
echo "値:{$value}";
出力結果は次のようになります。
値:
nullも空文字として扱われる
$value = null;
echo "値:{$value}";
出力結果は次のようになります。
値:
真偽値やnullを確認する場合、変数展開では値の違いが分かりにくくなります。
デバッグにはvar_dump()を使用します。
var_dump($value);
表示用に使う場合は、文字列へ明示的に変換すると分かりやすくなります。
$status = $value ? '有効' : '無効';
echo "状態:{$status}";
配列全体はそのまま展開できない
配列を文字列として出力すると警告が発生する
次のように配列全体を展開すると、配列から文字列への変換に関する警告が発生します。
$items = ['apple', 'banana'];
echo "商品:{$items}";
一般的には、次のような警告が表示されます。
Warning: Array to string conversion
出力にはArrayと表示されます。
商品:Array
配列を文字列へ変換する
配列の要素をカンマ区切りで表示する場合は、implode()を使います。
$itemText = implode(', ', $items);
echo "商品:{$itemText}";
出力結果は次のとおりです。
商品:apple, banana
デバッグ目的の場合
配列の内容を確認する場合は、var_dump()やprint_r()を使用します。
var_dump($items);
print_r($items);
JSON形式に変換する場合
JSONとして出力する場合は、json_encode()を使用します。
$json = json_encode(
$items,
JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR
);
echo $json;
オブジェクト全体を展開する
__toString()を実装する
オブジェクト全体を文字列として展開するには、クラスに__toString()メソッドを実装します。
class Product
{
public function __construct(
private string $name
) {
}
public function __toString(): string
{
return $this->name;
}
}
$product = new Product('ノートパソコン');
echo "商品:{$product}";
出力結果は次のとおりです。
商品:ノートパソコン
__toString()がない場合
__toString()を持たないオブジェクトを文字列として出力すると、エラーになります。
その場合は、必要なプロパティやメソッドの戻り値を出力します。
echo "商品:{$product->name}";
または、次のように記述します。
echo "商品:{$product->getName()}";
波括弧構文で使用できる記述
使用できる例
次のような構文は、文字列内で使用できます。
"{$variable}"
"{$array['key']}"
"{$array[$key]}"
"{$object->property}"
"{$object->method()}"
"{$object->method()->property}"
"{$callable($argument)}"
使用できない例
次のような計算式や条件式は、直接記述できません。
"{$a + $b}"
"{$a * $b}"
"{strtoupper($name)}"
"{count($items)}"
"{$condition ? 'yes' : 'no'}"
波括弧構文は、あらゆるPHP式を自由に評価するための仕組みではありません。
文字列連結との使い分け
変数展開を使う例
単純な変数を文章の中に含める場合は、変数展開が読みやすくなります。
echo "こんにちは、{$userName}さん";
文字列連結を使う例
関数呼び出しを含む場合は、文字列連結が自然なことがあります。
echo '価格:' . number_format($price) . '円';
処理結果を先に変数へ入れる方法もあります。
$formattedPrice = number_format($price);
echo "価格:{$formattedPrice}円";
処理速度の差よりも、可読性と保守性を優先して使い分けることが重要です。
HTML出力時はエスケープが必要
変数展開はHTMLエスケープを行わない
次のコードでは、ユーザー入力がそのままHTMLへ出力されます。
$userName = $_GET['name'] ?? '';
echo "<p>こんにちは、{$userName}さん</p>";
ユーザー入力にHTMLやJavaScriptが含まれていた場合、クロスサイトスクリプティングの原因になる可能性があります。
htmlspecialchars()を使用する
HTML本文へ値を出力する場合は、htmlspecialchars()を使用します。
$escapedUserName = htmlspecialchars(
$userName,
ENT_QUOTES | ENT_SUBSTITUTE,
'UTF-8'
);
echo "<p>こんにちは、{$escapedUserName}さん</p>";
変数展開できることと、安全に出力できることは別の問題です。
出力先に応じて処理を変える
HTML本文では、次のように処理します。
htmlspecialchars(
$value,
ENT_QUOTES | ENT_SUBSTITUTE,
'UTF-8'
);
URLの一部として使用する場合は、次のように処理します。
rawurlencode($value);
JSONとして使用する場合は、次のように処理します。
json_encode(
$value,
JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR
);
JavaScriptへPHPの値を渡す場合は、文字列を直接組み立てず、json_encode()を利用します。
<script>
const value = <?= json_encode(
$value,
JSON_HEX_TAG
| JSON_HEX_AMP
| JSON_HEX_APOS
| JSON_HEX_QUOT
| JSON_THROW_ON_ERROR
) ?>;
</script>
SQLには値を直接展開しない
危険な書き方
次のように、ユーザー入力をSQL文へ直接展開する方法は危険です。
$email = $_POST['email'] ?? '';
$sql = "SELECT * FROM users WHERE email = '{$email}'";
SQLインジェクションの原因になる可能性があります。
プリペアドステートメントを使用する
PDOを利用する場合は、プレースホルダーを使用します。
$stmt = $pdo->prepare(
'SELECT * FROM users WHERE email = :email'
);
$stmt->execute([
'email' => $email,
]);
文字列連結でも安全にはならない
次の2つは、どちらも危険です。
$sql = "SELECT * FROM users WHERE email = '{$email}'";
$sql = 'SELECT * FROM users WHERE email = "' . $email . '"';
変数展開を文字列連結へ変更しても、SQLインジェクション対策にはなりません。
値をSQL文字列へ直接組み込まず、必ずプレースホルダーを使用します。
実務で推奨される書き方
単純な変数
echo "こんにちは、{$name}さん";
配列要素
echo "商品名:{$product['name']}";
オブジェクトのプロパティ
echo "担当者:{$user->name}";
オブジェクトのメソッド
短い処理であれば、直接記述できます。
echo "担当者:{$user->getName()}";
処理が長い場合は、先に変数へ代入します。
$displayName = $user->getProfile()->getDisplayName();
echo "担当者:{$displayName}";
計算結果
$total = $price * $quantity;
echo "合計:{$total}円";
関数の戻り値
$formattedPrice = number_format($price);
echo "価格:{$formattedPrice}円";
HTML出力
$escapedName = htmlspecialchars(
$name,
ENT_QUOTES | ENT_SUBSTITUTE,
'UTF-8'
);
echo "<p>{$escapedName}</p>";
SQL処理
$stmt = $pdo->prepare(
'SELECT * FROM users WHERE id = :id'
);
$stmt->execute([
'id' => $userId,
]);
まとめ
PHPの変数展開では、次のポイントを押さえることが重要です。
- ダブルクォートとヒアドキュメントでは変数展開される
- シングルクォートとNowdocでは変数展開されない
- 変数の直後に文字が続く場合は波括弧を使う
- 配列要素やオブジェクトのプロパティを展開できる
- オブジェクトのメソッドも呼び出せる
- 可変関数も一定の形式で呼び出せる
- 通常の関数名をそのまま波括弧内に書くことはできない
- 四則演算や三項演算子などの任意の式は直接展開できない
${name}形式はPHP 8.2以降で非推奨- HTML出力では適切なエスケープが必要
- SQLでは値を直接展開せず、プレースホルダーを使用する
単純な変数や配列要素、短いメソッド呼び出しは文字列内で展開できます。
一方、計算や複雑な処理は先に変数へ代入したほうが、可読性と保守性に優れたコードになります。
以上、PHPの変数展開についてでした。
最後までお読みいただき、ありがとうございました。










