ویژگی تصویر

تابع xml_set_processing_instruction_handler() در PHP

  /  PHP   /  تابع xml_set_processing_instruction_handler() در PHP
بنر تبلیغاتی الف
آموزش PHP

تابع xml_set_processing_instruction_handler() یکی از توابع اکستنشن XML در PHP است که به شما اجازه می‌دهد هنگام پردازش فایل XML بر مبنای SAX (پارسِر Expat) به پردازش‌دستورات (processing instructions یا PIها) واکنش نشان دهید. این تابع برای پردازش جریان‌های XML سبک و واکنش فوری به PIها کاربرد دارد، به‌خصوص وقتی نیاز دارید بدون بارگذاری تمام سند در حافظه رفتار مشخصی انجام شود.

امضای تابع و پارامترها

نام پارامترنوعتوضیح
parserresourceآبجکت/منبع پارسر XML که با xml_parser_create() ساخته شده است.
handlercallableتابع یا callback که هنگام برخورد به PI فراخوانی می‌شود. امضا: handler($parser, $target, $data)

Callback سه آرگومان دریافت می‌کند: منبع پارسر، هدف PI (target) و محتوای PI (data). تابع مقدار برگشتی خاصی ندارد.

موقعیت استفاده و تفاوت با روش‌های دیگر

  • این تابع بخشی از مدل SAX (رویداد-محور) است. برخلاف DOM یا SimpleXML که تمام سند را در حافظه می‌سازند، SAX مناسب پردازش جریان‌ها و فایل‌های بزرگ است.
  • Processing Instructionها معمولاً برای اعلام stylesheetها، متادیتاهای سمتِ پردازش یا دستورات اختصاصی برنامه استفاده می‌شوند، مثل: .
  • اگر به‌دنبال دسترسی مستقیم به گره‌های PI پس از بارگذاری سند هستید، DOMDocument گزینه ساده‌تری است (DOMProcessingInstruction).

مثال ساده

$xml = '' .
       '' .
       'hello';

$parser = xml_parser_create();
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, false);

xml_set_processing_instruction_handler($parser, function($parser, $target, $data) {
    echo "Found PI: target={$target}, data={$data}n";
});

if (!xml_parse($parser, $xml, true)) {
    printf("XML error: %s at line %dn",
        xml_error_string(xml_get_error_code($parser)),
        xml_get_current_line_number($parser));
}

xml_parser_free($parser);

در این مثال یک رشته XML ساده تعریف شده و پارسر ایجاد می‌شود. گزینهٔ XML_OPTION_CASE_FOLDING خاموش شده تا نام‌تگ‌ها بدون تبدیل به حروف بزرگ پاس داده شوند. callback تعریف‌شده وقتی به PI می‌رسد نام هدف (مثل xml-stylesheet) و دادهٔ داخل PI را چاپ می‌کند. در انتها خطاها بررسی و پارسر آزاد می‌شود.

مثال پیشرفته — جمع‌آوری همه PIها

$xmlStream = "..."; // می‌تواند محتوای فایل یا استریم شبکه باشد

$parser = xml_parser_create();
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, false);

$collected = [];
xml_set_processing_instruction_handler($parser, function($parser, $target, $data) use (&$collected) {
    $collected[] = ['target' => $target, 'data' => $data, 'line' => xml_get_current_line_number($parser)];
});

// فرض کنید داده را در قطعات می‌خوانیم:
$pos = 0;
while ($pos = strlen($xmlStream))) {
        throw new Exception("XML parse error: " . xml_error_string(xml_get_error_code($parser)));
    }
}

xml_parser_free($parser);

// اکنون $collected شامل همه PIها است
print_r($collected);

این نمونه نشان می‌دهد چگونه با خواندن داده به‌صورت chunked می‌توان processing instructionها را جمع‌آوری کرد؛ هر PI همراه با شمارهٔ خط ذخیره می‌شود تا برای گزارش یا پردازش بعدی مفید باشد.

بهبودها و نکات فنی

  • برای نگهداری حالت در callback از closure با ارجاع (use (&$var)) یا از object-oriented approach استفاده کنید. پارسر خود مقدار state را نگه نمی‌دارد.
  • در محیط‌هایی که anonymous functions پشتیبانی نمی‌شود از نام تابع یا از array($object, ‘method’) استفاده کنید.
  • XML_OPTION_CASE_FOLDING را مطابق نیاز تنظیم کنید تا حساسیت حروف در نام‌ها کنترل شود.
  • به خاطر داشته باشید که PIها بخشی از محتوا نیستند و ترتیب نسبت به عناصر مهم است — اگر نیاز به وابستگی بین PI و عنصر خاصی دارید باید با نگهداری context در callback هماهنگ کنید.

خطاها، محدودیت‌ها و اشتباهات رایج

  • این روش تنها با پارسر Expat کار می‌کند (تابع‌های xml_* از ext/xml). اگر از SimpleXML یا DOM استفاده می‌کنید، باید از روش‌های دیگر برای گرفتن PI بهره ببرید.
  • callback باید سه پارامتر را بپذیرد؛ اگر امضا متفاوت باشد، خطا خواهید گرفت.
  • در صورتی که فایل بزرگ است، مدیریت حافظه و آزادسازی پارسر (xml_parser_free) مهم است.

نمونه جایگزین با DOM برای دسترسی پس از بارگذاری

$dom = new DOMDocument();
$dom->loadXML($xml);
foreach ($dom->childNodes as $node) {
    if ($node->nodeType === XML_PI_NODE) {
        echo "PI target: " . $node->target . ", data: " . $node->data . "n";
    }
}

اگر می‌خواهید گره‌های PI را بعد از بارگذاری سند بررسی کنید (نه بصورت event-driven)، DOMDocument یک روش ساده و خوانا ارائه می‌دهد؛ اما هزینهٔ حافظه بالاتری دارد.

کاربردهای عملی

  • خواندن برای بارگذاری XSLT مرتبط با سند.
  • دریافت متادیتای سفارشی که توسط سیستم‌های تولید کنندهٔ XML اضافه شده است.
  • به‌کارگیری در تبدیل‌گرهای جریان‌محور یا پردازش‌های زمان واقعی که باید بدون بارگذاری کامل سند تصمیم بگیرند.

جمع‌بندی

تابع xml_set_processing_instruction_handler() ابزار مناسب و قدرتمندی برای پردازش event-driven فایل‌های XML است که به شما اجازه می‌دهد به طور مستقیم به processing instructionها واکنش نشان دهید. برای فایل‌های بزرگ یا استریم‌ها، این روش بهینه‌تر از بارگذاری کامل سند است، اما در صورت نیاز به دسترسی ساختاری یا تغییر درخت XML، استفاده از DOM یا XMLReader پیشنهاد می‌شود. با رعایت نکات مربوط به مدیریت state، خطاگیری و آزادسازی منابع، می‌توانید به‌خوبی از این تابع در پروژه‌های واقعی بهره ببرید.

آیا این مطلب برای شما مفید بود ؟

خیر
بله
موضوعات شما در انجمن: