【PHP＋Docker】対話シェルで echo したら Parse error: syntax error, unexpected token "echo", expecting ";" or "," in php shell code on Line 1

## Docker の PHP で Parse syntax error `expecting ";" or "," in php shell`

> Docker で公式の PHP コンテナを対話モードで **`echo 'hoge';` ですら "`Parse error`" の構文エラーで正常に動かない**。
>
> ```shell-session:対話モードで正常に動かない
> $ docker run --rm -it php:php7-alpine
> Interactive shell
> 
> php > echo 'hoge';  // ← Parse エラーが出る ↓
> 
> Parse error: syntax error, unexpected token "echo", expecting ";" or "," in php shell code on line 1
> php >
> php > exit
> $
> ```

「<code>[docker PHP Parse error: syntax error, unexpected token "echo", expecting ";" or "," in php shell code on line 1](https://www.google.com/search?q=docker+PHP+Parse+error%3A+syntax+error%2C+unexpected+token+%22echo%22%2C+expecting+%22%3B%22+or+%22%2C%22+in+php+shell+code+on+line+1)</code>」でググってみても、「"`;`"（セミコロン）抜けてるよ」とか「PHP タグ閉じ忘れてるよ」といった、まぁ、当然かつ妥当な情報ばかり。かなりニッチな現象。

## TL; DR （SOLVED/対策）

> 困ったら `prune` `prune` する。

まずは「あるある」から確認。`;` を忘れてみます。

```shell-session:対話が終わっていない行がないか確認する
$ docker run --rm -it php:php7-alpine
Interactive shell

php > echo 'hoge'   // ← 処理が完結していない
php > echo 'hoge';  // ← ここで完結。"echo 'hoge' echo 'hoge';" となるので Parse エラーが出る ↓

Parse error: syntax error, unexpected token "echo", expecting ";" or "," in php shell code on line 2
php >
```

上記と違い、完結していたり、`php -r 'echo "hoge";'` でもエラーが出る場合は、一旦全部作り直してみる。

```shell-session:全てをPrunePruneする
$ # 起動中のコンテナを止める
$ docker stop $(docker ps -q)
...
$ # 全てを prune prune する （注意：データコンテナすら消える）
$ docker system prune -a -f
...
```

## TS; DR （経緯と原因）

PHP が [8.0.0 パブリック・ベータになった](https://github.com/php/php-src/releases/tag/php-8.0.0beta1)ので、[JIT を有効にした Docker イメージ](https://github.com/KEINOS/Dockerfile_of_PHP8-JIT)を更新しました。これを機に、既存の PHP スクリプトを見直そうと古びたディレクトリを漁り始めました。

何かの整理を始めると、目については遊び始めちゃう昔から直らないクセにより、とあるスクリプトを見つけ触り始めてしまいました。

複数のベースイメージ（Debian や Alpine）や PHP バージョンで動かしたりと、色々と試行錯誤していたところ、PHP の挙動がおかしくなりました。動いていたものが動かないのです。**何もしていないのに**。

「もぅ、夜も遅いから処理能力が落ちているんだな」と思い、Netflix を観ていたら寝落ちしました。

翌朝起きると、[Qiita の SNS（β）](https://qiitadon.com/) の LTL（ローカル・タイム・ライン）で気になるやりとりが。

- https://git.io/JJdCH @ Qiitadon

「もしや」と思い、試したところ現象が再現しました。

```shell-session:対話モードで正常に動かない
$ docker run --rm -it keinos/php8-jit
Interactive shell

php > echo 'hoge';  // ← Parse エラーが出る ↓

Parse error: syntax error, unexpected token "echo", expecting ";" or "," in php shell code on line 1
php >
php > exit
$
```

しかし、[7.4.9, 7.4.0 でも再現しているとの情報](https://git.io/JJdCH)が。確かに、公式のイメージで試しても挙動がおかしいのです。それでも「うちの環境じゃ問題ないよ」という人もいます。

ありがたいことに、他の言語のイメージでは正常に動いているという情報もあったので、どうやら、PHP 8.0.0-beta が原因ではないようです。

"`;`" の閉じ忘れなら可愛いもので、`$ php -v` をしても鉄砲玉で戻ってこなかったり。

となると環境依存。思い当たること、ありまくりです。

`docker container prune -f` や `docker image prune -f` は、某総統閣下のように `prune` `prune` 言っていたのですが、どうやらキャッシュが必要なタイミングでも削除しすぎたらしく、イメージのビルドに必要な中間ファイルやキャッシュの統合性が取れなくなったようです。

そこで、困った時の宝刀を抜いてみました。`docker system prune -f -a` です。直りました。


```shell-session:全てをPrunePruneする
$ # 対話式で確認
$ docker run --rm -it php:php7-alpine
Interactive shell

php > echo 'hoge';

Parse error: syntax error, unexpected token "echo", expecting ";" or "," in php shell code on line 1
php >
php > exit

$ # コマンドで確認
$ php -r 'echo "hoge";'
Parse error: syntax error, unexpected token "echo", expecting ";" or "," in php shell code on line 1

$ # PHP のバージョン確認（処理が戻ってこない）
$ php -v
^c$

$ # 起動中のコンテナを止める
$ docker stop $(docker ps -q)
...
$ # 全てを prune prune する （注意：データコンテナすら消える）
$ docker system prune -a -f
...

$ # 再チャレンジ
$ docker run --rm -it php:php7-alpine
Unable to find image 'php:php7-alpine' locally
latest: Pulling from php:php7-alpine
ce1cbf4a8451: Pull complete 
（中略）
e6c8e46ea4b3: Pull complete 
Digest: sha256:1ca266626067e5cb1cc7e5f4cfe79910f63e71a60ee4dc6a76bd9e6f436fd14a
Status: Downloaded newer image for php:php7-alpine
Interactive shell

php > declare(strict_types=1);
php > echo 'hello';
hello
php > exit
$
```


やはり、Docker の中間イメージというかレイヤーがおかしくなっていたようです。あちょんぶりけ。