یک بار، بعد از مهاجرت یک پروژه‌ی قدیمی به سرور جدید، سایت با صفحه‌ی سفید بالا آمد و در لاگ سرور یک پیام ساده دیدم: Call to undefined function mysql_connect(). تا آن روز، این خطا را به‌عنوان یک مشکل تایپی می‌شناختم که با یک جستجو در کد حل می‌شود. آن روز فهمیدم که خطای Call to undefined function در PHP، یک پنجره به سمت نسخه‌ها، افزونه‌های PHP، و معماری وابستگی‌ها است. این خطا، در ظاهر ساده به‌نظر می‌رسد ولی در باطن، معمولاً نشانه‌ی یک تغییر سیستماتیک در محیط اجرا یا در نسخه‌ی زبان است.

خطای Call to undefined function دقیقاً چیست؟

در PHP، هر فراخوانی تابع، نیازمند این است که تابع تعریف شده باشد. اگر کد شما تابعی را فراخوانی کند که در هیچ جای بارگذاری‌شده‌ی پروژه (هسته، افزونه‌ها، فایل‌های include شده) وجود نداشته باشد، PHP خطای زیر را مطرح می‌کند:

Fatal error: Uncaught Error: Call to undefined function my_custom_function() in /path/to/file.php:12
Stack trace:
#0 {main}
  thrown in /path/to/file.php on line 12

نکته‌ی مهم در این پیام: این خطا از نوع Fatal است. یعنی اسکریپت کاملاً متوقف می‌شود. این تفاوت آن با خطاهای Warning و Notice است، که اجرا را متوقف نمی‌کنند.

در PHP 7 و 8، این خطا به‌عنوان Error مطرح می‌شود که یک استثنای قابل مدیریت است. در PHP 5، به‌عنوان Fatal Error مستقیم مطرح می‌شد که قابل مدیریت نبود. این تفاوت، مهم است چون در PHP 7+ می‌توانید این خطا را در try/catch مدیریت کنید.

پیام خطا دو داده‌ی مهم دارد: نام تابع و مسیر فایل. نام تابع، دقیقاً می‌گوید کدام تابع یافت نشد. مسیر فایل، به شما می‌گوید کجا این فراخوانی انجام شده. ترکیب این دو، جهت تشخیص را تعیین می‌کند.

اگر با مبانی PHP آشنایی ندارید، ابتدا آموزش PHP از صفر برای مبتدیان را بخوانید تا مدل ذهنی درستی از توابع و بارگذاری فایل‌ها شکل بگیرد.

خطای Call to undefined function، شبیه به نامه‌ای است که به یک آدرس ارسال شده ولی گیرنده در آن آدرس نیست. تابع، در جایی که شما فراخوانی می‌کنید، وجود ندارد. ریشه، معمولاً یک لایه عقب‌تر در بارگذاری فایل‌ها یا نسخه‌ی PHP است.

چرا PHP این خطا را مطرح می‌کند؟

این خطا، از یک اصل بنیادین در PHP می‌آید: توابع باید قبل از فراخوانی تعریف شده باشند. PHP یک زبان interpreter است که در زمان اجرا، فایل‌ها را به ترتیب بارگذاری می‌کند. اگر تابعی در جای دیگری تعریف شده ولی هنوز بارگذاری نشده، یا اصلاً در هیچ جای بارگذاری‌شده وجود ندارد، این خطا مطرح می‌شود.

سه دلیل بنیادین برای این خطا:

یک: بارگذاری ناقص. تابع در یک فایل تعریف شده، ولی آن فایل بارگذاری نشده. مثلاً در functions.php قالب، یک تابع تعریف شده که به یک فایل دیگر include می‌شود. اگر include نادرست باشد، تابع یافت نمی‌شود.

دو: نبود افزونه‌ی PHP. بعضی توابع بخشی از افزونه‌های PHP هستند، نه هسته. مثلاً mysqli_connect بخشی از افزونه‌ی mysqli است، و curl_init بخشی از افزونه‌ی curl. اگر این افزونه‌ها نصب نباشند، توابع آن‌ها یافت نمی‌شوند.

