PHPで Parse error: syntax error, unexpected ... というエラーが出て困っていませんか?
このエラーは、PHPの構文(文法)ルールに違反するコードを書いたときに発生します。PHPインタプリタが「予期しないトークン(unexpected token)」を発見した、つまり「ここにこの記号や文字が来るはずがない」と判断したことを意味します。
初心者から上級者まで、誰もが一度は遭遇するのがこの Parse error です。しかも、エラーメッセージが指す行番号が実際のミス箇所とズレていることが多く、原因特定に苦労するケースも少なくありません。
この記事では、Parse error: syntax error, unexpected の全パターンを網羅的に解説し、それぞれの原因と具体的な修正方法をコード例付きで紹介します。
この記事で解決できるエラーパターン
unexpected } / expecting } — 波括弧の問題
unexpected ; — セミコロンの位置ミス
unexpected T_STRING — 文字列・クォートの問題
unexpected , / expecting , — カンマの問題
unexpected T_VARIABLE — 変数の前のエラー
unexpected T_FUNCTION / T_CLASS — PHPバージョン非対応
unexpected ( / ) — 括弧の不一致
unexpected end of file — ファイル末尾の問題
unexpected T_ECHO / T_IF / T_WHILE — 制御構文のエラー
- WordPress / フレームワーク特有のParse error
Parse error: syntax error とは? — エラーメッセージの読み方
PHPの Parse error は、コードが実行される前の段階(パース段階=構文解析段階)で発生するエラーです。つまり、プログラムは1行も実行されません。
エラーメッセージの構造
Parse error のメッセージは、次のような構造になっています。
エラーメッセージの構造
Parse error: syntax error, unexpected 'X', expecting 'Y' in /path/to/file.php on line N
| 要素 |
意味 |
例 |
Parse error |
構文解析エラー(パースエラー) |
— |
syntax error |
構文エラーの種類 |
— |
unexpected 'X' |
PHPが予期しなかったトークン |
unexpected ';' |
expecting 'Y' |
PHPが本来期待していたトークン(省略あり) |
expecting ')' |
in /path/to/file.php |
エラーが発生したファイルパス |
in /var/www/index.php |
on line N |
エラーが検出された行番号 |
on line 15 |
「unexpected」と「expecting」の関係
unexpected は「ここに来るべきでないものが来た」、expecting は「本来ここに来るべきだったもの」を示します。
例:セミコロン忘れのエラーメッセージ
Parse error: syntax error, unexpected T_VARIABLE, expecting ';' in /var/www/test.php on line 5
このメッセージは「5行目で変数(T_VARIABLE)が見つかったが、セミコロン(;)が来るはずだった」という意味です。つまり、4行目の末尾にセミコロンを付け忘れた可能性が高いことを示しています。
注意:Parse error で表示される行番号は「エラーが検出された行」であり、「実際にミスがある行」とは限りません。多くの場合、エラー行の1〜2行前に本当の原因があります。必ず前後の行も確認しましょう。
トークンとは?
PHPのエラーメッセージに出てくる T_STRING、T_VARIABLE などは「トークン」と呼ばれるものです。PHPは実行前にコードを「トークン」(字句)に分解します。
| トークン名 |
意味 |
具体例 |
T_STRING |
識別子(文字列リテラルではない) |
関数名、クラス名、定数名 |
T_VARIABLE |
変数 |
$name、$count |
T_LNUMBER |
整数リテラル |
42、0xFF |
T_DNUMBER |
浮動小数点リテラル |
3.14 |
T_CONSTANT_ENCAPSED_STRING |
クォートされた文字列 |
'hello'、"world" |
T_FUNCTION |
function キーワード |
function foo() |
T_CLASS |
class キーワード |
class User |
T_IF / T_ELSE / T_ELSEIF |
条件分岐キーワード |
if、else、elseif |
T_WHILE / T_FOR / T_FOREACH |
ループキーワード |
while、for、foreach |
T_ECHO / T_PRINT |
出力キーワード |
echo、print |
T_RETURN |
return キーワード |
return $val; |
T_OBJECT_OPERATOR |
アロー演算子 |
-> |
T_DOUBLE_ARROW |
ダブルアロー |
=> |
T_PAAMAYIM_NEKUDOTAYIM |
スコープ解決演算子 |
:: |
T_NS_SEPARATOR |
名前空間の区切り |
|
Parse error が発生する仕組み
PHPコードの実行プロセスは以下のとおりです。
| ステップ |
処理 |
エラーの種類 |
| 1. 字句解析(Lexing) |
コードをトークンに分解 |
不正なトークン |
| 2. 構文解析(Parsing) |
トークンの並びが文法に合うか検証 |
Parse error(ここで発生) |
| 3. コンパイル |
OPcodeに変換 |
— |
| 4. 実行 |
OPcodeを実行 |
Runtime error |
Parse error はステップ2で発生するため、コードは一切実行されません。try-catch で捕捉することもできません(PHP 7.0 以降は ParseError クラスが存在しますが、同じファイル内の構文エラーはキャッチできません)。
エラー行番号の「ズレ」に注意
Parse error の最大の落とし穴は、エラーが報告される行番号と、実際のミスの場所がズレることです。
PHP — 4行目のセミコロン忘れ
<?php
$name = 'John'
$age = 25; // ← ここでエラー報告(line 3)
echo 'Hello';
上のコードでは、2行目の末尾にセミコロンがありませんが、エラーは3行目で報告されます。PHPは3行目の $age を読んだ時点で「前の文が終わっていない」と気づくためです。
ポイント:エラーが報告された行にミスが見つからない場合は、必ず1〜3行前を確認しましょう。特にセミコロン忘れ、クォートの閉じ忘れが多いパターンです。
unexpected '}' / expecting '}' — 波括弧の閉じ忘れ・余分
波括弧 {} に関するエラーは、Parse error の中で最も頻繁に発生するパターンです。
パターン1: 波括弧の閉じ忘れ
エラーメッセージ:
エラーメッセージ
Parse error: syntax error, unexpected end of file, expecting '}' in /var/www/test.php on line 20
エラーが出るコード:
PHP(エラーあり)
function calculateTotal($items) {
$total = 0;
foreach ($items as $item) {
if ($item['price'] > 0) {
$total += $item['price'];
}
// ← foreach の閉じ括弧 } がない!
} // ← これは function の閉じ括弧
修正後のコード:
PHP(修正後)
function calculateTotal($items) {
$total = 0;
foreach ($items as $item) {
if ($item['price'] > 0) {
$total += $item['price'];
}
} // ← foreach の閉じ括弧を追加
return $total;
}
パターン2: 余分な閉じ波括弧
エラーメッセージ:
エラーメッセージ
Parse error: syntax error, unexpected '}' in /var/www/test.php on line 7
エラーが出るコード:
PHP(エラーあり)
function greet($name) {
if ($name !== '') {
echo "Hello, $name!";
}
}
} // ← 余分な閉じ波括弧!
修正後のコード:
PHP(修正後)
function greet($name) {
if ($name !== '') {
echo "Hello, $name!";
}
} // ← 余分な } を削除
パターン3: if/else のネストが深い場合
ネストが深くなると、どの { に対応する } なのかが分かりにくくなります。
エラーが出るコード:
PHP(エラーあり)
function processOrder($order) {
if ($order['status'] === 'pending') {
if ($order['total'] > 0) {
if ($order['payment'] === 'credit') {
processCredit($order);
} else {
processCash($order);
}
// ← if ($order['total'] > 0) の } がない!
} else {
echo "Order already processed";
}
}
修正後のコード:
PHP(修正後)
function processOrder($order) {
if ($order['status'] === 'pending') {
if ($order['total'] > 0) {
if ($order['payment'] === 'credit') {
processCredit($order);
} else {
processCash($order);
}
} // ← 閉じ括弧を追加
} else {
echo "Order already processed";
}
}
ポイント:波括弧の対応を確認するには、エディタの「括弧のハイライト機能」を使いましょう。VSCode では波括弧にカーソルを置くと、対応する括弧がハイライトされます。
パターン4: switch 文の波括弧
PHP(エラーあり)
switch ($status) {
case 'active':
echo "Active";
break;
case 'inactive':
echo "Inactive";
break;
default:
echo "Unknown";
// ← switch の閉じ波括弧 } がない!
PHP(修正後)
switch ($status) {
case 'active':
echo "Active";
break;
case 'inactive':
echo "Inactive";
break;
default:
echo "Unknown";
} // ← 閉じ括弧を追加
パターン5: クラス定義の波括弧
PHP(エラーあり)
class User {
private $name;
private $email;
public function __construct($name, $email) {
$this->name = $name;
$this->email = $email;
// ← __construct の閉じ括弧 } がない!
public function getName() {
return $this->name;
}
}
PHP(修正後)
class User {
private $name;
private $email;
public function __construct($name, $email) {
$this->name = $name;
$this->email = $email;
} // ← 閉じ括弧を追加
public function getName() {
return $this->name;
}
}
波括弧エラーを防ぐベストプラクティス
波括弧エラーの予防策
- 適切なインデントを徹底する(タブまたはスペース4つ)
{ を書いたら即座に } も書き、その間にコードを入れる
- VSCode の Bracket Pair Colorization を有効にして、対応する括弧を色で識別する
- ネストが3階層以上になったら、早期リターン(Early Return)でネストを減らすことを検討する
// end foreach のようなコメントを閉じ括弧の後に書く
早期リターンでネストを減らす例
PHP(ネストが深い — エラーが起きやすい)
function processUser($user) {
if ($user !== null) {
if ($user->isActive()) {
if ($user->hasPermission()) {
// メイン処理
return $user->process();
}
}
}
return false;
}
PHP(早期リターンでリファクタリング)
function processUser($user) {
if ($user === null) {
return false;
}
if (!$user->isActive()) {
return false;
}
if (!$user->hasPermission()) {
return false;
}
// メイン処理
return $user->process();
}
unexpected ';' — セミコロンの位置ミス
セミコロン ; に関する Parse error は、不適切な場所にセミコロンが置かれたときに発生します。
パターン1: for 文の構文内でのセミコロンミス
エラーメッセージ
Parse error: syntax error, unexpected ';' in /var/www/test.php on line 3
PHP(エラーあり)
// for文の括弧内でカンマの代わりにセミコロンを使用
for ($i = 0; $j = 0; $i < 10; $i++; $j++) {
// 4つのセミコロンがある(3つまで)
}
PHP(修正後)
// 同じパートの複数式はカンマで区切る
for ($i = 0, $j = 0; $i < 10; $i++, $j++) {
// セミコロンは2つだけ(初期化;条件;更新)
}
注意:for文の構文は for (初期化; 条件; 更新) の3パートで、セミコロンは2つだけ使います。各パート内で複数の式を書く場合はカンマで区切ります。
パターン2: 関数定義のパラメータ後のセミコロン
PHP(エラーあり)
// 関数定義の末尾にセミコロンを付けてしまった
function add($a, $b); {
return $a + $b;
}
PHP(修正後)
function add($a, $b) {
return $a + $b;
}
パターン3: 配列定義内のセミコロン
PHP(エラーあり)
$colors = [
'red'; // ← カンマではなくセミコロン!
'green';
'blue'
];
PHP(修正後)
$colors = [
'red', // ← カンマに修正
'green',
'blue'
];
パターン4: if 文の条件の後にセミコロン
PHP(エラーあり)
if ($count > 0); { // ← 条件の後にセミコロン!
echo "Items found";
}
注意:この場合、PHPバージョンによっては Parse error にならず、空文(empty statement)として解釈されることがあります。その場合、if の条件に関係なく波括弧内のコードが常に実行されてしまうため、別の意味で問題になります。
PHP(修正後)
if ($count > 0) { // ← セミコロンを削除
echo "Items found";
}
パターン5: クラスプロパティのデフォルト値にセミコロン
PHP(エラーあり)
class Config {
public $settings = [
'debug' => true; // ← カンマではなくセミコロン!
'cache' => false;
];
}
PHP(修正後)
class Config {
public $settings = [
'debug' => true, // ← カンマに修正
'cache' => false,
];
}
パターン6: 無名関数(クロージャ)の代入でのセミコロン忘れ
PHP(エラーあり)
$greet = function($name) {
return "Hello, $name";
} // ← 無名関数の代入にはセミコロンが必要!
$result = $greet('World');
PHP(修正後)
$greet = function($name) {
return "Hello, $name";
}; // ← セミコロンを追加
$result = $greet('World');
ポイント:通常の関数定義(function foo() {})にはセミコロンが不要ですが、無名関数を変数に代入する場合は文の終端なのでセミコロンが必要です。
unexpected T_STRING — 文字列・クォートの問題
T_STRING は PHP のトークン名で、「識別子」を意味します。文字列リテラルではなく、関数名やクラス名、定数名などの裸の文字列がこれに該当します。このエラーは主にクォートの問題で発生します。
パターン1: シングルクォートの閉じ忘れ
エラーメッセージ
Parse error: syntax error, unexpected T_STRING, expecting ',' or ';'
PHP(エラーあり)
echo 'It's a beautiful day';
// PHPは 'It' で文字列が終わったと認識し、
// s が T_STRING(識別子)として検出される
修正方法(3通り):
PHP(修正方法1: バックスラッシュでエスケープ)
echo 'It\'s a beautiful day';
PHP(修正方法2: ダブルクォートで囲む)
echo "It's a beautiful day";
PHP(修正方法3: ヒアドキュメント)
echo <<<EOT
It's a beautiful day
EOT;
パターン2: ダブルクォートの中にダブルクォート
PHP(エラーあり)
$html = "<a href="https://example.com">Link</a>";
// ← 二重引用符の中に二重引用符がそのまま入っている
PHP(修正方法1: エスケープ)
$html = "<a href="https://example.com">Link</a>";
PHP(修正方法2: シングルクォートで囲む)
$html = '<a href="https://example.com">Link</a>';
PHP(修正方法3: ヒアドキュメント)
$html = <<<HTML
<a href="https://example.com">Link</a>
HTML;
パターン3: SQL文の中のクォート問題
PHP(エラーあり)
$sql = "SELECT * FROM users WHERE name = 'O'Brien'";
// ← シングルクォート内のアポストロフィが問題
PHP(修正後 — プリペアドステートメント推奨)
// プリペアドステートメントを使うのが最善
$stmt = $pdo->prepare("SELECT * FROM users WHERE name = ?");
$stmt->execute(['O\'Brien']);
パターン4: PHP の予約語を関数名に使用
PHP(エラーあり)
// 'list' はPHPの予約語
function list($items) {
foreach ($items as $item) {
echo $item;
}
}
PHP(修正後)
// 予約語を避けた名前に変更
function listItems($items) {
foreach ($items as $item) {
echo $item;
}
}
| 予約語(関数名に使えない) |
代替案 |
list |
listItems、getList |
class |
className、cssClass |
array |
toArray、getArray |
empty |
isEmpty、checkEmpty |
global |
globalScope、getGlobal |
switch |
switchMode、toggle |
match(PHP 8.0+) |
matchPattern、findMatch |
fn(PHP 7.4+) |
func、callback |
パターン5: 文字列の結合忘れ
PHP(エラーあり)
echo "Hello, " $name;
// ← 結合演算子 . がない
PHP(修正後)
// 方法1: 結合演算子を使う
echo "Hello, " . $name;
// 方法2: ダブルクォート内に変数を埋め込む
echo "Hello, $name";
// 方法3: 波括弧で囲む(推奨)
echo "Hello, {$name}";
パターン6: 文字列内のバックスラッシュ問題(Windows パス)
PHP(エラーあり)
$path = "C:
ew estfile.txt";
//
が改行、 がタブとして解釈される
PHP(修正後)
// 方法1: バックスラッシュをエスケープ
$path = "C:\new\test\file.txt";
// 方法2: シングルクォート
$path = 'C:
ew estfile.txt';
// 方法3: スラッシュを使う(PHPはWindowsでも/を理解する)
$path = "C:/new/test/file.txt";
unexpected ',' / expecting ',' — カンマの問題
カンマに関するエラーは、関数の引数や配列の定義でよく発生します。
パターン1: 関数呼び出しで引数が欠落
PHP(エラーあり)
// 引数の間に値がないカンマ
myFunction($a, , $c); // ← 第2引数がない
PHP(修正後)
// 引数を正しく指定
myFunction($a, $b, $c);
// または引数を省略したい場合はデフォルト値を設定
function myFunction($a, $b = null, $c) {
// ...
}
パターン2: 配列定義で値が欠落
PHP(エラーあり)
$data = [
'name' => 'John',
'age' => , // ← 値がない!
'email' => 'john@example.com',
];
PHP(修正後)
$data = [
'name' => 'John',
'age' => 25, // ← 値を指定
'email' => 'john@example.com',
];
パターン3: trailing comma(末尾カンマ)とPHPバージョン
PHP(PHP 7.2 以前でエラー)
// 関数呼び出しの末尾カンマ(PHP 7.3+ で対応)
myFunction(
$arg1,
$arg2, // ← PHP 7.2以前ではエラー
);
// 関数定義の末尾カンマ(PHP 8.0+ で対応)
function myFunc(
$param1,
$param2, // ← PHP 7.4以前ではエラー
) {
// ...
}
| 構文 |
末尾カンマ対応バージョン |
配列 [1, 2, 3,] |
PHP 5.0+(古くから対応) |
関数呼び出し func($a, $b,) |
PHP 7.3+ |
関数定義 function($a, $b,) |
PHP 8.0+ |
use リスト use ($a, $b,) |
PHP 8.0+ |
match 式の各アーム |
PHP 8.0+ |
ポイント:末尾カンマはGit差分を見やすくし、配列やパラメータの追加・削除時にエラーを防ぐ効果があります。プロジェクトのPHPバージョンを確認して、対応している場合は積極的に使いましょう。
パターン4: 配列のカンマ忘れ
PHP(エラーあり)
$config = [
'host' => 'localhost' // ← カンマがない!
'port' => 3306,
'name' => 'mydb',
];
PHP(修正後)
$config = [
'host' => 'localhost', // ← カンマを追加
'port' => 3306,
'name' => 'mydb',
];
パターン5: match式のカンマ忘れ(PHP 8.0+)
PHP(エラーあり — PHP 8.0+)
$result = match($status) {
'active' => '有効' // ← カンマがない!
'inactive' => '無効',
default => '不明',
};
PHP(修正後)
$result = match($status) {
'active' => '有効', // ← カンマを追加
'inactive' => '無効',
default => '不明',
};
unexpected T_VARIABLE — 変数の前のエラー
T_VARIABLE(変数)が unexpected として報告される場合、ほとんどは前の行にあるミスが原因です。
パターン1: 前の行のセミコロン忘れ(最頻出)
PHP(エラーあり)
$name = 'John' // ← セミコロンがない!
$age = 25; // ← ここでエラー報告
PHP(修正後)
$name = 'John'; // ← セミコロンを追加
$age = 25;
パターン2: 文字列結合の . 忘れ
PHP(エラーあり)
$message = 'Hello '
$name // ← 結合演算子 . がない
', welcome!';
PHP(修正後)
$message = 'Hello '
. $name // ← . を追加
. ', welcome!';
パターン3: 連想配列の => 忘れ
PHP(エラーあり)
$user = [
'name' $name, // ← => がない!
'age' => $age,
];
PHP(修正後)
$user = [
'name' => $name, // ← => を追加
'age' => $age,
];
パターン4: echo/print の後のカンマ区切りでの問題
PHP(エラーあり)
echo 'Name: ' $name; // ← 結合演算子がない
PHP(修正後)
// 方法1: 結合演算子
echo 'Name: ' . $name;
// 方法2: カンマ区切り(echo のみ可能)
echo 'Name: ', $name;
// 方法3: ダブルクォートで変数展開
echo "Name: $name";
パターン5: 三項演算子の不完全な構文
PHP(エラーあり)
$result = $value > 0 // ← ? がない
'positive' : 'non-positive';
PHP(修正後)
$result = $value > 0 ? 'positive' : 'non-positive';
// PHP 8.0+ では null合体演算子も便利
$name = $data['name'] ?? 'Unknown';
パターン6: 関数呼び出しの括弧忘れ
PHP(エラーあり)
$length = strlen $text; // ← 括弧がない
PHP(修正後)
$length = strlen($text); // ← 括弧を追加
unexpected T_FUNCTION / T_CLASS — PHPバージョン非対応
T_FUNCTION や T_CLASS が unexpected として報告される場合、使用中のPHPバージョンが構文をサポートしていないことが多いです。
パターン1: アロー関数(PHP 7.4 未満で使用)
PHP(PHP 7.3以前でエラー)
// アロー関数は PHP 7.4+ の機能
$doubled = array_map(fn($n) => $n * 2, $numbers);
PHP(PHP 7.3以前でも動く修正)
$doubled = array_map(function($n) {
return $n * 2;
}, $numbers);
パターン2: 名前付き引数(PHP 8.0 未満で使用)
PHP(PHP 7.4以前でエラー)
// 名前付き引数は PHP 8.0+ の機能
$result = str_contains(haystack: $text, needle: 'hello');
PHP(PHP 7.4以前でも動く修正)
// 通常の位置引数を使う
$result = strpos($text, 'hello') !== false;
パターン3: match式(PHP 8.0 未満で使用)
PHP(PHP 7.4以前でエラー)
// match式は PHP 8.0+ の機能
$label = match($status) {
1 => 'Active',
2 => 'Inactive',
default => 'Unknown',
};
PHP(PHP 7.4以前でも動く修正)
// switch文で書き直す
switch ($status) {
case 1:
$label = 'Active';
break;
case 2:
$label = 'Inactive';
break;
default:
$label = 'Unknown';
}
パターン4: コンストラクタプロモーション(PHP 8.0 未満)
PHP(PHP 7.4以前でエラー)
// コンストラクタプロモーションは PHP 8.0+ の機能
class User {
public function __construct(
private string $name,
private int $age,
) {}
}
PHP(PHP 7.4以前でも動く修正)
class User {
private $name;
private $age;
public function __construct(string $name, int $age) {
$this->name = $name;
$this->age = $age;
}
}
パターン5: Enum(PHP 8.1 未満)
PHP(PHP 8.0以前でエラー)
// Enum は PHP 8.1+ の機能
enum Status: string {
case Active = 'active';
case Inactive = 'inactive';
}
PHP(PHP 8.0以前でも動く修正)
// クラス定数で代替
class Status {
const ACTIVE = 'active';
const INACTIVE = 'inactive';
}
PHPバージョン別の主要な新構文
| PHP バージョン |
追加された構文 |
トークン |
| PHP 7.0 |
スカラー型宣言、null合体演算子 ?? |
— |
| PHP 7.1 |
nullable型 ?string、void 戻り値型 |
— |
| PHP 7.4 |
アロー関数 fn() =>、型付きプロパティ |
T_FN |
| PHP 8.0 |
match式、名前付き引数、union型 int|string |
T_MATCH |
| PHP 8.1 |
Enum、Fiber、readonly プロパティ |
T_ENUM、T_READONLY |
| PHP 8.2 |
readonly クラス、DNF型 |
— |
| PHP 8.3 |
型付きクラス定数 |
— |
ポイント:自分のPHPバージョンを確認するには、php -v コマンドまたは phpinfo() を実行しましょう。サーバーとローカルのバージョンが異なる場合も多いので、両方を確認してください。
パターン6: 名前空間のuseとクラス定義の競合
PHP(エラーあり)
namespace AppControllers;
// use文の後にセミコロンを忘れた
use AppModelsUser
class UserController { // ← T_CLASS が unexpected
// ...
}
PHP(修正後)
namespace AppControllers;
use AppModelsUser; // ← セミコロンを追加
class UserController {
// ...
}
unexpected '(' / ')' — 括弧の不一致
括弧 () に関するエラーは、関数呼び出しや式の中で発生します。
パターン1: 配列の即時アクセス(PHP 5.3 以前)
PHP(PHP 5.3以前でエラー)
// 関数の戻り値に対する即時配列アクセス
$first = explode(',', $csv)[0]; // PHP 5.4+
PHP(PHP 5.3以前でも動く修正)
$parts = explode(',', $csv);
$first = $parts[0];
パターン2: 括弧の数が合わない
PHP(エラーあり)
if ((is_array($data) && (count($data) > 0)) {
// 開き括弧が3つ、閉じ括弧が2つ
}
PHP(修正後)
if (is_array($data) && (count($data) > 0)) {
// 開き括弧と閉じ括弧が2つずつ
}
パターン3: new の即時メソッド呼び出し(PHP 5.3 以前)
PHP(PHP 5.3以前でエラー)
// new の結果に対する即時メソッド呼び出し
$result = (new MyClass())->method(); // PHP 5.4+
PHP(PHP 5.3以前でも動く修正)
$obj = new MyClass();
$result = $obj->method();
パターン4: 定数のスプレッド演算子(PHP 8.0 以前)
PHP(PHP 8.0以前でエラー)
// 関数定義でのスプレッド演算子
function sum(int ...$numbers): int {
return array_sum($numbers);
}
// 引数のアンパックは PHP 5.6+ で対応
sum(...$values);
パターン5: 複雑な条件式の括弧不一致
PHP(エラーあり)
if (
($user->isActive() || $user->isAdmin())
&& ($user->hasPermission('edit')
|| ($user->getRole() === 'superadmin')
) {
// 括弧の対応が取れていない
}
PHP(修正後 — 変数に分解して可読性を上げる)
$isActiveOrAdmin = $user->isActive() || $user->isAdmin();
$hasEditAccess = $user->hasPermission('edit')
|| $user->getRole() === 'superadmin';
if ($isActiveOrAdmin && $hasEditAccess) {
// 読みやすく、括弧エラーも防げる
}
ポイント:複雑な条件式は、意味のある変数名に分解すると括弧の不一致を防げるだけでなく、コードの可読性も大幅に向上します。
unexpected end of file — ファイル末尾の問題
unexpected end of file は、ファイルの末尾に到達したが、PHPがまだ何かを期待しているときに発生します。
パターン1: 閉じ括弧の不足
エラーメッセージ
Parse error: syntax error, unexpected end of file, expecting '}' in /var/www/test.php on line 50
PHP(エラーあり)
function process($data) {
if ($data) {
foreach ($data as $item) {
echo $item;
}
}
// ← function の } がない! ファイル終了
PHP(修正後)
function process($data) {
if ($data) {
foreach ($data as $item) {
echo $item;
}
}
} // ← 閉じ括弧を追加
パターン2: PHP タグの閉じ忘れ(混在ファイル)
PHP/HTML(エラーあり)
<?php
$title = 'My Page';
// <?php の閉じタグを忘れたまま HTML に入ると...
<html>
<head><title></title></head>
PHP/HTML(修正後)
<?php
$title = 'My Page';
?>
<html>
<head><title><?php echo $title; ?></title></head>
注意:純粋なPHPファイル(HTMLを含まない)では、閉じタグ ?> は省略するのが推奨です。閉じタグの後に空白や改行があると、「Headers already sent」エラーの原因になります。
パターン3: ヒアドキュメントの閉じ忘れ
PHP(エラーあり)
$html = <<<HTML
<div class="container">
<h1>Hello World</h1>
</div>
HTML; // ← PHP 7.2以前ではインデント不可!
PHP(修正後 — PHP 7.2以前)
$html = <<<HTML
<div class="container">
<h1>Hello World</h1>
</div>
HTML; // ← 行頭に置く(インデントなし)
ポイント:PHP 7.3 以降では、ヒアドキュメントの終了マーカーをインデントできるようになりました。7.2 以前では行頭に置く必要があります。
パターン4: 文字列リテラルの閉じ忘れ
PHP(エラーあり)
$message = "This is a very long string
that spans multiple lines
but the closing quote is missing;
// ← 閉じダブルクォートがない!
echo $message; // ← ここもまだ文字列の中と解釈される
PHP(修正後)
$message = "This is a very long string "
. "that spans multiple lines "
. "and each line is properly quoted";
echo $message;
パターン5: PHPの開始タグ忘れ
PHP(エラーあり)
// <?php タグがない
$name = 'John';
echo "Hello, $name";
PHP(修正後)
<?php
$name = 'John';
echo "Hello, $name";
パターン6: コメントアウトのミス
PHP(エラーあり)
function test() {
/* コメントアウト開始
$a = 1;
$b = 2;
閉じるのを忘れた
return $a + $b;
}
PHP(修正後)
function test() {
/* コメントアウト開始
$a = 1;
$b = 2;
ここで閉じる */
$a = 1;
$b = 2;
return $a + $b;
}
unexpected T_ECHO / T_IF / T_WHILE 等 — 制御構文のエラー
制御構文のキーワード(echo、if、while、for など)が unexpected として報告される場合、ほとんどは前の行のセミコロン忘れかHTMLとPHPの混在ミスが原因です。
パターン1: 前の行のセミコロン忘れ
PHP(エラーあり)
$name = 'John' // ← セミコロンがない
echo $name; // ← unexpected T_ECHO
PHP(修正後)
$name = 'John';
echo $name;
パターン2: HTMLとPHPの混在ミス
PHP/HTML(エラーあり)
<?php if ($loggedIn) { ?>
<p>Welcome!</p>
<?php if ($isAdmin) { ?> // ここまでOK
<p>Admin Panel</p>
<?php } ?>
<?php } ?>
<!-- ↑ 閉じの } が1つ足りない or 多い場合エラー -->
PHP/HTML(修正後 — 代替構文を使用)
<?php if ($loggedIn): ?>
<p>Welcome!</p>
<?php if ($isAdmin): ?>
<p>Admin Panel</p>
<?php endif; ?>
<?php endif; ?>
ポイント:HTMLとPHPを混在させる場合は、代替構文(if(): ... endif;、foreach(): ... endforeach;)を使うと、対応関係が明確になりエラーを防げます。
パターン3: 式の途中で制御構文を使おうとした
PHP(エラーあり)
$result = if ($value > 0) 'positive' else 'negative';
// ← if は式(expression)ではなく文(statement)
PHP(修正後)
// 三項演算子を使う
$result = $value > 0 ? 'positive' : 'negative';
// PHP 8.0+ では match式も使える
$result = match(true) {
$value > 0 => 'positive',
default => 'negative',
};
パターン4: ショートタグの問題
PHP(エラーあり — short_open_tag=Off の場合)
<? echo 'Hello'; ?>
// short_open_tag が Off だとPHPとして認識されない
PHP(修正後)
// 常にフルタグを使う
<?php echo 'Hello'; ?>
// ショートechoタグは PHP 5.4+ で常に使用可能
<?= 'Hello' ?>
パターン5: foreach / while の中でのセミコロン忘れ
PHP(エラーあり)
foreach ($items as $item) {
$total += $item['price'] // ← セミコロンがない
if ($item['tax']) { // ← unexpected T_IF
$total += $item['tax'];
}
}
PHP(修正後)
foreach ($items as $item) {
$total += $item['price']; // ← セミコロンを追加
if ($item['tax']) {
$total += $item['tax'];
}
}
WordPress / フレームワークでの Parse error
WordPress やLaravel などのフレームワークで Parse error が発生すると、画面が真っ白になったり、管理画面にアクセスできなくなることがあります。
functions.php の編集ミスで画面真っ白
WordPress のテーマファイル(特に functions.php)に構文エラーがあると、サイト全体が表示されなくなります。
注意:WordPress の管理画面(/wp-admin/)も表示されなくなるため、管理画面からの修正ができません。FTPまたはSSHでファイルを直接修正する必要があります。
復旧方法1: FTP/SSH でファイルを修正
SSH でサーバーに接続して修正
# SSHでサーバーに接続
ssh user@your-server.com
# functions.php を編集
vi /path/to/wp-content/themes/your-theme/functions.php
# または直前のバックアップに戻す
cp /path/to/backup/functions.php /path/to/wp-content/themes/your-theme/functions.php
復旧方法2: テーマを一時的に切り替える
phpMyAdmin または MySQL コマンドで実行
-- 現在のテーマを確認
SELECT option_value FROM wp_options
WHERE option_name = 'template';
-- デフォルトテーマに切り替え
UPDATE wp_options SET option_value = 'twentytwentyfour'
WHERE option_name = 'template';
UPDATE wp_options SET option_value = 'twentytwentyfour'
WHERE option_name = 'stylesheet';
復旧方法3: wp-config.php でデバッグモードを有効にする
wp-config.php
// デバッグモードを有効にしてエラーの詳細を表示
define('WP_DEBUG', true);
define('WP_DEBUG_DISPLAY', true);
define('WP_DEBUG_LOG', true);
// エラーログは wp-content/debug.log に出力される
wp-config.php 自体の構文エラー
PHP(wp-config.php でのよくあるエラー)
// DB接続情報でクォートのミス
define('DB_PASSWORD', 'my'password'); // ← エラー
// 修正: エスケープまたはダブルクォート
define('DB_PASSWORD', 'my\'password');
// または
define('DB_PASSWORD', "my'password");
WordPress でよくある Parse error パターン
| ファイル |
よくあるエラー |
原因 |
functions.php |
unexpected end of file |
閉じ括弧の忘れ、コピペミス |
wp-config.php |
unexpected T_STRING |
パスワードにシングルクォートが含まれる |
header.php |
unexpected T_ECHO |
PHPタグの閉じ忘れ |
single.php |
unexpected '}' |
テンプレートタグの波括弧不一致 |
| プラグインファイル |
unexpected T_FUNCTION |
PHPバージョン非対応の構文 |
Laravel / Composer でのParse error
ターミナル
# Composer autoload でParse errorが出た場合
# autoloadキャッシュをクリア
composer dump-autoload
# キャッシュのクリア
php artisan cache:clear
php artisan config:clear
php artisan view:clear
# 特定のファイルの構文チェック
php -l app/Http/Controllers/UserController.php
CakePHP / Symfony でのParse error
ターミナル
# CakePHP のキャッシュクリア
bin/cake cache clear_all
# Symfony のキャッシュクリア
php bin/console cache:clear
# プロジェクト全体の構文チェック
find . -name "*.php" -exec php -l {} ; | grep -i "error"
フレームワークでの Parse error 対策
- 本番環境にデプロイする前に、ローカルで構文チェックを行う
- Git を使って変更履歴を管理し、いつでも前のバージョンに戻せるようにする
- CI/CD パイプラインに
php -l による構文チェックを組み込む
- WordPress の場合、子テーマを使ってカスタマイズし、親テーマのアップデートで壊れないようにする
- ステージング環境で動作確認してから本番にデプロイする
デバッグテクニック — Parse error を素早く見つける方法
テクニック1: エラー行の1〜2行前を確認する
Parse error の最も基本的なデバッグ方法は、エラーが報告された行の1〜3行前を確認することです。
エラーメッセージの例
Parse error: syntax error, unexpected T_VARIABLE in /var/www/test.php on line 10
この場合、まず8〜10行目を集中的にチェックします。
| 確認すべきポイント |
具体的なチェック項目 |
| 前の行の末尾 |
セミコロン ; はあるか? |
| 文字列リテラル |
クォートの開始と終了は対応しているか? |
| 括弧の対応 |
()、{}、[] の対応は正しいか? |
| 結合演算子 |
文字列結合の . は忘れていないか? |
| カンマ |
配列や引数のカンマは正しいか? |
テクニック2: エディタのシンタックスハイライトを活用する
モダンなエディタは、構文エラーがある箇所を色の変化で示してくれます。
シンタックスハイライトで分かること
- 文字列のクォートが閉じていない → その行以降がすべて文字列色になる
- 波括弧が対応していない → 対応する括弧のハイライトがずれる
- 予約語のスペルミス → キーワードの色が付かない
- コメントが閉じていない → その行以降がコメント色になる
テクニック3: PHP -l(lint)コマンド
php -l コマンドは、ファイルを実行せずに構文チェックだけを行います。
ターミナル
# 単一ファイルの構文チェック
php -l test.php
# 正常な場合の出力
No syntax errors detected in test.php
# エラーがある場合の出力
Parse error: syntax error, unexpected end of file in test.php on line 15
Errors parsing test.php
ターミナル(複数ファイルを一括チェック)
# Linux / macOS
find . -name "*.php" -exec php -l {} ; 2>&1 | grep -v "No syntax"
# Windows(PowerShell)
Get-ChildItem -Recurse -Filter *.php | ForEach-Object {
php -l $_.FullName 2>&1
} | Where-Object { $_ -notmatch "No syntax" }
テクニック4: IDE の活用(VSCode / PhpStorm)
VSCode の設定:
settings.json(VSCode)
{
// PHP実行ファイルのパスを設定
"php.validate.executablePath": "C:/xampp/php/php.exe",
"php.validate.enable": true,
"php.validate.run": "onType",
// 推奨拡張機能
// - PHP Intelephense(構文チェック + 補完)
// - PHP Debug(Xdebug連携)
// - Error Lens(エラーをインラインで表示)
}
PhpStorm:
PhpStorm は設定不要で構文エラーをリアルタイムに検出します。エラー箇所に赤い波線が表示され、ホバーするとエラー内容が分かります。
テクニック5: php.ini の display_errors 設定
php.ini
; 開発環境では有効にする
display_errors = On
error_reporting = E_ALL
; 本番環境では無効にし、ログに記録
display_errors = Off
log_errors = On
error_log = /var/log/php_errors.log
PHP(スクリプト内で設定する場合)
// ただし Parse error は実行前に発生するため
// 同じファイル内でこの設定をしても効果がない
// 別のファイル(共通設定ファイル等)で設定する
ini_set('display_errors', 1);
error_reporting(E_ALL);
注意:Parse error は実行前に発生するため、エラーが起きているファイル内で ini_set() や error_reporting() を設定しても効果がありません。php.ini で設定するか、別のファイル(例:.htaccess や共通のbootstrapファイル)で設定してください。
テクニック6: Git diff で変更箇所を特定する
ターミナル
# 直前の変更を確認
git diff
# 特定のファイルの変更を確認
git diff path/to/file.php
# 直前のコミットとの差分
git diff HEAD~1
# 変更を元に戻す(注意して使用)
git checkout -- path/to/file.php
テクニック7: 二分探索法でエラー箇所を特定する
大きなファイルでエラー箇所が分からない場合、ファイルの半分をコメントアウトして、エラーが出るかどうかを確認する方法が有効です。
PHP(二分探索法の例)
<?php
// ===== ここから上半分 =====
// コード...
/* ===== ここから下半分をコメントアウト =====
// コード...
===== ここまで */
ポイント:エラーが消えたら下半分に原因があり、消えなかったら上半分に原因があります。これを繰り返すと、log2(n) 回の試行で原因箇所を特定できます。
テクニック8: オンラインPHP構文チェッカー
ローカル環境がない場合は、オンラインツールで構文チェックができます。
| ツール名 |
URL |
特徴 |
| PHP Sandbox |
phpsandbox.io |
ブラウザで実行・構文チェック |
| 3v4l.org |
3v4l.org |
複数のPHPバージョンで同時テスト |
| PHP Online Editor |
php-online.net |
シンプルなオンラインエディタ |
まとめ — Parse error 解決の早見表とフローチャート
エラーパターン早見表
| エラーメッセージ |
主な原因 |
確認すべき箇所 |
unexpected '}' |
余分な閉じ波括弧 |
対応する開き括弧を確認 |
expecting '}' |
閉じ波括弧の不足 |
ネスト構造を確認 |
unexpected ';' |
不適切な場所のセミコロン |
配列内、for文、関数定義を確認 |
unexpected T_STRING |
クォートの問題、予約語の使用 |
文字列のクォートを確認 |
unexpected ',' |
値のないカンマ |
関数引数、配列定義を確認 |
unexpected T_VARIABLE |
前の行のセミコロン忘れ |
1〜2行前を確認 |
unexpected T_FUNCTION |
PHPバージョン非対応 |
使用中のPHPバージョンを確認 |
unexpected '(' |
括弧の不一致 |
括弧の対応を確認 |
unexpected end of file |
閉じ括弧不足、文字列未閉じ |
ファイル全体の構造を確認 |
unexpected T_ECHO/T_IF |
前の行のセミコロン忘れ |
1〜2行前を確認 |
Parse error 解決フローチャート
Parse error が出たらこの手順で解決
- エラーメッセージを読む — unexpected と expecting を確認
- 報告された行番号を確認 — その行と1〜3行前をチェック
- エディタのハイライトを確認 — 色の変化で異常箇所を特定
- 括弧・クォートの対応を確認 — 開きと閉じの数を数える
- セミコロンを確認 — 文の末尾にあるか?不要な場所にないか?
- php -l で構文チェック — 修正後に確認
- PHPバージョンを確認 — 新しい構文を使っていないか?
予防のためのベストプラクティス
| 対策 |
効果 |
推奨度 |
| IDE/エディタの構文チェックを有効化 |
リアルタイムでエラーを検出 |
必須 |
| 適切なインデントを徹底 |
波括弧の対応が視覚的にわかる |
必須 |
| Bracket Pair Colorization を有効化 |
括弧の対応を色で識別 |
必須 |
php -l をGitフックに設定 |
コミット前に自動チェック |
強く推奨 |
| PHPStan / Psalm を導入 |
構文エラー以外も検出 |
推奨 |
| PHP CS Fixer で自動整形 |
コードスタイルの統一 |
推奨 |
| Git でバージョン管理 |
いつでも前の状態に戻せる |
必須 |
| ステージング環境で動作確認 |
本番での事故を防止 |
強く推奨 |
Git pre-commit フックでの構文チェック
.git/hooks/pre-commit
#!/bin/bash
# コミット対象のPHPファイルを構文チェック
FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E ".php$")
if [ -z "$FILES" ]; then
exit 0
fi
ERROR=0
for FILE in $FILES; do
php -l "$FILE" > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Syntax error in: $FILE"
php -l "$FILE"
ERROR=1
fi
done
if [ $ERROR -ne 0 ]; then
echo "Commit aborted due to PHP syntax errors."
exit 1
fi
exit 0
ポイント:上のスクリプトを .git/hooks/pre-commit に保存して実行権限を付与すると、構文エラーのあるPHPファイルをコミットしようとしたときに自動的にブロックしてくれます。
最後に
Parse error: syntax error, unexpected は、PHPプログラミングで最も基本的なエラーですが、エラーメッセージの読み方とよくあるパターンを知っていれば、素早く原因を特定して修正できます。
この記事で紹介したパターンとデバッグテクニックを参考に、構文エラーに悩む時間を最小限に抑えましょう。また、IDE やリンターを活用することで、そもそもエラーを書いてしまう前に検出できるようになります。
この記事のまとめ
- Parse error は構文解析段階で発生し、コードは1行も実行されない
- エラー行の1〜3行前に本当の原因があることが多い
- 最も多い原因はセミコロン忘れ、波括弧の不一致、クォートの閉じ忘れ
php -l コマンドで実行前に構文チェックができる
- IDE / エディタのシンタックスハイライトと構文チェック機能を活用する
- WordPress の場合、Parse error で画面が真っ白になったらFTP/SSHで復旧する
- Git pre-commit フックでコミット前の自動チェックを導入する