PHP のヒアドキュメントで見落としがちなポイント（あるある単純ミス集）

（**P.S.** なんと [PHP7.3 以降では下記制限の一部がなくなる](#comments)そうです by [@​rana_kualu​さん](./51f3a1bc3830070c632a#comment-3f032be33d19ca77c516)情報。関連情報「[フレキシブルなheredocがやってくる](https://qiita.com/tadsan/items/3e5a094cd57e430b6ea9)」@ Qiita）

---

## ヒアドキュメント専用「凡ミス集」

PHP で複数行を代入するための[ヒアドキュメント構文](http://php.net/manual/ja/language.types.string.php#language.types.string.syntax.heredoc) ("`<<<`") で、個人的にありがちなミスのチェック・リストです。

1. 終端 ID（識別子）の "`;`" の後ろに改行コード以外の何かがある（空白、タブ、制御コードなど）
2. 終端 ID（識別子）の前にタブやスペースなどでインデントしている
3. 改行に OS の改行コードを使用していない
4. 開始 ID（識別子）の後ろに改行コード以外の何かがある（空白、タブ、制御コードなど）
5. ID の後ろにコメントを入れている

## 意外と大丈夫なパターン

スペース位置に注目してください。

```php
$msg =<<<HEREDOC
  OK
HEREDOC;

$msg =<<< HEREDOC
  OK
HEREDOC;

$msg = <<< HEREDOC
  OK
HEREDOC;
```

## 他の言語のヒアドキュメントの構文と間違えてる

```bash:bashかよっ！　👋　ﾊﾞｼｯ
$msg = << HEREDOC
  OK
HEREDOC
```

## エラーメッセージから判断

### `unexpected '<<' (T_SL) in`

> 「`Parse error: syntax error, unexpected '<<' (T_SL) in ... on line`」
>  「`Fatal error: Uncaught Error: syntax error, unexpected T_SL in`」

`echo <<<HEREDOC` の開始 ID（識別子）の後ろに空白がありませんか？

```php:最初のHEREDOCの後ろに実はスペースが入っている
<?php
$hoge = 'hoge';
echo <<< HEREDOC 
${hoge} is not fuga
piyo is not ${hoge}
HEREDOC;
```

もしくは `echo <<<HEREDOC` の開始 ID（識別子）の後ろにコメント入れてませんか？

```php:最初のHEREDOCの後ろにコメントが入っている
<?php
$hoge = 'hoge';
echo <<< HEREDOC //mogera
${hoge} is not fuga
piyo is not ${hoge}
HEREDOC;
```
```shell-session:エラー内容
PHP Parse error:  syntax error, unexpected '<<' (T_SL) in /workspace/Main.php on line 3
```

上記は PHP7.3 でも NG でした。

### `unexpected end of file in` `Unterminated heredoc at end of file`

> 「`Parse error: syntax error, unexpected end of file in ... on line`」
> 「`Fatal error: Uncaught Error: Unterminated heredoc at end of file (Line:.., Char:..)`」
> 「`Parse error:  Invalid body indentation level (expecting an indentation level of at least ...) in ... on line`

終端 ID（識別子）の前後に空白などがありませんか？ 

```php:最後のHEREDOCの前に空白がある（PHP>=7.3では大丈夫）
<?php
$hoge = 'hoge';
$fuga = <<< HEREDOC
    ${hoge} is not fuga
    piyo is not ${hoge}
    HEREDOC;
echo $fuga;
```

終端 ID（識別子）の後にコメント入れてませんか？

```php:最後のEOTの後に空白やコメントがある（PHP>=7.3では大丈夫）
<?php
$hoge = 'hoge';
if (empty($msg)){
    $msg = <<< HEREDOC
{$hoge} is not fuga
HEREDOC; //piyo
}
```

**上記は PHP7.3 では大丈夫**でした。PHP7.3 では最後の `HEREDOC` のインデント・レベルを基準に、左インデントをトリムしてくれるようです。

```php
<?php
$fuga = <<< HEREDOC

    ${hoge} is hoge
    but fuga is not ${hoge}
    HEREDOC; 

echo $fuga, PHP_EOL;
```
```text:出力結果

hoge is hoge
but fuga is not hoge
```

- [オンラインで動作を見る](https://paiza.io/projects/gkZh1rjz0XETujWusrnmOg) @ paiza.IO

### `Invalid body indentation level`

PHP 7.3 以降での問題は、最後の `HEREDOC` のインデントがヒアドキュメント内のインデントよりも深い場合です。

```php:最後のHEREDOCのインデントが１スペースぶん多い
$fuga = <<< HEREDOC

    ${hoge} is hoge
    but fuga is not ${hoge}
     HEREDOC;

echo $fuga, PHP_EOL;
```
```text:エラー内容
PHP Parse error:  Invalid body indentation level (expecting an indentation level of at least 5) in /workspace/Main.php on line 4
```

## TS;DR（所感）

わかっちゃいるけど、コード・エディタ使っていないと沼にハマることが多いので、自分への戒め。[ググっても Qiita では基本すぎてストレートにヒットしない](https://www.google.co.jp/search?q=site%3Aqiita.com+php+%E3%83%92%E3%82%A2%E3%83%89%E3%82%AD%E3%83%A5%E3%83%A1%E3%83%B3%E3%83%88+%E3%83%9F%E3%82%B9)ので、自分の~~ググラビリティをごまかす~~ Qiita 依存を高めるための記事です。

ああ、何度同じ問題で悩むのだろう。Qiita 方が早いのに。