سه: تغییر نسخه‌ی PHP. بعضی توابع در نسخه‌های قدیمی PHP وجود داشتند و در نسخه‌های جدید حذف شده‌اند. مثال کلاسیک: توابع mysql_* که در PHP 5.5 به بعد Deprecated و در PHP 7 حذف شدند. اگر کد شما هنوز از این توابع استفاده می‌کند، در PHP 7+ این خطا ظاهر می‌شود.

در چارچوب کلی PHP، این خطا در سه لایه‌ی متفاوت رخ می‌دهد: لایه‌ی بارگذاری فایل، لایه‌ی افزونه‌های PHP، و لایه‌ی نسخه‌ی زبان. تشخیص درست، نیاز به بررسی هر سه لایه دارد. اگر با ساختار فایل‌های PHP آشنا نیستید، آموزش PDO در PHP می‌تواند به درک بهتر لایه‌ی دیتابیس کمک کند.

چهار دسته اصلی این خطا

در تجربه‌ی من روی صدها پروژه‌ی PHP، خطای Call to undefined function در چهار دسته‌ی اصلی طبقه‌بندی می‌شود. شناخت این دسته‌بندی، تشخیص را در چند دقیقه ممکن می‌کند.

  1. افزونه‌ی PHP نصب نشده: تابع بخشی از افزونه‌ای است که نصب نشده.
  2. تابع حذف‌شده یا Deprecated: تابع در نسخه‌ی جدید PHP حذف شده.
  3. مشکلات namespace: تابع در namespace دیگری تعریف شده و شما بدون use فراخوانی می‌کنید.
  4. مشکلات autoload: فایل تابع بارگذاری نشده، معمولاً در Composer یا autoloaderهای سفارشی.

هر دسته، نشانه‌های مخصوص به خود و راه‌حل اختصاصی دارد. در بخش‌های بعدی، هر دسته را جداگانه باز می‌کنم.

افزونه‌ی PHP نصب نشده

شایع‌ترین دسته‌ی این خطا، مربوط به افزونه‌های PHP است. PHP به‌طور پیش‌فرض، مجموعه‌ی محدودی از توابع را ارائه می‌دهد. برای قابلیت‌های بیشتر، افزونه‌های PHP باید نصب و فعال شوند.

افزونه‌های رایج و توابع مربوطه

  • mysqli: توابع mysqli_connect، mysqli_query، و مشابه‌ها. برای اتصال به MySQL/MariaDB.
  • pdo_mysql: کلاس PDO با driver mysql. برای اتصال استاندارد به MySQL.
  • curl: توابع curl_init، curl_setopt، curl_exec. برای درخواست‌های HTTP.
  • gd یا imagick: توابع پردازش تصویر مثل imagecreatefromjpeg.
  • mbstring: توابع کار با رشته‌های چندبایتی مثل mb_strlen.
  • json: توابع json_encode و json_decode. در PHP 8 به‌طور پیش‌فرض فعال است.
  • xml: توابع کار با XML مثل simplexml_load_string.
  • intl: توابع بین‌المللی‌سازی مثل collator_sort.
  • zip: توابع کار با فایل‌های zip.
  • openssl: توابع رمزنگاری و اتصال امن.

هر یک از این افزونه‌ها، مجموعه‌ای از توابع را فراهم می‌کند. اگر افزونه‌ای نصب نباشد، توابع مربوطه یافت نمی‌شوند و خطای Call to undefined function مطرح می‌شود. مبانی کامل اتصال به دیتابیس در اتصال PHP به MySQL آمده است.

نحوه بررسی و نصب افزونه‌ها

برای بررسی افزونه‌های نصب‌شده:

php -m

برای نصب افزونه در سرورهای لینوکس:

# Debian/Ubuntu
sudo apt-get install php-mysqli php-curl php-gd php-mbstring

# CentOS/RHEL
sudo yum install php-mysqli php-curl php-gd php-mbstring

در هاست‌های اشتراکی، معمولاً از پنل هاست (cPanel یا DirectAdmin) می‌توانید افزونه‌ها را فعال کنید. در cPanel، بخش Select PHP Version یا PHP Extensions به شما این امکان را می‌دهد. مبانی cPanel در cPanel چیست آمده است.

تابع حذف‌شده یا Deprecated

دسته‌ی دوم، مربوط به توابعی است که در نسخه‌های قبلی PHP وجود داشته‌اند ولی در نسخه‌های جدید حذف شده‌اند. این دسته به‌خصوص در مهاجرت از PHP 5 به PHP 7+ شایع است.

خانواده توابع mysql_*

توابع mysql_* که در PHP 5 استفاده می‌شدند، در PHP 5.5 Deprecated و در PHP 7 کاملاً حذف شدند. اگر کد شما هنوز از این توابع استفاده می‌کند:

$connection = mysql_connect("localhost", "user", "pass"); // Fatal error در PHP 7+

راه‌حل: مهاجرت به mysqli_* یا PDO. الگوهای جدید در آموزش PDO در PHP و اتصال PHP به MySQL آمده است.

توابع ایجاد شده در PHP 7

بعضی از کدهای قدیمی، تابعی از PHP 7 را استفاده می‌کنند ولی روی PHP 5 اجرا می‌شوند. مثلاً random_bytes در PHP 7 معرفی شد. اگر کد شما این تابع را فراخوانی کند و روی PHP 5 اجرا شود، خطا می‌گیرید. راه‌حل: ارتقای PHP یا استفاده از polyfill.

تابع create_function

create_function در PHP 7.2 Deprecated و در PHP 8 حذف شد. اگر کد شما از این تابع استفاده می‌کند، مهاجرت به anonymous functions ضروری است. جزئیات کامل در خطای Deprecated در PHP آمده است.

تابع each

each() که برای پیمایش آرایه‌ها استفاده می‌شد، در PHP 7.2 Deprecated و در PHP 8 حذف شد. راه‌حل: استفاده از foreach استاندارد.

تابع money_format

money_format() که برای قالب‌بندی پول استفاده می‌شد، در PHP 7.4 Deprecated و در PHP 8 حذف شد. راه‌حل: استفاده از NumberFormatter از افزونه‌ی intl.

مبانی این تغییرات در تفاوت PHP 7 و PHP 8 آمده است.

مشکلات namespace و use statement

در PHP 5.3 به بعد، namespaceها معرفی شدند. این امکان، کد را سازمان‌دهی‌شده‌تر می‌کند، ولی در عین حال، منبع خطاهای Call to undefined function نیز هست.

مشکل رایج: فراموشی backslash در توابع گلوبال

وقتی در یک namespace هستید و می‌خواهید یک تابع گلوبال PHP را فراخوانی کنید، باید از backslash استفاده کنید:

namespace MyPlugin;

// اشتباه - به دنبال MyPlugin\strlen می‌گردد
$len = strlen($text);

// درست - به تابع strlen گلوبال اشاره می‌کند
$len = \strlen($text);

نکته‌ی ظریف: PHP به‌طور خودکار برای توابع، fallback به namespace گلوبال انجام می‌دهد. یعنی در namespace، اگر تابع محلی نباشد، به‌طور خودکار تابع گلوبال فراخوانی می‌شود. ولی اگر namespace یا use statement اشتباه باشد، این fallback ممکن است کار نکند.

مشکل رایج: use statement فراموش‌شده

وقتی از کلاس‌ها یا توابع یک namespace دیگر استفاده می‌کنید، باید use statement داشته باشید:

namespace MyPlugin;

// اشتباه - کلاس پیدا نمی‌شود
$client = new HttpClient();

// درست - با use statement
use GuzzleHttp\Client;
$client = new Client();

مشکل رایج: use statement تکراری

اگر در یک فایل، دو use statement با نام مشابه داشته باشید، PHP خطا می‌دهد:

use App\User;
use Other\User; // خطای Conflict

راه‌حل: از alias استفاده کنید:

use App\User;
use Other\User as OtherUser;

مبانی namespace در مباحث شی‌گرایی PHP آمده است. اگر با PHP مدرن آشنایی ندارید، آموزش PHP از صفر نقطه‌ی شروع خوبی است.

مشکلات Composer و autoload

در پروژه‌های مدرن PHP، Composer ابزار اصلی مدیریت وابستگی‌ها است. Composer به‌طور خودکار فایل‌های کلاس‌ها و توابع را در زمان اجرا بارگذاری می‌کند. اگر این autoload نادرست باشد، خطای Call to undefined function ظاهر می‌شود.

مشکل رایج: اجرا نکردن composer dump-autoload

وقتی یک کلاس یا تابع جدید اضافه می‌کنید، باید autoload را به‌روز کنید:

