echoとprintの違い

PHPの`echo`と`print`はどちらも関数ではなく言語構造です。どちらも文字列を出力バッファに書き出すという機能では同じですが、使われかたが異なります。

```php
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`を薦めます。

```php
echo $string;
```

または

```php
echo $str1, $str2, PHP_EOL;
```

この形式だけを使えばいいと思います。

また、 `echo`と`print`はどちらも関数ではないので `echo($v)`や`print($v)`のような関数呼び出し風の記述は誤解を呼ぶので使わない方が良いと思います。

## echo

https://www.php.net/echo

> echo — 1 つ以上の文字列を出力する
>
> `print` との主な違いは、 `echo` がリスト形式の引数を受け付け、返り値を持たないことです。

たしかにPHPの文は式の項にならない(値を返さない)ので、説明通りです。

まれに`echo`を関数のように呼び出すひとがいます。

```php
echo("str");
```

しかし、この `()` は `$i = 1 + 2;` と書いても `$i = (1 + 2);`と書いても結果が変わらないのと同じで、余分なカッコを書いているだけです。

これで、以下のような式がsyntax errorになることを説明できます。

```php
echo("str1", "str2");
```

これは関数呼び出しで例えると `f(1, 2)` と書くべきものを `f((1, 2))` と書いていることと同じです。PHPには関数呼び出しや言語構造の引数以外に`(1, 2)`のように値を列挙する式はありません。

## print

https://www.php.net/print

> print — 文字列を出力する
>
> `echo`との主な違いは、`print`が単一の引数のみ受け付け、常に 1 を返すことです。

この説明からはわかりにくいですが、`print`は式であり、式の中に書くことができるということです。

どうしてわざわざ、`echo`とは異なるこのような仕様があるのでしょうか。

わたしが考えつく限り、この仕様のユースケースは以下のようなものです。

```php
foo() and print "success\n";
bar() or print "error\n";
```

これらの式は`if`を使って以下のように書き直せます。

```php
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の組み込み関数です。

https://www.php.net/printf

> printf — フォーマット済みの文字列を出力する

これも出力バッファに文字列を書き出すという意味では共通していますが、意味が異なります。`echo`と`print`が単に文字列を出力するだけのものであるのに対して、`printf()`はフォーマット文字列を整形する、一種のテンプレートエンジンと呼べるものです。

```php
printf('%d + %d = %d', $a, $b, $a + $b);
```

`printf()`は高機能なので活用すると便利ですが、`echo`や`print`とは違う使いかたを意識する必要があります。

```php
// 安全なコード
echo "こんにちは {$name} さん！ ({$num}回め)";

// 危険なコード
printf("こんにちは {$name} さん！ (%d回め)", $num);
```

後者のコードでは`$name`に`%`が含まれると実行時エラーやテンプレートの位置をずらされるといった問題が起きえます。`sprintf()`を使って文字を組み立てる場合などもバグや脆弱性の原因となりうることがあるでしょう。

```php
printf("こんにちは %s さん！ (%d回め)", $name, $num);
```

`printf()`や`sprintf()`などの第一引数には変数を直接展開せず、`printf()`の`%s`などを使ってください。

## オペコードとの関係

PHP5時代はオペコードレベルで`PRINT`と`ECHO`は別の命令でしたが、PHP7では`ECHO`命令に統合されており最適化も施されるので特に違いは生じないはずです。

 * [PHP AST 徹底解説](https://www.slideshare.net/do_aki/php-ast)
 * [PHP の echo と print の違い (闇) - y_uti のブログ](https://y-uti.hatenablog.jp/entry/2015/12/07/000027)

2015年9月に出版された[PHPはどのように動くのか ～PHPコアから読み解く仕組みと定石](https://gihyo.jp/book/2015/978-4-7741-7642-0)では`print`よりも`echo`の方がパフォーマンスに優れていると読み取れる記述があるのですが、実際には2015年12月にはPHP 7.0がリリースされており、実態にそぐわない記述になってしまいました。

## 読者への課題

[PHP-Parser](https://github.com/nikic/PHP-Parser)を使って、以下のようなソースコードを生成してみましょう。

```php
<?php

echo 1;
print 2;
```