ویژگی تصویر

تابع vfprintf() در PHP

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

vfprintf() یکی از توابع خانوادهٔ printf در PHP است که رشتهٔ قالب‌بندی‌شده را به یک stream (مثلاً فایل یا STDOUT) می‌نویسد. این تابع به‌جای دریافت پارامترهای جداگانه برای مقادیر، یک آرایه از آرگومان‌ها می‌گیرد و آن‌ها را مطابق قالب (format) جایگذاری می‌کند. در این مقاله به توضیح دقیق عملکرد، مثال‌های عملی، نکات امنیتی، مقایسه با توابع مشابه و بهترین شیوه‌ها می‌پردازیم.

تعریف و امضای تابع

امضای تابع به‌صورت زیر است:

int vfprintf ( resource $handle , string $format , array $args )

تابع تعداد بایت‌های نوشته‌شده را برمی‌گرداند یا در صورت خطا مقدار false.

چه زمانی از vfprintf استفاده کنیم؟

  • وقتی می‌خواهیم قالب‌بندی پیچیده را مستقیم به یک فایل یا stream بنویسیم.
  • وقتی آرگومان‌ها به‌صورت داینامیک در یک آرایه موجود هستند (مثلاً از JSON یا دیتابیس خوانده شده‌اند).
  • وقتی می‌خواهیم از ساختار C-style formatting استفاده کنیم اما با آرایه‌ای از مقادیر کار کنیم.

نمونه‌های عملی

<?php
$fp = fopen("log.txt", "a");
$format = "[%s] User %s (id=%d) performed %sn";
$args = [date("Y-m-d H:i:s"), "alice", 42, "login"];
$bytes = vfprintf($fp, $format, $args);
fclose($fp);
?>

در این مثال یک خط لاگ با قالب مشخص به فایل log.txt اضافه می‌شود. آرایه $args مقادیر را به ترتیب جایگزین می‌کند و تعداد بایت‌های نوشته‌شده در $bytes باز می‌گردد.

<?php
// نوشتن مستقیم به خروجی استاندارد
$stdout = fopen('php://stdout', 'w');
$format = "Progress: %03d/%03d (%.2f%%)n";
$args = [7, 100, 7/100*100];
vfprintf($stdout, $format, $args);
fclose($stdout);
?>

مثال بالا برای نمایش وضعیت پیشرفت مناسب است. توجه کنید که فرمت‌ها برای صفرپر کردن تعداد ارقام و تنظیم دقت اعشار استفاده شده‌اند.

نمونه‌هایی از مشخصه‌های فرمت (format specifiers)

مشخصهمعنی
%bنمایش عدد به صورت دودویی (binary)
%cکاراکتر از کد ASCII
%d / %iعدد صحیح ده‌دهی (signed integer)
%uعدد صحیح بدون علامت
%f / %Fعدد اعشاری با دقت مشخص
%e / %Eنمایش علمی (exponential)
%oعدد به صورت اکتال
%sرشته
%x / %Xهگزادسیمال (حروف کوچک/بزرگ)

علاوه بر مشخصه‌ها، می‌توان از پرچم‌ها مثل +, , 0, فاصله و عرض و دقت استفاده کرد: نمونه: %+08.2f.

نکات مهم و موارد قابل توجه

  • vfprintf آرایه‌ای از پارامترها را دریافت می‌کند؛ ترتیب عناصر آرایه باید دقیقاً با ترتیب مشخصه‌های قالب یکسان باشد.
  • اگر تعداد عناصر کمتر باشد، PHP پیغام هشدار صادر کرده و مقادیر پیش‌بینی نشده ممکن است تولید شوند.
  • استفاده مستقیم از ورودی کاربر در قالب (format string) خطرناک است—هرچند در PHP مثل C آسیب‌پذیری حافظه ایجاد نمی‌شود، ولی می‌تواند باعث افشای اطلاعات یا خطا شود. همیشه قالب را ثابت نگه دارید و ورودی را تنها در آرایه پارامترها قرار دهید.
  • locale می‌تواند رفتار نمایش اعشار (%f) را تحت تأثیر قرار دهد؛ اگر نیاز دارید فرمت آی‌دی‌آنتیک در تمام محیط‌ها باشد، locale را مدیریت کنید یا از توابع عددی دیگری استفاده کنید.

مقایسه با توابع مشابه

  • fprintf(): مشابه vfprintf اما پارامترها را به‌صورت جداگانه قبول می‌کند (variadic).
  • vsprintf() و vprintf(): مقادیر را از آرایه می‌گیرند؛ اما vsprintf رشتهٔ قالب‌بندی‌شده را برمی‌گرداند، در حالی که vprintf آن را به خروجی چاپ می‌کند. vfprintf ترکیبی از fprintf و vsprintf است (نوشتن به stream با آرایه).
  • به‌جای vfprintf می‌توان از fwrite($handle, vsprintf($format, $args)) استفاده کرد؛ اما vfprintf خواناتر است و برای برخی پیاده‌سازی‌ها می‌تواند کارایی بهتر یا مصرف حافظه کمتر داشته باشد.

نمونه پیشرفته — ارسال پارامترها به صورت داینامیک

<?php
$data = [
  ['time'=> '2025-01-01', 'user'=>'bob', 'action'=>'create'],
  ['time'=> '2025-01-02', 'user'=>'alice', 'action'=>'delete'],
];

$fp = fopen("events.log", "w");
$fmt = "[%s] %s -> %sn";
foreach ($data as $row) {
    // تبدیل آرایه‌ی انجمنی به آرایه‌ی عددی طبق ترتیب فرمت
    $args = [$row['time'], $row['user'], $row['action']];
    vfprintf($fp, $fmt, $args);
}
fclose($fp);
?>

در اینجا داده‌ها به صورت انجمنی (associative) هستند؛ قبل از استفاده از vfprintf باید آن‌ها را به آرایهٔ عددی با ترتیب مناسب تبدیل کنیم.

نکات عملکردی و بهینه‌سازی

  • برای نوشتن تعداد زیادی خط، باز و بسته کردن فایل درون حلقه پرهزینه است؛ بهتر است فایل را یک بار باز کرده و سپس چندین بار vfprintf فراخوانی کنید.
  • اگر قالب‌بندی بسیار سنگین است و می‌خواهید حافظه را مدیریت کنید، از streamها و vfprintf استفاده کنید تا نیاز به نگهداری رشتهٔ کامل در حافظه کاهش یابد.
  • در محیط‌هایی که I/O محدودیتی دارد، گروه‌بندی نوشته‌ها (buffering) و سپس flush می‌تواند کارایی را بهبود دهد.

خطاها و دیباگ

  • اگر $handle معتبر نباشد، تابع false برمی‌گرداند و هشدار تولید می‌شود.
  • استفاده از فرمت‌هایی که با نوع داده‌ها سازگار نیستند می‌تواند نتایج نامطلوب یا هشدار تولید کند؛ بهتر است قبل از فراخوانی نوع‌ها را بررسی کنید.

جمع‌بندی

vfprintf تابعی ساده اما قدرتمند برای نوشتن قالب‌بندی‌شده به streamها است که مخصوصاً وقتی مقادیر در قالب آرایه در دسترس باشند کاربردی و خوانا است. با رعایت نکات امنیتی درباره فرمت و مدیریت صحیح فایل/stream، می‌توان از آن در لاگ‌گذاری، تولید گزارش و ایجاد خروجی‌های ساخت‌یافته استفاده کرد.

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

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