composer dump-autoload

اگر این کار را نکنید، Composer نمی‌داند که کلاس یا تابع جدید کجاست و خطا می‌دهد.

مشکل رایج: نبود پکیج

اگر وابستگی‌ای در composer.json تعریف شده ولی نصب نشده:

composer install

این دستور، تمام پکیج‌های تعریف‌شده را نصب می‌کند و autoload را به‌روز می‌کند.

مشکل رایج: توابع در Composer

Composer به‌طور پیش‌فرض کلاس‌ها را autoload می‌کند، ولی توابع را نه. برای autoload توابع، باید در composer.json تعریف کنید:

{
    "autoload": {
        "files": [
            "src/helpers.php"
        ]
    }
}

سپس composer dump-autoload را اجرا کنید.

خطاهای خاص وردپرس و افزونه‌ها

در وردپرس، این خطا در چند سناریوی خاص شایع است:

سناریو اول: فراخوانی تابع افزونه‌ای که نصب نشده

اگر کد شما تابعی از یک افزونه را فراخوانی کند و آن افزونه نصب نباشد، خطا می‌گیرید. مثال:

// در قالب
$products = wc_get_products(); // اگر ووکامرس نصب نباشد، خطا می‌دهد

راه‌حل: بررسی وجود تابع قبل از فراخوانی:

if (function_exists("wc_get_products")) {
    $products = wc_get_products();
}

سناریو دوم: بارگذاری نادرست قالب یا افزونه

اگر فایل‌های قالب یا افزونه به‌درستی بارگذاری نشوند، توابع آن‌ها یافت نمی‌شوند. راه‌حل: بررسی functions.php و includeها. مبانی در قالب وردپرس چیست آمده است.

سناریو سوم: نسخه‌های مختلف PHP

افزونه‌های قدیمی وردپرس ممکن است از توابع PHP استفاده کنند که در نسخه‌های جدید حذف شده‌اند. راه‌حل: به‌روزرسانی افزونه یا جایگزینی آن. الگوهای عیب‌یابی در چگونه افزونه مشکل‌ساز را پیدا کنیم آمده است.

سناریو چهارم: افزونه‌های رهاشده

افزونه‌هایی که به‌روزرسانی نمی‌شوند، ممکن است با نسخه‌ی جدید PHP ناسازگار باشند. راه‌حل: جایگزینی با افزونه‌ی فعال. انتخاب افزونه‌ی مطمئن در دانلود افزونه‌ی مطمئن آمده است.

روش تشخیص اصولی در چهار گام

در تجربه‌ی من، تشخیص این خطا در چند دقیقه انجام می‌شود، اگر روش سیستماتیک داشته باشید:

گام اول: خواندن دقیق پیام خطا. پیام دقیقاً می‌گوید کدام تابع یافت نشد و در کدام فایل. این دو داده، جهت جستجو را تعیین می‌کند.

گام دوم: بررسی وجود تابع. از تابع function_exists() استفاده کنید:

var_dump(function_exists("my_custom_function"));
var_dump(function_exists("mysqli_connect"));
var_dump(function_exists("curl_init"));

این بررسی، مشخص می‌کند که تابع در PHP تعریف شده یا نه.

گام سوم: بررسی نسخه PHP و افزونه‌ها. با phpinfo() یا php -m، نسخه‌ی PHP و افزونه‌های فعال را ببینید. اگر تابع بخشی از افزونه‌ای است که نصب نشده، در این گام پیدا می‌شود.

گام چهارم: بررسی کد و autoload. اگر تابع سفارشی است، بررسی کنید که فایل تعریف‌کننده‌ی تابع در جای درست بارگذاری شده باشد. اگر از Composer استفاده می‌کنید، composer dump-autoload را اجرا کنید.

مبانی مدیریت خطا در مدیریت خطا در PHP آمده است.

راهبردهای رفع اصولی

بعد از تشخیص، نوبت به رفع می‌رسد. راهبردهای رفع، بر اساس نوع خطا متفاوت است:

راهبرد اول: نصب افزونه‌ی PHP

اگر تابع بخشی از افزونه‌ی PHP است، افزونه را نصب کنید. در هاست‌های اشتراکی، از پنل هاست. در سرورهای اختصاصی، با apt یا yum.

راهبرد دوم: مهاجرت به APIهای جدید

