- ساخت استریم رپر سفارشی
همانطور که در قسمت های قبل گفته شد، به صورت پیشفرض چندین Stream Wrapper داخلی وجود دارد.
با این حال، PHP این امکان را فراهم کرده است که پروتکلهای سفارشی خود را به عنوان Stream Wrapper پیادهسازی کنیم تا توابع فایلسیستم روی منابع دلخواه ما عمل کنند.
به عبارتی میتوانیم یک Stream Wrapper سفارشی بسازیم و آن را با یک اسکیم (پروتکل) دلخواه (مثلاً myprot://) ثبت کنیم و سپس با توابع معمولی PHP مثل fopen() یا file_get_contents() به منابع سفارشی خود دسترسی داشته باشیم.
- مراحل ساخت Stream Wrapper سفارشی
ابتدا یک کلاس PHP تعریف میکنیم که متدهای لازم برای یک Stream Wrapper را پیادهسازی کند. این متدها شامل عملیات پایهای مانند باز کردن، خواندن، نوشتن و ... روی منبع سفارشی هستند و با نام های خاص و از پیش تعیین شده پیاده سازی می شوند (در بخش بعد لیست کامل متدها توضیح داده خواهد شد).
نام کلاس میتواند دلخواه باشد (مثلاً MyStreamWrapper) و این کلاس نمایندهی پروتکل سفارشی ما خواهد بود که متدهای ما در آن تعریف می شوند.
پس از تعریف کلاس، باید آن را به PHP معرفی (ثبت) کنیم.
برای این کار از تابع stream_wrapper_register استفاده میشود.
پارامتر اول نام پروتکل (اسکیم) دلخواه ما به صورت رشته (مثلاً "myprot") و پارامتر دوم نام کلاس پیادهکنندهی آن پروتکل است.
اگر ثبت با موفقیت انجام شود، از این پس هر زمان که PHP با آدرسی به شکل myprot://... مواجه شود، به جای دسترسی مستقیم به فایلسیستم، متدهای کلاس ما را فراخوانی میکند. در صورت عدم موفقیت در ثبت (مثلاً اگر نام پروتکل تکراری باشد) این تابع مقدار false برمیگرداند.
پس از ثبت پروتکل سفارشی، میتوانیم از آن دقیقاً مانند سایر پروتکلها استفاده کنیم.
برای مثال، میتوان با fopen("myprot://something", "r") یک منبع را باز کرد که منجر به اجرای متد stream_open (یکی از متدهای خاص و از پیشی تعیین شده) در کلاس ما میشود.
برای روشنتر شدن موضوع، یک مثال ساده در نظر بگیرید. فرض کنیم میخواهیم یک Stream Wrapper بنام var:// پیادهسازی کنیم که با آن بتوان دادهها را مستقیماً در یک متغیر PHP ذخیره و بازیابی کرد (نوعی استریم درونحافظهای).
کلاس ما مثلاً VariableStream نام دارد و دادهها را در یک متغیر سراسری با نام مشخص ذخیره میکند:
class VariableStream {
function stream_open($path, $mode, $options, &$opened_path) {
$url = parse_url($path);
$this->varname = $url["host"];
$this->position = 0;
if (strpos($mode, 'w') !== false || strpos($mode, 'x') !== false || strpos($mode, 'c') !== false) {
$GLOBALS[$this->varname] = '';
}
return true;
}
function stream_read($count) {
$data = substr($GLOBALS[$this->varname], $this->position, $count);
$this->position += strlen($data);
return $data;
}
function stream_write($data) {
$left = substr($GLOBALS[$this->varname], 0, $this->position);
$right = substr($GLOBALS[$this->varname], $this->position + strlen($data));
$GLOBALS[$this->varname] = $left . $data . $right;
$this->position += strlen($data);
return strlen($data);
}
stream_wrapper_register("var", "VariableStream") or die("Failed to register protocol");
$myvar = "";
$fp = fopen("var://myvar", "r+");
fwrite($fp, "Hello\n");
fwrite($fp, "World\n");
fclose($fp);
var_dump($myvar);نکته: برای خوانایی بهتر کد، پیشنهاد میشود آن را درون یک ادیتور باز کنید.
در مثال بالا، ابتدا پروتکل var:// به کلاس VariableStream نگاشت شده است.
سپس متغیری به نام $myvar تعریف شده و با fopen("var://myvar", "r+") یک استریم خواندن/نوشتن روی آن باز میکنیم. این عمل باعث فراخوانی stream_open در کلاس می شود.
با fwrite در واقع متد stream_write کلاس فراخوانی میشود و داده را در متغیر ذخیره میکند.
در پایان fclose($fp) استریم را میبندد (که منجر به stream_close در کلاس میشود، هرچند در این مثال ما این متد را پیادهسازی نکردهایم).
در نهایت خروجی به صورت زیر خواهد بود:
string(12) "Hello
World
"
همانطور که مشاهده میکنید، با استفاده از Stream Wrapper سفارشی، توانستیم عملیات فایلگونه (خواندن/نوشتن) را روی یک متغیر ساده انجام دهیم، گویی که یک فایل است.
در قسمت های بعد، تمامی متدهایی که میتوان در یک Stream Wrapper سفارشی پیادهسازی کرد را معرفی کرده و کاربرد هر کدام را توضیح میدهیم.
#PHP #PHP_streams
@AmirhDeveloper
.