PHP のシングルクォートとダブルクォートの違い

はじめに

実務にて、一重引用符(シングルクォート, シングルコーテーション)と二重引用符(ダブルクォート, ダブルコーテーション)の違いって何ですかと聞かれることがあります。周りにあまり意識しないでコーディングしている方が多かったので、わかりやすく記事にしてみました。

検証環境

解説

一重引用符 とは ' という記号のことです。

二重引用符 とは " という記号のことです。

プログラミングの世界では、一重引用符のことをシングルクォート、又はシングルコーテーションと言うことが多いです。

同様に、二重引用符のこともダブルクォート、又はダブルコーテーションと言います。

シングルクォートで括ると、PHP は文字列として解釈します。

$a = 'HEYYEYAAEYAAAEYAEYAA';

var_dump($a); // string(20) "HEYYEYAAEYAAAEYAEYAA"

ダブルクォートで括ると、PHP は以下のエスケープシーケンスを特殊文字として解釈します。

  • \n : 改行(newline)
  • \r : 復帰(carriage return)
  • \t : 水平タブ
  • \v : 垂直タブ
  • \e : エスケープ
  • \f : 改ページ(formfeed)
  • \\ : バックスラッシュ
  • \$ : ドル記号
  • \" : ダブルクォート
  • \[0-7]{1,3} : 8 進数表記の 1 文字
  • \x[0-9A-Fa-f]{1,2} : 16 進数表記の 1 文字
  • \u{[0-9A-Fa-f]+} : Unicode のコードポイント

ダブルクォートは、下記のように中で変数を展開することができます。

$a = "0"; // 8進数のH
$b = "\x45"; // 16進数のE
$c = "\u{0059}"; // UnicodeのY

var_dump("$a$b$c" . 'YEYAAEYAAAEYAEYAA'); // string(20) "HEYYEYAAEYAAAEYAEYAA"

シングルクォートは、下記のようにエスケープシーケンスと変数を展開できません。

$a = "0"; // 8進数のH
$b = "\x45"; // 16進数のE

var_dump('$a${b}\u{0059}YEYAAEYAAAEYAEYAA'); // string(31) "$a${b}\u{0059}YEYAAEYAAAEYAEYAA"

また、ダブルクォートの中で波括弧を使用して変数名を明示することもできます。

$a = "0"; // 8進数のH
$b = "\x45"; // 16進数のE
$c = "\u{0059}"; // UnicodeのY

var_dump("${a}${b}${c}YEYAAEYAAAEYAEYAA"); // string(20) "HEYYEYAAEYAAAEYAEYAA"

波括弧で変数名を明示しない場合、下記のように書いてしまうと変数名がおかしなことになってエラーが発生します。

$a = "0"; // 8進数のH
$b = "\x45"; // 16進数のE
$c = "\u{0059}"; // UnicodeのY

var_dump("$a$b$cYEYAAEYAAAEYAEYAA"); // Undefined variable $cYEYAAEYAAAEYAEYAA

半角スペースを挟む場合は、下記のようにエラーが発生しません。

$a = "0"; // 8進数のH
$b = "\x45"; // 16進数のE
$c = "\u{0059}"; // UnicodeのY

var_dump("$a$b$c YEYAAEYAAAEYAEYAA"); // string(21) "HEY YEYAAEYAAAEYAEYAA"

配列の要素やオブジェクトのプロパティであっても、下記のように展開することができます。

$a = [
  "0",
  ["\x45"],
];
$b = new stdClass();
$b->char = "\u{0059}";

var_dump("{$a[0]}{$a[1][0]}{$b->char}YEYAAEYAAAEYAEYAA"); // string(20) "HEYYEYAAEYAAAEYAEYAA"

波括弧で多次元配列の要素を明示しない場合、下記のように書いてしまうと警告(Warning)が発生します。

$a = [
  "0",
  ["\x45"],
];

var_dump("$a[1][0]"); // Warning: Array to string conversion