اگر تابع حذف شده، به API جدید مهاجرت کنید. مثال:

// قدیمی - mysql_query (حذف شده)
$result = mysql_query($sql);

// جدید - mysqli
$result = mysqli_query($connection, $sql);

// یا با PDO
$stmt = $pdo->query($sql);

راهبرد سوم: بررسی قبل از فراخوانی

قبل از فراخوانی تابع، وجود آن را بررسی کنید:

if (function_exists("wc_get_products")) {
    $products = wc_get_products();
} else {
    error_log("WooCommerce not active");
}

این رویکرد در افزونه‌های وردپرسی که وابستگی به افزونه‌های دیگر دارند، استاندارد است.

راهبرد چهارم: نصب polyfill

برای توابع جدید PHP که در نسخه‌های قدیمی نیستند، می‌توانید polyfill نصب کنید. Composer پکیج symfony/polyfill-php80 و مشابه‌ها را ارائه می‌دهد:

composer require symfony/polyfill-php80

این رویکرد، اجازه می‌دهد کد شما روی نسخه‌های قدیمی PHP هم کار کند.

راهبرد پنجم: مدیریت صریح خطا

در PHP 7+، می‌توانید این خطا را در try/catch مدیریت کنید:

try {
    $result = my_optional_function();
} catch (Error $e) {
    error_log("Function not found: " . $e->getMessage());
    $result = null;
}

نکته: در PHP 7+، خطای Call to undefined function از نوع Error است، نه Exception. بنابراین باید Error را catch کنید، نه Exception را.

مهاجرت نسخه PHP و این خطا

مهاجرت از نسخه‌ی قدیمی PHP (مثل 5.6 یا 7.4) به نسخه‌ی جدید (8.x) یکی از بزرگ‌ترین منابع این خطاست. در تجربه‌ی من، سه مرحله‌ی اصلی برای مهاجرت امن وجود دارد:

مرحله اول: ارزیابی

پروژه را با نسخه‌ی جدید PHP در staging اجرا کنید و تمام خطاها را لاگ کنید. ابزارهایی مثل phpstan یا rector می‌توانند به‌طور خودکار بخش بزرگی از مشکلات را تشخیص دهند.

مرحله دوم: رفع تدریجی

خطاها را یکی‌یکی رفع کنید، نه همه را یک‌جا. هر رفع را تست کنید و اطمینان از اینکه چیزی نمی‌شکند. مبانی کامل در خطای Deprecated در PHP آمده است.

مرحله سوم: تست در staging

بعد از رفع تمام خطاها، در staging با داده‌ی واقعی تست کنید. اگر خطای جدیدی ظاهر شد، به مرحله‌ی قبل برگردید.

نکته‌ی ظریف: در مهاجرت، همیشه یک شاخه‌ی جدید در git بسازید و مراحل را در آن انجام دهید. اگر مشکل جدی پیش آمد، می‌توانید به شاخه‌ی اصلی برگردید.

این خطا در محیط production

در محیط production، خطای Call to undefined function پیامدهای جدی‌تری دارد:

قطع کامل سرویس

از آن‌جا که این خطا از نوع Fatal است، اسکریپت متوقف می‌شود. اگر این خطا در مسیر بحرانی باشد (مثل پرداخت یا احراز هویت)، کاربر نمی‌تواند ادامه دهد.

نشت اطلاعات

پیام خطا، مسیر فایل را افشا می‌کند. اگر این پیام به کاربر نمایش داده شود، اطلاعات حساس (مسیر سرور، نام افزونه‌ها) افشا می‌شود. راه‌حل: در production، display_errors = Off و log_errors = On.

پایش و آلارم‌دهی

در production، این خطا باید به‌طور فوری به تیم فنی اطلاع داده شود. ابزارهایی مثل Sentry، Rollbar، یا حتی لاگ‌های ساختارمند ساده، این پایش را فراهم می‌کنند.

پیشگیری با staging

بیشتر این خطاها را می‌توان قبل از production با اجرای پروژه در staging کشف کرد. همیشه تغییرات را در staging تست کنید، نه روی سایت زنده. مبانی staging در مباحث توسعه‌ی وردپرس آمده است.

اشتباهات رایج در برخورد با این خطا

