Lỗi Gặp Phải
Bạn nâng cấp PHP (hoặc hosting tự động làm điều đó), và giờ log tràn ngập những dòng như sau:
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
Trên PHP 8.0, lỗi này leo thang thành fatal error và trang web trắng tinh. Lúc 2 giờ sáng, đó là thứ bạn không bao giờ muốn gặp.
Nguyên Nhân
create_function() xuất hiện từ PHP 4.0.1 vào năm 2000. Hàm này bị deprecated từ PHP 7.2 và bị xóa hoàn toàn trong PHP 8.0. Về bản chất, nó chỉ là lớp bọc quanh eval() — biên dịch một hàm ẩn danh từ chuỗi thuần túy lúc runtime. Đây vừa là lỗ hổng bảo mật, vừa gây hao tốn hiệu năng. PHP 5.3 đã giới thiệu closure thực sự, làm được mọi thứ mà không mang theo bất kỳ gánh nặng nào.
Thấy lỗi này sau khi nâng cấp nghĩa là code của bạn hoặc một thư viện bên thứ ba vẫn đang dùng cú pháp cũ này.
Bước 1 — Tìm Tất Cả Vị Trí Sử Dụng
Đừng đoán mò phạm vi — hãy đo lường thực tế. Chạy lệnh này từ thư mục gốc của project:
grep -rn "create_function" /var/www/html --include="*.php"
Để bỏ qua vendor/ và node_modules/:
grep -rn "create_function" /var/www/html \
--include="*.php" \
--exclude-dir=vendor \
--exclude-dir=node_modules
Ghi lại từng file và số dòng. Mười chỗ trong code của bạn là việc của một buổi sáng. Nếu tất cả đều nằm trong vendor/, nhảy thẳng đến Bước 3.
Bước 2 — Thay create_function() Bằng Closure
Cấu trúc luôn giống nhau: một chuỗi tham số, một chuỗi code. Thay thế bằng hàm ẩn danh thực sự.
// Cũ — kiểu PHP 4, deprecated từ 7.2, bị xóa trong 8.0
$greet = create_function('$name', 'return "Hello, " . $name . "!";');
echo $greet('World'); // Hello, World!
// Mới — hoạt động trên PHP 5.3 đến 8.x
$greet = function($name) {
return 'Hello, ' . $name . '!';
};
echo $greet('World'); // Hello, World!
Callback truyền vào array_map, usort và các hàm tương tự là thủ phạm phổ biến nhất:
// Cũ
$doubled = array_map(create_function('$x', 'return $x * 2;'), [1, 2, 3]);
// Mới — hàm ẩn danh
$doubled = array_map(function($x) { return $x * 2; }, [1, 2, 3]);
// Gọn hơn với arrow function (PHP 7.4+)
$doubled = array_map(fn($x) => $x * 2, [1, 2, 3]);
Khi code cũ nội suy biến ngoài vào thân chuỗi, hãy chuyển sang mệnh đề use:
// Cũ — hack nội suy chuỗi
$multiplier = 5;
$fn = create_function('$x', "return \$x * {$multiplier};");
// Mới — capture biến tường minh
$multiplier = 5;
$fn = function($x) use ($multiplier) {
return $x * $multiplier;
};
Bước 3 — Xử Lý Code Bên Thứ Ba Trong vendor/
Tuyệt đối không chỉnh sửa trực tiếp các file trong vendor/. Lần composer update tiếp theo sẽ ghi đè thay đổi của bạn và mọi thứ trở về điểm xuất phát.
Kiểm tra xem package lỗi có phiên bản mới hơn không:
composer outdated
Cập nhật riêng package đó:
composer update vendor/package-name
Không có bản cập nhật mà bạn cần PHP 8.0 ngay? Có hai hướng đi:
- Fork package đó, tự áp dụng bản sửa lỗi, rồi trỏ
composer.jsonvào fork của bạn thông qua mụcrepositories. - Thay thế nó bằng một package thay thế đang được bảo trì tích cực.
Với WordPress: plugin lỗi thời là nguyên nhân của phần lớn các cảnh báo này. Cập nhật tất cả cùng lúc:
wp plugin update --all
Bước 4 — Tạm Thời Tắt Thông Báo Deprecated (Chỉ Là Giải Pháp Tạm Thời)
Cần deploy hotfix tối nay trong khi việc refactor đúng đắn phải chờ? Tắt thông báo deprecated ở cấp độ ứng dụng. Lưu ý rõ ràng: cách này chỉ ẩn cảnh báo trên PHP 7.x. Trên PHP 8.0 hàm đã bị xóa và vẫn sẽ crash.
// bootstrap/index.php — đánh dấu TODO này và quay lại sau
error_reporting(E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED);
Hoặc qua file cấu hình:
# php.ini
error_reporting = E_ALL & ~E_DEPRECATED
# .htaccess (Apache)
php_value error_reporting "E_ALL & ~E_DEPRECATED"
Cách này chỉ cho bạn thêm vài tiếng. Không phải vài tuần.
Xác Nhận Bản Sửa Lỗi
Theo dõi PHP error log trong khi tải lại trang bị lỗi:
# Theo dõi PHP error log
tail -f /var/log/php/error.log
# hoặc
tail -f /var/log/nginx/error.log
Kiểm tra cú pháp một file cụ thể từ dòng lệnh:
php -l path/to/fixed-file.php
# Output: No syntax errors detected in path/to/fixed-file.php
Kiểm tra toàn bộ thư mục ứng dụng theo cách đệ quy và lọc bỏ các file không lỗi:
find /var/www/html/app -name "*.php" -exec php -l {} \; 2>&1 | grep -v "No syntax errors"
Không có output nghĩa là bạn đã sạch lỗi.
Phát Hiện Lỗi Trước Khi Lên Production
Một lần gọi create_function() lọt qua đến server PHP 8.0 sẽ làm trắng trang của bạn. Thêm Rector vào CI pipeline để chặn loại lỗi này ngay từ lúc commit:
# Cài đặt Rector
composer require rector/rector --dev
# Chạy thử: xem tất cả những gì nó sẽ thay đổi
vendor/bin/rector process src --dry-run
Rector hiểu phép chuyển đổi create_function() → closure và có thể tự động viết lại hàng chục chỗ. Chạy một lần, xem lại diff, commit. Xong.
Tóm Tắt Nhanh
- PHP 7.2 —
create_function()deprecated (cảnh báo E_DEPRECATED) - PHP 8.0 —
create_function()bị xóa (fatal error, trang trắng) - Cách sửa: viết lại thành hàm ẩn danh
function() {}hoặc arrow functionfn() => - Code bên thứ ba: cập nhật package qua Composer — không bao giờ chỉnh sửa trực tiếp
vendor/ - Bảo vệ CI: thêm Rector hoặc PHPStan để bắt các lệnh gọi deprecated trước khi deploy

