エラーの内容
PHPをアップグレードした(あるいはホスティング側が勝手にアップグレードした)後、ログが以下のメッセージで埋め尽くされています:
Deprecated: Function create_function() is deprecated in /var/www/html/wp-includes/functions.php on line 4587
Deprecated: Function create_function() is deprecated in /var/www/html/app/lib/template.php on line 112
PHP 8.0ではこれが致命的なエラーに昇格し、ページが真っ白になります。深夜2時に、これほど困るものはありません。
なぜこのエラーが発生するのか
create_function()は2000年にPHP 4.0.1で導入された関数です。PHP 7.2で非推奨となり、PHP 8.0で完全に削除されました。内部的にはeval()のラッパーに過ぎず、実行時に文字列から無名関数をコンパイルします。これはセキュリティ上の脆弱性であり、パフォーマンスの低下にもつながります。PHP 5.3で導入された本来のクロージャは、こうした問題を一切抱えずに同じ処理を実現できます。
アップグレード後にこのエラーが表示される場合、自分のコードまたはサードパーティのライブラリがまだこの古いパターンを使用しています。
ステップ1 — すべての該当箇所を洗い出す
範囲を推測するのではなく、実際に調査しましょう。プロジェクトのルートから以下を実行します:
grep -rn "create_function" /var/www/html --include="*.php"
vendor/とnode_modules/を除外する場合:
grep -rn "create_function" /var/www/html \
--include="*.php" \
--exclude-dir=vendor \
--exclude-dir=node_modules
ファイルと行番号をすべてメモしておきましょう。自分のコードに10箇所あれば、午前中の作業で対応できます。すべてがvendor/内であれば、ステップ3へ直接進んでください。
ステップ2 — create_function() をクロージャに書き換える
パターンは常に同じです。引数の文字列とコードの文字列があれば、それを本来の無名関数に置き換えます。
// 旧 — PHP 4スタイル、7.2で非推奨、8.0で削除
$greet = create_function('$name', 'return "Hello, " . $name . "!";');
echo $greet('World'); // Hello, World!
// 新 — PHP 5.3〜8.x で動作
$greet = function($name) {
return 'Hello, ' . $name . '!';
};
echo $greet('World'); // Hello, World!
array_map、usortなどに渡すコールバックが最もよく見られるケースです:
// 旧
$doubled = array_map(create_function('$x', 'return $x * 2;'), [1, 2, 3]);
// 新 — 無名関数
$doubled = array_map(function($x) { return $x * 2; }, [1, 2, 3]);
// アロー関数を使えばさらにすっきり(PHP 7.4+)
$doubled = array_map(fn($x) => $x * 2, [1, 2, 3]);
古いコードが外部変数を文字列本体に展開している場合は、use句に変換します:
// 旧 — 文字列展開によるハック
$multiplier = 5;
$fn = create_function('$x', "return \$x * {$multiplier};");
// 新 — 明示的な変数キャプチャ
$multiplier = 5;
$fn = function($x) use ($multiplier) {
return $x * $multiplier;
};
ステップ3 — vendor/ 内のサードパーティコードへの対処
vendor/配下のファイルを直接編集してはいけません。次回のcomposer updateで変更が上書きされ、振り出しに戻ってしまいます。
問題のあるパッケージに新しいバージョンが存在するか確認します:
composer outdated
該当パッケージだけを更新します:
composer update vendor/package-name
更新版がなく、今すぐPHP 8.0が必要な場合は、以下の2つの選択肢があります:
- パッケージをフォークして自分で修正を適用し、
repositoriesエントリ経由でcomposer.jsonがフォーク先を参照するようにする。 - 積極的にメンテナンスされている代替パッケージに置き換える。
WordPressサイトの場合、古いプラグインがこれらの警告の大部分の原因です。一括更新しましょう:
wp plugin update --all
ステップ4 — 非推奨通知を一時的に抑制する(暫定対応のみ)
今夜ホットフィックスをリリースしなければならず、本格的なリファクタリングは後回しにしたい場合は、アプリケーションレベルで非推奨通知を抑制できます。ただし注意が必要です。これはPHP 7.xで警告を消すだけです。PHP 8.0では関数自体が削除されているため、引き続きクラッシュします。
// bootstrap/index.php — TODOとしてマークして後で対応すること
error_reporting(E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED);
設定ファイルで指定する場合:
# php.ini
error_reporting = E_ALL & ~E_DEPRECATED
# .htaccess (Apache)
php_value error_reporting "E_ALL & ~E_DEPRECATED"
これで稼げるのは数時間です。数週間ではありません。
修正の確認
対象ページをリロードしながらPHPエラーログを監視します:
# PHPエラーログをリアルタイム確認
tail -f /var/log/php/error.log
# または
tail -f /var/log/nginx/error.log
コマンドラインで特定のファイルを構文チェックします:
php -l path/to/fixed-file.php
# 出力例: No syntax errors detected in path/to/fixed-file.php
アプリケーションディレクトリ全体を再帰的に構文チェックし、問題のないファイルを除外します:
find /var/www/html/app -name "*.php" -exec php -l {} \; 2>&1 | grep -v "No syntax errors"
何も出力されなければ、問題ありません。
本番環境に持ち込む前に検出する
create_function()の呼び出しが1つでもPHP 8.0のサーバーに紛れ込めば、ページが真っ白になります。RectorをCIパイプラインに組み込んで、このクラスのバグをコミット時点で防ぎましょう:
# Rectorのインストール
composer require rector/rector --dev
# ドライラン:変更内容を事前確認
vendor/bin/rector process src --dry-run
Rectorはcreate_function()からクロージャへの変換を理解しており、多数の該当箇所を自動的に書き換えることができます。一度実行してdiffを確認し、コミットすれば完了です。
クイックリファレンス
- PHP 7.2 —
create_function()非推奨(E_DEPRECATED警告) - PHP 8.0 —
create_function()削除(致命的エラー、ページ真っ白) - 修正方法:無名関数
function() {}またはアロー関数fn() =>として書き直す - サードパーティコード:Composerでパッケージを更新する —
vendor/を直接編集しない - CIガード:RectorまたはPHPStanを追加して非推奨な呼び出しをデプロイ前に検出する