در طول سال‌ها، الگوهای تکراری از اشتباهات دیده‌ام که هر کدام می‌تواند پروژه را به چالش بکشد:

اشتباه اول: نصب افزونه بدون بررسی نیازمندی‌ها

بعضی توسعه‌دهنده‌ها افزونه‌ای نصب می‌کنند که نیازمندی‌هایی دارد که در سرور نیست. راه‌حل: قبل از نصب افزونه، نیازمندی‌های آن را بررسی کنید.

اشتباه دوم: نادیده گرفتن deprecation warnings

اگر deprecation warnings را در نسخه‌های قدیمی PHP نادیده بگیرید، در نسخه‌های جدید با Fatal Error مواجه می‌شوید. راه‌حل: همواره deprecation warnings را جدی بگیرید و در چرخه‌ی نگهداری رفع کنید.

اشتباه سوم: فراموش کردن composer dump-autoload

بعد از اضافه کردن کلاس یا تابع جدید با Composer، فراموش می‌کنید که autoload را به‌روز کنید. راه‌حل: این دستور را به فرآیند build اضافه کنید.

اشتباه چهارم: حذف فایل بدون بررسی وابستگی‌ها

فایلی که تابعی را تعریف می‌کند حذف می‌شود ولی جای دیگری هنوز به آن تابع وابسته است. راه‌حل: قبل از حذف فایل، تمام مراجع را جستجو کنید.

اشتباه پنجم: استفاده از تابع وردپرسی قبل از بارگذاری وردپرس

در پروژه‌های وردپرسی، اگر قبل از بارگذاری وردپرس، تابعی از وردپرس فراخوانی کنید، خطا می‌گیرید. راه‌حل: بارگذاری وردپرس با require_once("wp-load.php") قبل از فراخوانی توابع.

اشتباه ششم: نبود تست در staging

بدون تست در staging، خطاها به production می‌رسند. راه‌حل: همیشه تغییرات را در staging تست کنید.

اشتباه هفتم: نادیده گرفتن این خطا در لاگ

اگر این خطا در لاگ نادیده گرفته شود، ممکن است هفته‌ها ادامه یابد بدون اینکه کسی متوجه شود. راه‌حل: پایش مداوم لاگ‌ها.

خطای Call to undefined function، سیگنالی است از تغییر. تغییر نسخه‌ی PHP، تغییر افزونه‌ها، تغییر محیط. اگر این سیگنال را جدی بگیرید، پروژه‌ی شما با هر تغییر، قوی‌تر می‌شود. اگر نادیده بگیرید، هر تغییر به یک بحران تبدیل می‌شود.

پرسش‌های پرتکرار درباره خطای Call to undefined function

این پرسش‌ها از دل تجربه‌ی عملی و جلسات مشاوره جمع‌آوری شده‌اند. پاسخ هر کدام بر اساس سناریوهای واقعی است.

تفاوت Call to undefined function و Call to a member function چیست؟

اولی وقتی است که یک تابع مستقل (function) یافت نمی‌شود. دومی وقتی است که یک متد (member function) روی یک شیء یافت نمی‌شود. مثال اولی: undefined_function(). مثال دومی: $obj->undefinedMethod(). تفاوت مهم است چون راه‌حل هم متفاوت است.

چرا این خطا در وردپرس شایع است؟

چون وردپرس اکوسیستم گسترده‌ای از افزونه‌ها و قالب‌ها دارد که هر کدام می‌توانند تابعی تعریف کنند. اگر افزونه‌ای حذف شود یا نصب نشود، توابع آن یافت نمی‌شوند. همچنین نسخه‌های مختلف PHP و تغییرات APIهای وردپرس، می‌توانند این خطا را ایجاد کنند.

آیا می‌توانم از try/catch برای این خطا استفاده کنم؟

بله، در PHP 7+ این امکان وجود دارد. مثال:

try {
    $result = my_optional_function();
} catch (Error $e) {
    error_log("Function error: " . $e->getMessage());
}

نکته: در PHP 7+، خطا از نوع Error است، نه Exception. بنابراین باید Error را catch کنید.

چگونه بفهمم که یک تابع در PHP وجود دارد؟

با تابع function_exists():

if (function_exists("mysqli_connect")) {
    // تابع وجود دارد
}

این رویکرد، در کدهای سازگار با چند نسخه‌ی PHP توصیه می‌شود.

