PHP で、コメントが原因でエラーになった話

正確には、PHP の１行コメントに落とし穴があった、という話です。

【環境】
> （このエラー自体は、環境依存ではないと思いますが、一応あげておきます。）
> ＯＳ：Windows 10
> サーバー：Xampp 8.1.6 (Apache 2.4, PHP 8.1.6)
> ブラウザ：Firefox 102.0.1 (64 ビット)
> エディタ：さくらエディタ v2.4.1.2849 32bit (tag v2.4.1)


## 現象１
PHP で、アトミック正規表現 `(?>...)` を修正する時、オリジナルを残しておこうと頭に`#`をつけ（１行コメントアウト）たら、原因特定困難なエラーが生じました。（この現象は、 `//` の場合も同様に発生します。）


:::note warn
**注意**
この現象は、アトミック正規表現 `(?>...)` に限って発生するわけではなく、その他の正規表現でも発生する可能性があります。また、それ以外の一般的な PHP スクリプトの中でも、入力ミスによって同様のエラーが発生する可能性があります。
:::

:::note warn
**注意**
なお、このエラーが「原因特定困難」なのは「エディタ環境」に原因があります。エディタが「１行コメントの中断」を正確に認識・色分け表示できる設定であれば、即対処可能でした。
この記事は、そのエディタ環境に焦点を当てたものです。
:::


## エラーメッセージ１
```PHP
Warning: Undefined variable $***** in (スクリプトファイルへのパス) on line (行番号)

（他の変数でも、同じ警告がいくつか）

Fatal error: Uncaught Error: Call to undefined function *******() in (ファイルへのパス):(行番号) Stack trace: #0 {main} thrown in (ファイルへのパス) on line (行番号)
```

:::note info
Fatal エラーは、`catch` ブロックの中で使用したユーザー定義関数によって引き起こされました。
`if (function_exists('関数名')) { (元の式) }` にすると、エラーメッセージ２と同様になったので、「原因究明１」を削除します。
:::

## エラーメッセージ２
```
Parse error: Unclosed '{' on line (開始カッコのある行番号) in (インクルードファイルへのパス) on line (ファイルの最終行番号)
```

## エラーメッセージ２の解釈
「パースエラー：開始カッコ `{` に対応する閉じカッコ `}` が（ファイルの最終行まで探しましたが）ありません！」
と解釈できました。

開始カッコは、まさに修正していたクラスメソッドの開始カッコでしたので、修正中のこのメソッドの開始カッコから閉じカッコの間に、エラーの原因がありそうです！


## 原因究明２
しかし、調査した結果、開始カッコには、正しく閉じカッコが対応しているように見えました。
依然として、メソッド中のどこに問題があるかがわからなかったので、コメント以外の有効行のうちから少しずつ削除・アンドゥ(CTRL+Z)を繰り返して、プログラムが動くかどうか試してみました。

ところが、どこを削除してみても、同じエラーが出ます！一体どうしたと言うのでしょう！？頭を切り替えるため、再度の休憩を取りました。


## 原因究明３
今度は、メソッド全体を削除してみたところ、このメソッドを利用していない別のスクリプトファイルが（それまでエラーメッセージ２だったのが）正常に動作しました！

そして次に、今度はかなり広範囲に（コメント行も含めて）調査したところ、何と、

:::note warn
**コメント行に問題があることがわかったのです！**
:::

## 原因究明４
次は、コメント行の、一体どの箇所に問題があるのかを調査したところ、どうやらアトミック正規表現 `(?>...)` の一部である`?>`の部分に問題があることがわかりました。１行コメントの`#`の後方に`?>`がある場合にのみ、エラーメッセージが表示されました。`?`だけでも`>`だけでもエラーは無く、`?>`がつながって存在する場合だけでした。

もちろん、コメントアウトする前は、プログラムに正常に正規表現として認識されていたらしく、エラーは出ていませんでした。コメントアウトした途端、エラーが発生していたのです！

なお、`/* ～ */`で囲んだ場合は、エラーは生じませんでした。

:::note alert
**警告**
この問題を引き起こす文字列 `?>` は、アトミック正規表現だけでなく一般的な正規表現でも出現する可能性があり、また、正規表現を使用しないスクリプトであっても、入力ミス等によって出現する可能性があります。

これらを１行コメントアウトした途端、同様のエラーが発生します。
:::

## PHPマニュアル
PHPマニュアルにバグ報告する前に、念のため「コメント」の解説を読んでみると、何と、ちゃんと書いてありました！「１行コメントは、改行またはPHP 終了タグ`?>`まで」的なことが。

