エラーの内容
PHP Warning: preg_match(): No ending delimiter '/' found in /var/www/html/app.php on line 23
PHPが正規表現をコンパイルしようとした際に終了デリミタが見つからないと、このエラーが発生します。preg_match()は0や1ではなくfalseを返すため、パターンが実行されていないにもかかわらず、下流のif文が気づかないまま誤動作します。
原因
PHPのPCRE関数(preg_match、preg_replace、preg_splitなど)は、パターンをデリミタ文字で囲む必要があります。慣例的にスラッシュが使われます:
/パターン/フラグ
このワーニングが発生する原因は主に4つです:
- 終了デリミタが完全に抜けている
- デリミタ文字がパターン内でエスケープされずに使われている
- 正しい正規表現の代わりにプレーン文字列が渡されている(例:
"/email/"の代わりに"email") - パターンを動的に構築する際に文字列結合で終了デリミタが脱落している
修正手順
1. 終了デリミタを追加する
最も多い原因は、開始スラッシュは書いたが終了スラッシュを忘れているケースです:
<?php
// 誤り
preg_match('/^[a-z]+', $input);
// 修正後
preg_match('/^[a-z]+/', $input);
2. パターン内のデリミタをエスケープする
URLパターンは典型的な落とし穴です。パターンに/が含まれると、PHPは最初の/を終了デリミタと解釈し、それ以降は無効になります:
<?php
// 誤り — URL内の / が 'https:' の直後で正規表現を閉じてしまう
preg_match('/https://example.com/', $url);
// 方法A — デリミタをエスケープする
preg_match('/https:\/\/example\.com/', $url);
// 方法B — デリミタを変更する(URLには圧倒的にスッキリ)
preg_match('#https://example\.com#', $url);
PHPでは英数字・バックスラッシュ・空白以外の文字であればデリミタとして使用できます:/、#、~、!、|、さらに{}や()のような対応する括弧ペアも使えます。URLやファイルパスを含むパターンには#を使うと、スラッシュのエスケープが不要になります。
3. 動的に構築したパターンを修正する
動的パターンはこのバグの最も気づきにくい原因です。ユーザー入力からキーワード検索フィルターを構築する例を見てみましょう:
<?php
$keyword = 'error';
// 誤り — 開始デリミタが完全に抜けている
$pattern = $keyword . '/i';
preg_match($pattern, $log);
// 修正後
$pattern = '/' . preg_quote($keyword, '/') . '/i';
preg_match($pattern, $log);
変数の内容は必ずpreg_quote()でラップしてください。選択したデリミタを含むすべての特殊な正規表現文字をエスケープするため、挿入された値がパターン構造を壊せなくなります。
4. 誤ってプレーン文字列を渡していないか確認する
デリミタが全くない場合も多いミスです。特にereg()(PHP 5.3で非推奨、PHP 7で削除)からの古いコードを移行する際によく見られます:
<?php
// 誤り — デリミタが全くない
preg_match('email', $input);
// 修正後
preg_match('/email/i', $input);
修正の確認
アプリをリロードせずにCLIからテストしましょう:
php -r "var_dump(preg_match('/your-pattern/', 'test string'));"
正常な結果は次のようになります:
int(0) # マッチなし、ただしワーニングもなし
int(1) # マッチあり
ワーニングが続く場合、PHPはint()の出力前に表示します。デバッグ中はエラーレポートを有効にしてすべてを表示させましょう:
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
ヒント
正規表現のミスは書きやすく、長いパターンでは見つけにくいものです。本番環境にプッシュする前に、インタラクティブにテストしましょう。ToolCraftのRegex Testerを使えば、PHPスタイルのパターンを入力し、サンプル文字列に対して実行してマッチ結果をリアルタイムで確認できます。ブラウザ外にデータは出ません。このようなデリミタの問題をコードがサーバーに到達する前に発見するために活用しています。
このワーニングを根本的に防ぐ3つの習慣:
- URLやファイルパスを含むパターンにはデリミタとして
#を使う — スラッシュのエスケープが不要になる preg_quote($value, $delimiter)は必ず両方の引数を渡す — 第2引数を省略すると選択したデリミタがエスケープされない- PHPStormまたはVS CodeでPHP Intelephense拡張機能を使うと、ファイルを実行する前に不正なパターンに下線が引かれる