چرا در PHP 8، خطای Fatal Error به Error تبدیل شده؟

در PHP 7، مفهوم Error معرفی شد که یک استثنای قابل مدیریت است. در PHP 8، این مفهوم گسترش یافت. مزیت: می‌توانید خطاهای Fatal را در try/catch مدیریت کنید. این تغییر، انعطاف بیشتری در مدیریت خطا می‌دهد.

چگونه از این خطا در افزونه‌های وردپرسی پیشگیری کنم؟

سه رویکرد: اول، قبل از فراخوانی تابع افزونه‌ی دیگر، با function_exists یا class_exists بررسی کنید. دوم، در plugins_loaded hook کد را اجرا کنید که افزونه‌های دیگر بارگذاری شده باشند. سوم، در صورت وابستگی، افزونه را به‌عنوان نیازمندی اعلام کنید.

آیا polyfill می‌تواند همه‌ی مشکلات را حل کند؟

polyfill می‌تواند توابع ساده را فراهم کند، ولی برای توابع پیچیده‌تر (مثل APIهای جدید دیتابیس) کارایی ندارد. polyfill بیشتر برای توابع ساده مثل str_contains، array_key_first، و مشابه‌ها مناسب است.

چرا این خطا در محیط development ظاهر نمی‌شود ولی در production بله؟

چون تنظیمات PHP در دو محیط می‌توانند متفاوت باشند. در development، ممکن است افزونه‌ای نصب باشد که در production نیست. راه‌حل: محیط staging با تنظیمات مشابه production.

چگونه در PHP 8، خطاهای Error را مدیریت کنم؟

با try/catch که Error را می‌گیرد:

try {
    // کد
} catch (Error $e) {
    error_log($e->getMessage());
} catch (Exception $e) {
    error_log($e->getMessage());
}

نکته: Error و Exception دو سلسله‌مراتب جداگانه هستند. برای پوشش کامل، هر دو را catch کنید.

آیا نصب افزونه‌های اضافی، روی performance اثر دارد؟

بله. هر افزونه‌ی نصب‌شده، مصرف حافظه و CPU را افزایش می‌دهد. بنابراین توصیه می‌شود فقط افزونه‌های مورد نیاز نصب شوند. مبانی در مباحث مربوط به سرعت PHP آمده است.

چگونه در CLI، این خطا را تشخیص دهم؟

در CLI، پیام خطا در stderr نمایش داده می‌شود. اگر سایت شما در وب کار می‌کند ولی در CLI خطا می‌دهد، احتمالاً فایل‌های autoload یا تنظیمات PHP در CLI متفاوت است. راه‌حل: بررسی php.ini در CLI و مقایسه با وب.

تفاوت Error و Exception در PHP چیست؟

Exception در PHP برای خطاهای قابل پیش‌بینی طراحی شده است که برنامه‌نویس خودش مطرح می‌کند. Error برای خطاهای داخلی زبان طراحی شده است مثل Call to undefined function. از نظر فنی، هر دو از یک interface به‌نام Throwable ارث می‌برند.

چرا این خطا در PHP 5 ظاهر نمی‌شد ولی در PHP 7 بله؟

در PHP 5، این خطا از نوع Fatal Error مستقیم بود که اجرا را متوقف می‌کرد ولی قابل catch نبود. در PHP 7، به Error تبدیل شد که قابل مدیریت است. اگر کد شما در PHP 5 کار می‌کرد، احتمالاً در PHP 7 هم کار می‌کند، ولی اگر خطایی رخ دهد، نحوه‌ی برخورد با آن متفاوت است.

آیا می‌توانم از eval برای تعریف پویای توابع استفاده کنم؟

بله، ولی توصیه نمی‌شود. eval یک نقص امنیتی جدی است و برای تعریف توابع، راه‌حل‌های بهتری وجود دارد (مثل autoload). فقط در سناریوهای خاص و با اعتبارسنجی دقیق استفاده کنید.

چگونه در Composer، autoload توابع را تنظیم کنم؟

در فایل composer.json:

{
    "autoload": {
        "files": [
            "src/helpers.php",
            "src/utils.php"
        ]
    }
}

سپس composer dump-autoload را اجرا کنید.

آیا خطای Call to undefined function روی سئو تأثیر دارد؟

اگر این خطا باعث قطع کامل سرویس شود، بله. اگر سایت با خطای Fatal باز نشود، خزنده‌ی گوگل نمی‌تواند محتوا را ایندکس کند. راه‌حل: تشخیص و رفع سریع. مبانی سئو در سئو چیست آمده است.

چگونه در PHP، خطاهای Error را لاگ کنم؟

با نصب یک error handler سفارشی:

set_error_handler(function ($severity, $message, $file, $line) {
    throw new ErrorException($message, 0, $severity, $file, $line);
});

این رویکرد، خطاها را به استثنا تبدیل می‌کند که در try/catch قابل مدیریت هستند. الگوهای کامل در مدیریت خطا در PHP آمده است.

چرا بعد از آپدیت وردپرس، این خطا ظاهر می‌شود؟

چون آپدیت وردپرس می‌تواند APIها را تغییر دهد. اگر افزونه یا قالب شما از API قدیمی استفاده می‌کند که حذف شده، خطا ظاهر می‌شود. راه‌حل: به‌روزرسانی افزونه‌ها و قالب‌ها، یا در صورت لزوم، مهاجرت به API جدید.

آیا در PHP، تابعی به‌نام my_undefined_function وجود دارد؟

خیر. این فقط یک نام فرضی است برای مثال. در PHP، توابع داخلی مشخص هستند و توابع سفارشی توسط برنامه‌نویس تعریف می‌شوند.

چگونه از این خطا در پروژه‌های چند-نسخه‌ای PHP جلوگیری کنم؟

سه رویکرد: اول، استفاده از polyfill برای توابع جدید. دوم، بررسی وجود توابع با function_exists قبل از فراخوانی. سوم، استفاده از CI که پروژه را روی چند نسخه‌ی PHP تست می‌کند.

آنچه از سال‌ها کار با این خطا در PHP آموختم

اگر بخواهم چکیده‌ی این سال‌ها را در چند جمله بگویم، سه اصل عملی دارم:

یک: این خطا، سیگنالی از تغییر است. در بیشتر موارد، این خطا بعد از یک تغییر ظاهر می‌شود: نسخه‌ی PHP، افزونه‌ای که نصب یا حذف شده، مهاجرت سرور. قبل از اینکه کد را سرزنش کنید، تغییرات محیط را بررسی کنید.

دو: بررسی قبل از فراخوانی، عادت حرفه‌ای است. در کدهایی که وابستگی به افزونه‌های دیگر دارند، همیشه با function_exists یا class_exists بررسی کنید. این رویکرد، کد شما را مقاوم‌تر می‌کند.

سه: CI روی چند نسخه‌ی PHP، سرمایه‌گذاری بلندمدت است. اگر پروژه‌ی شما روی چند نسخه‌ی PHP اجرا می‌شود، در CI هر نسخه را تست کنید. این کار، بخش بزرگی از این خطاها را قبل از production کشف می‌کند.

در کنار این سه اصل، یک هشدار عملی هم دارم: خطای Call to undefined function در نگاه اول یک مشکل فنی ساده به‌نظر می‌رسد، ولی وقتی در چارچوب کلی نگهداری پروژه دیده شود، تبدیل به یک سیگنال می‌شود. این سیگنال می‌گوید که پروژه‌ی شما با تغییرات محیط، ناسازگار است. اگر این سیگنال را جدی بگیرید و کد را بر اساس آن بهبود دهید، پروژه‌ی شما در ماه‌های بعد، با هر تغییر محیط، پایدارتر خواهد بود.

هدف این مقاله، تمام‌کردن همه‌ی سناریوهای ممکن نبود. هدف، دادن یک چارچوب ذهنی برای تشخیص، پیشگیری و رفع این خطا بود. وقتی این چارچوب را درونی کنید، برخورد با خطای Call to undefined function از یک واکنش اضطراری به یک فرآیند منظم تبدیل می‌شود.

اگر این خطا در پروژه‌ی شما به شکلی ظاهر شده که با الگوهای این مقاله حل نشده، برای من جالب است بدانم کدام سناریو بود. تجربه‌ی خودتان را در دیدگاه‌ها بنویسید؛ به‌ویژه اگر راه‌حلی پیدا کرده‌اید که هنوز در این مقاله نیست. 🔧