それって...「１行コメント」という言い方ってどうなの？PHP 終了タグ `?>` 以降は同じ行でもコメントにならないってことでしょ！


## バグ退治の問題点
今回、私はさくらエディタを使っており、緑色に表示されるコメント行には何の注意も払っていませんでした。そのため、エラーの原因究明に大変手間取りました。私のさくらエディタは、PHP 終了タグ`?>`による１行コメントの中断が認識できない設定になっていました。（デフォルトも同様です。）


## 対策
この件の対策としては、「エディタで、コメント部分を正しく表示させる」があげられます。

さくらエディタ用ですが、コメント部分を正しく表示させるための「正規表現キーワード」を試作したので紹介します。（もし問題が見つかったら教えてください。）以下に設定の仕方を記します。

:::note info
なお、通常行において、引用符 `'` `"` に囲まれた `#` `//` については、うまく色分け表示できない（コメントではないのにコメント色になってしまう）ことがわかっていますが、残念ながら解決策が見つかりません。良い方法があれば、どなたか教えてください。（デフォルト設定でも同様です。）
:::

まず、さくらエディタを起動し、
任意の「PHP ファイル」を開いて「設定」>「タイプ別設定」を開くか、
又は「設定」>「タイプ別設定一覧」を開いて「ＰＨＰ（php）」タイプを選択した後「設定変更」をクリックして「タイプ別設定」を開きます。

:::note alert
**警告！**
不具合が見つかったので、「コメントスタイル」の「行型」から「`//`」や「`#`」を削除する、という部分を取り消します。
:::

~~そして、「カラー」タブを開き、~~
![PHPタイプ別設定(カラー)タブ(取り消し)](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327025/372f0c79-6f60-5fb8-9663-bcf89ce78f70.jpeg "PHPタイプ別設定(カラー)タブ(取り消し)")
~~右側の「コメントスタイル」の「行型」に「`//`」や「`#`」があれば、それらを削除します。~~

~~次に、~~ 「正規表現キーワード」タブを開き、
![PHPタイプ別設定(正規表現キーワード)タブ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327025/779f4548-5a4f-2d9d-5d50-43cf78cb3d1b.jpeg "PHPタイプ別設定(正規表現キーワード)タブ")
「正規表現」の入力欄に、次の正規表現を１つずつ上から順に入力し、好みの「色指定」にし、「追加」をクリックします。（３つとも同様に設定します。）

```
/(?#アトリビュート)#\[[^\]]*\]?/k
/(?#PHP終了タグ有り1行コメント)(#|\/\/).*(?=\?>)/k
/(?#PHP1行コメント)(#|\/\/).*$/k
```

:::note warn
**注意**
この欄は、下へ行くほど優先順位が低いので、先にマッチする正規表現があればそちらが優先されます。なので、順番はとても大切です。必ず上記の順番で入力するようにして下さい。
:::

:::note warn
**注意**
なお、1行目は「アトリビュート」を色分け表示するためのものです。アトリビュートを正確に色分け表示できないと、これもエラーの原因になります。

そのため、コメントとは異なる色指定にしてください。2,3行目は「色指定」に「コメント」を設定するのが良いでしょう。
:::

~~最後に、再び~~ 「タイプ別設定」>「カラー」タブを開き、
![PHPタイプ別設定(カラー)タブ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327025/05615dc2-8965-abed-17f7-9d9febefff20.jpeg "PHPタイプ別設定(カラー)タブ")
左側の「色指定」の一覧のところで、先ほど好みに設定した「色指定」の項目を選択し、その項目の左端に「チェック」が付いてなければ付け（又は「色分け／表示」チェックボックスにチェックを入れ）、「文字色」「背景色」に好きな色を設定してその項目の設定は終了です。
一番最後に、「OK」をクリックして全ての設定を確定します。

これで、コメント以外の部分が通常表示されるようになりました。


## まとめ
1. PHP で、１行コメント中に`?>`があると、それは PHP 終了タグと解釈されてしまう！これによって、パースエラーが発生する場合がある。
2. １行コメントがPHP 終了タグ `?>` によって中断される場合でも、エディタがそれ以降をHTMLコードとして表示せずに、同じコメント色で表示してしまう場合、バグ退治に支障を来す。
3. さくらエディタで、PHP の１行コメントを正しく表示するための正規表現の紹介



:::note info
みなさんも、自分のエディタで `# ?>あいうえお` などを表示させてみて、`?>` 以降の文字列（あいうえお）をコメントと誤解するような表示になっていないか確かめてみて下さい。
:::