خروجی بافر یا همان Output Buffering در php یکی از قابلیت های مهم برای کنترل خروجی اسکریپت php است . کنترل خروجی بر اساس زمان ارسال خروجی به مرورگر , ترتیب خروجی ها و غیره .. . انجام می شود .
به طور پیش فرض , تمام داده های مشخص شده در در دستورات چاپی یا محتویات HTML در اسکریپت PHP به طور تکه تکه به مرورگر ارسال می شود .
اما با استفاده از Output Buffering در php این داده ها در یک متغییر در حافظه بافر ذخیره خواهند شد و در نهایت به صورت یکجا یا همان یک تکه به مرورگر ارسال می شوند.
این قابلیت باعث جلوگیری از خطاهایی مثل header already sent در هنگام استفاده از توابعی مثل ()session_start که در مقاله آموزش کار با SESSION ها در php توضیح دادم می شود
بافر یک قسمت کوچک از حافضه برای ذخیره سازی موقت داده ها است .
برای کنترل خروجی های یک اسکریپت php توسط بافر , نیاز داریم که Output Buffering را با استفاده از هرکدام از روش های زیر فعال کنیم .
سه دستور پیکربندی زیر برای کنترل خروجی بافر استفاده می شوند
Output_buffering
– به صورت پیش فرض ۰
است . نیاز داریم که با مقدار ON قابلیت Output Buffering را برای تمام اسکریپت های php فعال کنیمOutput_handler
– مقدار پیش فرض , NULL
است .نیاز داریم که یک تابع از پیش ساخته مرجع برای ارسال خروجی به آن تابع مشخص کنیمImplicit_flush
– قرار دادن مقدار ON
برای این دستور , باعث خواهد شد که اسکریپت php مقدار خروجی را به ازای هر دستور چاپی در php یکبار flush یا ارسال کند .هر دو دستور اول در هرکدام از فایل های php.ini , .htacces , httpd.conf یا user.ini می تواند ست شود . و دستور پیکربندی آخر لیست بالا می تواند به هر طریق حتی با تابع ()ini_set
ست شود .
با ست کردن تنظیمات بالا , نتیجه بر روی تمام اسکریپت های php که بر روی سرور اجرا می شوند , اثر خواهد گذاشت . اما , فعال کردن Output Buffering در php بر روی یک فایل یا پروژه خاص بهتر از آن است که بخواهیم به صورت سراسری تنظیمات را اعمال کنیم .
بنابراین , php شامل توابعی برای کنترل Output Buffering است .این توابع با توضیحات کوتاه در زیر لیست شده اند .
()Ob_start
– این تابع برای هر دیتای ذخیره شده یک بافر می سازد . این دیتا ها در صورت استفاده از دستور های print یا echo یا هر دستور چاپی به اسکریپت php پاس داده خواهند شد.()ob_flussh و ()ob_end_flush
این توابع برای ارسال خروجی بافر برای نمایش در مروگر استفاده می شوند . تفاوت این توابع اینجاست که , ()ob_flush
بعد از ارسال بافر , مقدار بافر ذخیره شده را پاک نمی کند . ولی با یکبار اجرای ()ob_end_flush , اگر نیاز داشتیم باید دوباره یک بافر جدید بسازیم .()ob_clean
و ()ob_end_clean
این توابع برای پاک کردن داده های ذخیره شده در بافر استفاده می شوند .با استفاده از توابع بالا قصد داریم یک مثال را با هم ببینیم.
<?php ob_start(); print "PHP Output Buffering: level-1<br/>"; ob_end_flush(); ob_start(); print "PHP Output Buffering: level-2<br/>"; ob_flush(); print "Store into recently created buffer on level-2<br/>"; ob_end_flush(); ?>
در اسکریپت php بالا , در اولین خط با استفاده از تابع ()ob_start
یک بافر ساختیم . و بعد , داده مشخص شده در تابع print
در بافر ذخیره شد . پس از آن , تابع ()ob_end_flush
را به ترتیب برای ارسال و پاکسازی داده های بافر اجرا کردیم
بعد از آن , دوباره تابع ()ob_start
را برای ساخت یک بافر با محتوای داده های دستور print
ساختیم . اما این دفعه به جای تابع ()ob_end_flush
, تابع ()ob_flush
را استفاده کردیم . بنابراین فقط مقدار بافر را برای نمایش ارسال کردیم ولی آن را از بافر حذف نکردیم . بنابراین , سومین دستور print داده ذخیره شده در بافر قبلی را نیز ذخیره می کند.
به جز توابع اولیه و پایه بالا , php چندین تابع دیگر برای این extension را نیز پشتیبانی می کند . این توابع برای پیاده سازی قابلیت های زیر کاربرد دارد .
حالا اجازه بدید دسته بندی های بالا را به ترتیب بررسی کنیم
با استفاده از تابع Output Buffering در php , می توانیم اطلاعاتی مثل محتوای بافر , طول داده بافر شده و غیره .. را بدست آوریم.
()ob_get_contents
– این تابع محتوای خروجی بافر را برگشت می دهد()ob_get_length
– این تابع طول داده ذخیره شده در بافر را return می کند.()ob_get_level
– برای دریافت سطح یا همان level خروجی بافر به کار می رود. وقتی تعداد بافرهای ما زیاد می شود این بافرها به سطح بندی می شوند که با این level ها می توانیم به راحتی به آنها دسترسی پیدا کنیم.()ob_get_status
– برای دریافت آرایه از وضعیت بافر های سطح بالا یا تمام بافر ها با هر سطح استفاده می شود.()ob_get_flush
– این تابع کار هر دو تابع ()ob_get_contents
و ()ob_end_flush
را یکجا انجام میدهد !()ob_get_clean
– مشابه مورد بالا تاثیر هر دو تابع ()ob_get_contents
و ()ob_end_flush
همزمان نشان می دهد .می توانیم از مثال قبلی برای نحوه ارسال بافر ها به stack یا همان پشته استفاده کنیم .
<?php ob_start(); print "PHP Output Buffering: level-1<br/>"; ob_start(); print "PHP Output Buffering: level-2<br/>"; ob_end_flush(); ?>
stack یکی از سه بخش تخصص یافته به یک برنامه در حافظه RAM است .ساختمان داده های stack به صورت LIFO عمل می کند.(Last in First Out)
این نوع تکنیک به این معناست که آخرین دیتای ورودی اول از همه خارج می شود .(روش LIFO و FIFO در حسابداری موجودی کالا نیز استفاده می شود.)
حتما بخوانید تفاوت بین آرایه ها در php
اگر یک بافر را با فراخوانی تابع ()ob_start
بسازیم , پس از آن هر بافر ساخته شده به حافظه stack در بالای بافر قبلی قرار می گیرد . برای مثال :
در php , خروجی دیتای بافر شده با مشخص کردن مقدار ob_gzhandler
به عنوان آرگومان تابع ()ob_start
فشرده سازی خواهد شد . ()ob_gzhandler
یک تابع از پیش ساخته (in-built) در php است که به عنوان تابع بازگشتی (callback) استفاده کردیم. با کمک این تابع بازگشتی , php داده فشرده شده را به مرورگر ارسال خواهد کرد.
طبیعتا کمی زمان برای فشرده کردن داده خروجی صرف خواهد شد , این زمان توسط مروگر برای دانلود دیتای فشرده شده جبران خواهد شد .
دو تابع برای کنترل Output Buffering در php هنگام کار با URL Rewritng وجود دارد که به صورت زیر است .
()output_add_rewrite_var
– اسم و مقدار را به صورت جفت در آرگومان می پذیرد .این اسم و مقادیر ها به صورت query string در یک url اضافه خواهند شد و سپس یک فیلد خالی برای این جفت ها افزوده می شود .()output_reset_rewrite_varts
– این تابع تمام مقادیر URL Rewriting را پاک می کند .Php به طور خودکار قادر است عملیات ارسال داده های خروجی بافر را تا زمان رسیدن به پایان خط php انجام دهد حتی اگر هیچ تابع output bufferingی مشخص نشده باشد !
با استفاده از Output Buffering در php , می توانید جلوی خطاهایی که مربوط به ارسال داده قبل از اجرای کدهای session یا ()setcookie
می شود , را بگیرد.
بافرها در PHP می توانند بصورت تو در تو (Nested) باشند. بنابراین زمانی که یکی از بافرها فعال است, یک ()ob_start
دیگر یک بافر جدید را فعال می کند.
بنابراین هر دو تابع ()ob_end_flush
و ()ob_flush
در واقع هیچ بافری را به خروجی (output) ارسال نمی کنند, اما به بافر والد (parent) بله. و همچنین فقط زمانی هیچ بافر والدی نداریم که محتویات به مرورگر ارسال شده باشد.
بنابراین بسیار مهم است که عملیات بافر را غیرفعال کنیم حتی اگر یک استثنا (exception) رخ دهد.
ob_start(); try { $foo->render(); } finally { //finally exists since PHP 5.5 ob_end_clean(); // or ob_end_flush() }
مزایای استفاده از Output Buffering در php این است که