他にも、関数やメソッドの戻り値、二つの波括弧でクラス定数や静的クラス変数を展開することもできます。

class test {
  public const A = 'h';
  public static $b = 'y';

  public function c() {
    return "\u{0059}";
  }
}

$h = "0";
$y = "\x45";
$test = new test();

var_dump("{${test::A}}{${test::$b}}{$test->c()}YEYAAEYAAAEYAEYAA"); // string(20) "HEYYEYAAEYAAAEYAEYAA"

PHP 7.1 以降では、負の文字列オフセットに対応しています。

$a = 'HEY'[-1];

var_dump("HE{$a}YEYAAEYAAAEYAEYAA"); // string(20) "HEYYEYAAEYAAAEYAEYAA"

波括弧で文字列オフセットにアクセスすると、PHP 7.4 以降で Deprecated(非推奨)、PHP 8.0 以降で Fatal error(致命的なエラー)が発生するので気を付けましょう。

'HEY'{-1}; // Fatal error: Array and string offset access syntax with curly braces is no longer supported

ここまでで、シングルクォートとダブルクォートの違いは、エスケープシーケンスと変数が展開されるかどうかということが理解できました。

では、処理時間はどうでしょうか。

シングルクォートの文字列結合とダブルクォートの変数展開を 1000 万回実行して比較してみました。

$str = 'HEYYEYAA';

$start = hrtime(true);

for ($i = 0; $i <= 10000000; ++$i) {
  $str . 'EYAAAEYAEYAA';
}

$end = hrtime(true);
echo '処理時間: ', ($end - $start) / 1e+9, ' 秒'; // 処理時間: 1.037500012 秒
$str = 'HEYYEYAA';

$start = hrtime(true);

for ($i = 0; $i <= 10000000; ++$i) {
  "${str}EYAAAEYAEYAA";
}

$end = hrtime(true);
echo '処理時間: ', ($end - $start) / 1e+9, ' 秒'; // 処理時間: 1.047425666 秒

シングルクォートの方が、僅かに処理が速いです。

では、可読性はどうでしょうか。

$a = 'H';
$b = 'E';
$c = 'Y';

var_dump($a . $b . $c . $c . $b . $c . 'AA' . $b . $c . 'AAA' . $b . $c . 'A' . $b . $c . 'AA'); // string(20) "HEYYEYAAEYAAAEYAEYAA"
$a = 'H';
$b = 'E';
$c = 'Y';

var_dump("$a$b$c$c$b${c}AA$b${c}AAA$b${c}A$b${c}AA"); // string(20) "HEYYEYAAEYAAAEYAEYAA"

どっこいどっこいですね。

ただ、下記のような記述は微妙です。

$str = "HEYYEYAAEYAAAEYAEYAA~HEYYEYAAEYAAA~";

理由は、エスケープシーケンスか変数を展開させるわけでもないのに、長い文字列に対してダブルクォートで括っているからです。

読み手がシングルクォートとダブルクォートの違いを理解している場合、ダブルクォートで括っているから、どこかでエスケープシーケンスか変数を展開させているのではないかと考え、場所を探してしまいます。

つまり、他人の時間を奪っているということです。

良いコーディングというのは、他人が最速で理解できるコードを書くことです。

シングルクォートで括っておけば、読み手は、文字列の中でエスケープシーケンスか変数は展開されていないんだなとすぐに理解できます。

誤解を招く書き方は、成る丈やめておきましょう。

まとめ

基本的には、シングルクォートを使用しましょう。

エスケープシーケンスか変数を展開させる場合は、ダブルクォートを使用しましょう。

大量アクセスのある大規模なシステムでは、処理の速さを考慮して使い分けましょう。

無意味にダブルクォートで括るのはやめましょう。

以上です。

おわりに

シングルクォートとダブルクォートの使い分けを間違えると、これを書いた人は読み手のことをあまり考えないコーダーだねと思われてしまう可能性があるので気を付けましょう。