xpcall ومعالجات الرسائل
استخدم xpcall مع معالج مخصص للحصول على تتبعات تفصيلية للأخطاء
xpcall ومعالجات الرسائل درس مجاني في Lua Academy على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Lua Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Lua Academy 4 دروس في المجموع.
صيغة xpcall
يستدعي xpcall(f, handler, ...) الدالة f بالوسائط ... في وضع محمي، ويستدعي عند حدوث خطأ handler(errorObject). تصبح قيمة الإرجاع من المعالج قيمة الإرجاع الثانية لـ xpcall. بخلاف pcall، يشغّل xpcall المعالج بينما يكون المكدس سليمًا.
local function handler(err)
return "HANDLED: " .. tostring(err)
end
local ok, msg = xpcall(
function() error("something bad") end,
handler
)
print(ok) -- false
print(msg) -- HANDLED: ...: something badاستخدام debug.traceback معالجًا
أكثر معالجات xpcall شيوعًا هو debug.traceback. مرّره مباشرةً بوصفه المعالج — فهو ينسّق الخطأ مع تتبّع كامل لمكدس الاستدعاءات، وهو أمر بالغ الأهمية لتصحيح أخطاء الإنتاج.
local function level3() error("deep error") end
local function level2() level3() end
local function level1() level2() end
local ok, err = xpcall(level1, debug.traceback)
if not ok then
-- err contains the full stack trace
print(err)
endمعالج مخصّص مع السياق
يمكن لمعالج مخصّص إضافة سياق، مثل الطابع الزمني، أو تسجيل الخطأ في ملف، أو إشعار أنظمة المراقبة، ثم إعادة الخطأ المنسّق. هذا هو النمط القياسي لمعالجة أخطاء الإنتاج في تطبيقات Lua.
local function errorHandler(err)
local trace = debug.traceback(err, 2)
local ts = os.date("%H:%M:%S")
local report = string.format("[%s] ERROR\n%s", ts, trace)
-- Could log to file here
io.stderr:write(report .. "\n")
return report
end
local ok, msg = xpcall(
function()
local t = nil
return t.field -- error!
end,
errorHandler
)
print("ok:", ok)لا يمكن للمعالج إصدار خطأ
إذا أصدر معالج الرسالة نفسه خطأً، تعيد Lua مؤشر خطأ من دون استدعاء المعالج مرة أخرى. اكتب المعالجات دائمًا بحيث تكون شديدة المتانة — من دون عمليات إدخال وإخراج قد تفشل، ومن دون فهرسة لقيم nil.
local function safeHandler(err)
-- Keep handler simple and safe
local ok, trace = pcall(debug.traceback, err, 2)
if ok then return trace
else return tostring(err) .. " (traceback failed)"
end
end
local ok, msg = xpcall(
function() error({complex="error table"}) end,
safeHandler
)
print(ok, type(msg))استخدام xpcall للحلقة الرئيسية
في البرامج طويلة التشغيل (مثل الخوادم وحلقات الألعاب)، غلّف الدالة الرئيسية في xpcall لالتقاط أي أخطاء غير معالجة وتسجيلها من دون تعطل البرنامج. ويمكن للحلقة الرئيسية بعد ذلك أن تقرر ما إذا كانت ستُعاد أو ستخرج.
local function mainApp()
-- simulate work
for i = 1, 3 do
print("Tick", i)
if i == 2 then error("transient error") end
end
end
local function handler(e)
return debug.traceback("App error: "..tostring(e), 2)
end
local ok, err = xpcall(mainApp, handler)
if not ok then
print("Application crashed:\n" .. err)
endالإبلاغ المنظّم عن الأخطاء
اجمع بين xpcall وكائنات الأخطاء المنظّمة ومعالج غني لإنتاج تقارير أخطاء مفصّلة وقابلة للتنفيذ لأغراض تصحيح الأخطاء أو لوحات المراقبة.
local function handler(err)
local info = {
error = tostring(err),
time = os.date("!%Y-%m-%dT%H:%M:%SZ"),
trace = debug.traceback(nil, 2),
}
return info
end
local ok, report = xpcall(
function() error({code=500, msg="internal error"}) end,
handler
)
if not ok then
print("Time:", report.time)
print("Error:", report.error)
-- print("Trace:", report.trace)
endاستخدام xpcall مع Coroutines
يعمل pcall بصورة طبيعية داخل coroutine. وللحصول على تتبعات الأخطاء من الأخطاء الواقعة داخل coroutines، غلّف جسم coroutine في xpcall. يعمل المعالج ضمن سياق مكدس coroutine.
local function co_body()
error("error inside coroutine")
end
local co = coroutine.create(function()
local ok, err = xpcall(co_body, debug.traceback)
if not ok then
print("Caught in coroutine:", err:match("([^\n]+)"))
end
end)
coroutine.resume(co)إثراء كائن الخطأ
يمكن للمعالج تحويل خطأ نصي عادي إلى كائن غني، أو إثراء كائن غني بمزيد من المعلومات. يتيح ذلك للشيفرة منخفضة المستوى إصدار أخطاء بسيطة، بينما يضيف المعالج السياق (معرّف الطلب، وجلسة المستخدم، ومعلومات البيئة).
local requestID = "req-123"
local function handler(err)
if type(err) == "string" then
return {message=err, requestID=requestID, level="error"}
end
err.requestID = requestID
return err
end
local ok, result = xpcall(
function() error("database timeout") end,
handler
)
if not ok then
print(result.message, result.requestID)
-- database timeout req-123
endمقارنة pcall وxpcall
استخدم pcall عندما: تحتاج إلى قيمة الخطأ فقط، أو يكون الخطأ متوقعًا وتتم معالجته داخل السطر، أو تكون البساطة مهمة. استخدم xpcall عندما: تحتاج إلى تتبعات المكدس، أو تكون عند حدّ علوي، أو تريد إضافة سياق إلى جميع الأخطاء.
-- pcall: simple, no overhead
local ok, err = pcall(function()
return 1/0 -- no error in Lua! returns inf
end)
print(ok, err) -- true inf
-- xpcall: adds traceback
local ok2, err2 = xpcall(
function() error("real error") end,
debug.traceback
)
print(ok2) -- false
print(err2:sub(1,40)) -- first line of tracebackقيمة إرجاع المعالج
أيًا كانت القيمة التي يعيدها المعالج، تصبح القيمة الثانية التي يعيدها xpcall. إذا أعاد المعالج nil، فستكون قيمة الإرجاع الثانية لـ xpcall هي nil. ويُعد المعالج الذي يعيد كائن الخطأ الأصلي مع معلومات إضافية النهج الأكثر مرونة.
local function enrichedHandler(err)
return {
original = err,
traceback = debug.traceback(nil, 2),
timestamp = os.time(),
}
end
local ok, report = xpcall(
function() error("oops") end,
enrichedHandler
)
if not ok then
print(type(report)) -- table
print(report.original) -- ...: oops
print(report.timestamp > 0) -- true
endتحقق سريع
ما الميزة الأساسية التي يوفرها xpcall مقارنةً بـ pcall؟
مراجعة: xpcall
الملخص:
xpcall(f, handler, ...)— يعمل المعالج بينما يكون المكدس سليمًا- استخدم
debug.tracebackمعالجًا للحصول على تتبعات كاملة - يجب ألا يصدر المعالج خطأً — أبقه بسيطًا
- أثرِ الأخطاء بالسياق داخل المعالج
- غلّف الحلقات الرئيسية أو معالجات الخادم في xpcall
- تصبح قيمة إرجاع المعالج قيمة الإرجاع الثانية لـ xpcall
الأسئلة الشائعة
هل درس «xpcall ومعالجات الرسائل» مجاني؟
نعم — نص درس «xpcall ومعالجات الرسائل» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Lua Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Lua Academy 4 دروس في المجموع.
ماذا ستتعلم في «xpcall ومعالجات الرسائل»؟
استخدم xpcall مع معالج مخصص للحصول على تتبعات تفصيلية للأخطاء تتمرن على Lua Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Lua Academy؟
لا تُشترط خبرة سابقة. Lua Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.
كم من الوقت يستغرق درس «xpcall ومعالجات الرسائل»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Lua Academy هذا؟
نعم. كل درس في Lua Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- الدالة error()
- الاستدعاءات المحمية باستخدام pcall
- xpcall ومعالجات الرسائل
- كائنات الأخطاء المهيكلة