PHPのecho
とprint
はどちらも関数ではなく言語構造です。どちらも文字列を出力バッファに書き出すという機能では同じですが、使われかたが異なります。
echo 1, 2, 3; // ← syntax error ではない
print 1, 2, 3; // ← これは syntax error
echo print 1; // ← syntax error ではない
print echo 1; // ← これは syntax error
形式的に言うと
-
echo
とprint
はどちらも出力バッファに書き込む機能です- まれに「標準出力する」と言及されますが、それは間違いです
-
fwrite(STDOUT, $str)
の実行結果とは一致しないということです
-
echo
は文ですがprint
は式です -
echo
は複数の引数をとりますが、print
は1つの引数をとります - 便宜上関数マニュアルに掲載されているが関数ではありません
どれを使えばいいの?
好みで何を使ってもいいと思うのですが、print
を使うメリットは特にないのでecho
を薦めます。
echo $string;
または
echo $str1, $str2, PHP_EOL;
この形式だけを使えばいいと思います。
また、 echo
とprint
はどちらも関数ではないので echo($v)
やprint($v)
のような関数呼び出し風の記述は誤解を呼ぶので使わない方が良いと思います。
echo
echo — 1 つ以上の文字列を出力する
echo
がリスト形式の引数を受け付け、返り値を持たないことです。
たしかにPHPの文は式の項にならない(値を返さない)ので、説明通りです。
まれにecho
を関数のように呼び出すひとがいます。
echo("str");
しかし、この ()
は $i = 1 + 2;
と書いても $i = (1 + 2);
と書いても結果が変わらないのと同じで、余分なカッコを書いているだけです。
これで、以下のような式がsyntax errorになることを説明できます。
echo("str1", "str2");
これは関数呼び出しで例えると f(1, 2)
と書くべきものを f((1, 2))
と書いていることと同じです。PHPには関数呼び出しや言語構造の引数以外に(1, 2)
のように値を列挙する式はありません。
print — 文字列を出力する
echo
との主な違いは、
この説明からはわかりにくいですが、print
は式であり、式の中に書くことができるということです。
どうしてわざわざ、echo
とは異なるこのような仕様があるのでしょうか。
わたしが考えつく限り、この仕様のユースケースは以下のようなものです。
foo() and print "success\n";
bar() or print "error\n";
これらの式はif
を使って以下のように書き直せます。
if (foo()) {
echo "error", PHP_EOL;
}
if (!bar()) {
echo "error", PHP_EOL;
}
これらは、わざわざショートコーディングを正当化するためには心許ない例です。書き捨てのコードでデバッグ用途で一瞬使うだけならともかく、もっとわかりやすく書いた方がよいでしょう。
print
は関数呼び出しではなく言語構造なので、print(1)
と書いても(print 1)
と書いても同じことです。print(1, 2)
と書いてしまうと関数呼び出しのように錯覚させてしまいますが、これは関数呼び出し式ではないため、純粋にsyntax errorです。
printf()
せっかくなのでprintf()
にも言及しておきましょう。echo
とprint
は言語構造でしたが、printf()
はPHPの組み込み関数です。
printf — フォーマット済みの文字列を出力する
これも出力バッファに文字列を書き出すという意味では共通していますが、意味が異なります。echo
とprint
が単に文字列を出力するだけのものであるのに対して、printf()
はフォーマット文字列を整形する、一種のテンプレートエンジンと呼べるものです。
printf('%d + %d = %d', $a, $b, $a + $b);
printf()
は高機能なので活用すると便利ですが、echo
やprint
とは違う使いかたを意識する必要があります。
// 安全なコード
echo "こんにちは {$name} さん! ({$num}回め)";
// 危険なコード
printf("こんにちは {$name} さん! (%d回め)", $num);
後者のコードでは$name
に%
が含まれると実行時エラーやテンプレートの位置をずらされるといった問題が起きえます。sprintf()
を使って文字を組み立てる場合などもバグや脆弱性の原因となりうることがあるでしょう。
printf("こんにちは %s さん! (%d回め)", $name, $num);
printf()
やsprintf()
などの第一引数には変数を直接展開せず、printf()
の%s
などを使ってください。
オペコードとの関係
PHP5時代はオペコードレベルでPRINT
とECHO
は別の命令でしたが、PHP7ではECHO
命令に統合されており最適化も施されるので特に違いは生じないはずです。
2015年9月に出版されたPHPはどのように動くのか ~PHPコアから読み解く仕組みと定石ではprint
よりもecho
の方がパフォーマンスに優れていると読み取れる記述があるのですが、実際には2015年12月にはPHP 7.0がリリースされており、実態にそぐわない記述になってしまいました。
読者への課題
PHP-Parserを使って、以下のようなソースコードを生成してみましょう。
<?php
echo 1;
print 2;