Standart PHP Library یا به اختصار SPL یک اکستنش در زبان پیاچپی حاوی مجموعهای از اینترفیسها و کلاسها است که در هستهٔ زبان برنامهنویسی پیاچپی از نسخهٔ 5.0 به بعد گنجانده شده تا به منظور حل مسائل رایج توسط توسعهدهندگان این زبان مورد استفاده قرار گیرد. به طور مثال، اسپیال حاوی یک سری کلاس تحت عنوان Iterator است که به منظور ایجاد یک حلقه به برای گشتزنی در حلقهها، آبجکتها و فایلهای اکسامال مورد استفاده قرار میگیرند. به طور کلی، از جمله مزایای استفاده از اسپیال میتوان به موارد زیر اشاره کرد:
- کدهای سادهتر
- کامپوننتهایی با قابلیت استفادهٔ مجدد در سایر بخشهای سورسکد
- پرفورمنس بهتر به دلیل نوشته شدن کدهای پشتپردهٔ اسپیال با زبان سی
- استفاده از مِموری کمتر
همچنین برای کسب اطلاعات بیشتر در این ارتباط، میتوانید به لینک SPL Introduction در سایت رسمی این زبان مراجعه نمایید و برای نمایش کلیهٔ کلاسهای اسپیال میتوانید فانکشن ()spl_classes
را داخل دستور ()var_dump
اجرا کنید و یا به منظور آگاهی از کلیهٔ متدهای موجود داخل کلاسی همچون CachingIterator
، میتوان دستور (get_class_methods(CachingIterator
را داخل ()var_dump
به کار گرفت.
اساساً به منظور درک سازوکار اسپیال، هیچ چیز بهتر از کدنویسی نیست و از همین روی، داخل پوشهٔ oop
پروژهای تحت عنوان standard-php-library
ساخته و در مسیر روت این دایرکتوری فایلی تحت عنوان index.php
ساخته و آن را به صورت زیر تکمیل میکنیم:
<?php
ini_set('display_errors', '1');
$obj = new stdClass;
$obj->name = "Behzad";
echo $obj->name;
همانطور که ملاحظه میشود، از روی کلاسی به نام stdClass
آبجکت ساختهایم تحت عنوان obj$
و لازم به یادآوری است که این کلاس به صورت اصطلاحاً Built-in در هستهٔ زبان پیاچپی تعبیه شده است و به عنوان یک کلاس خالی محسوب میگردد که حاوی هیچ گونه پراپرتی یا متدی نیست. در خط بعد یک پراپرتی به این کلاس افزودهایم تحت عنوان name
و مقدار آن را برابر با یک استرینگ قرار دادهایم و در نهایت هم آن را در محیط کامندلاین به صورت زیر چاپ کردهایم:
/var/www/oop/standard-php-library$ php index.php
Behzad
به عنوان مثالی دیگر، یک پراپرتی از جنس آرایه به آبجکت فوق به صورت زیر میافزاییم:
<?php
ini_set('display_errors', '1');
$obj = new stdClass;
// $obj->name = "Behzad";
// echo $obj->name;
$obj->colors = ['red', 'green', 'blue'];
foreach ($obj->colors as $color) {
echo $color . "\n";
}
در خط هفتم یک پراپرتی تحت عنوان colors
ساخته و مقدارش را برابر با آرایهای از رنگها قرار دادهایم به طوری که در خروجی داریم:
/var/www/oop/standard-php-library$ php index.php
red
green
blue
همانطور که میبینیم، با استفاده از یک حلقه مقادیر این آرایه را چاپ کردهایم (دستور "n\"
به منظور رفتن به یک خط جدید درج شده است.)
آشنایی با یک سری Iterator کاربردی در SPL
پیش از این گفتیم که لایبرری استاندارد پیاچپی (SPL) حاوی یک سری اینترفیس، کلاس و ... پرکاربرد است که در نهایت منجر به سهولت توسعهٔ نرمافزار میگردند که در همین راستا، در ادامه قصد داریم سه نمونه از این کلاسها را مورد بررسی قرار دهیم که عبارتند از LimitIterator
،ArrayIterator
و CachingIterator
. برای همین منظور، فایل index.php
را به صورت زیر آپدیت میکنیم:
<?php
ini_set('display_errors', '1');
$numbers = [1, 2, 3];
$iterator = new ArrayIterator($numbers);
echo $iterator->current();
همانطور که ملاحظه میشود، آرایهای ساختهایم متشکل از سه اِلِمان تحت عنوان numbers$
سپس در خط بعد آبجکتی از روی کلاس ArrayIterator ساختهایم به نام iterator$
و به عنوان آرگومان ورودی این کلاس نیز آرایهٔ فوق را پاس دادهایم و در نهایت با استفاده از دستور echo
و فراخوانی متد ()current
روی آبجکت iterator$
مقدار زیر را در خروجی چاپ کردهایم:
1
در واقع، متد فوق اولین اِلِمان آرایه را هدف قرار میدهد. یکی دیگر از متدهای این کلاس ()count
است که در صورت فراخوانی آن به شکل زیر تعداد کل اِلِمانهای آرایهای که به این کلاس پاس داده شده است ریترن میگردد:
<?php
ini_set('display_errors', '1');
$numbers = [1, 2, 3];
$iterator = new ArrayIterator($numbers);
echo $iterator->count();
در مثال فوق خروجی برابر با عدد ۳ خواهد بود. در ادامه قصد داریم تا با کلاس LimitIterator آشنا شویم که این امکان را در اختیارمان میگذارد تا روی بخشی از یک آرایه حلقه را اجرا کنیم به طوری که برای مثال داریم:
<?php
ini_set('display_errors', '1');
$numbers = [1, 2, 3];
$iterator = new ArrayIterator($numbers);
// echo $iterator->count();
$limit = new LimitIterator($iterator, 0, 2);
foreach($limit as $item) {
echo $item . "\n";
}
همانطور که میبینیم، آبجکتی از روی این کلاس ساختهایم به نام limit$
و به عنوان آرگومان اول این کلاس متغیر iterator$
را پاس دادهایم و آرگومانهای دوم و سوم به ترتیب مرتبط با نقطهٔ آغازین انتخاب اِلِمانهای آرایه و نقطهٔ پایانی هستند (توجه داشته باشیم که در مثال فوق، اِلِمانهای ۰ تا ۱ انتخاب خواهند شد و خودِ اِلِمان ۲ انتخاب نخواهد شد.) در ادامه، روی متغیر یا بهتر بگوییم آرایهٔ limit$
یک حلقه اجرا کرده و مقادیر آن را چاپ کردهایم به طوری که در خروجی خواهیم داشت:
1
2
در ادامه، قصد داریم تا به کاربرد کلاس CachingIterator بپردازیم. این کلاس نیز یکی دیگر از کلاسهای به اصطلاح Iterator زبان پیاچپی است که میتواند به منظور کار با مجموعهای از اِلِمانهای یک آبجکت یا آرایه مورد استفاده قرار گیرد و به طور کلی میتوان گفت که این کلاس یک به اصطلاح Forward-seeking Iterator است بدان معنا که بررسی میکند ببیند آیا اِلِمانهای بعدی یک آبجکت یا آرایه معتبر هستند یا خیر. برای درک بهتر این موضوع، کدهای فوق را به صورت زیر آپدیت میکنیم:
<?php
ini_set('display_errors', '1');
$numbers = [1, 2, 3];
$iterator = new ArrayIterator($numbers);
// echo $iterator->count();
// $limit = new LimitIterator($iterator, 0, 2);
// foreach($limit as $item) {
// echo $item . "\n";
// }
$ci = new CachingIterator($iterator);
foreach ($ci as $item) {
echo $item;
if ($ci->hasNext()) {
echo ", ";
}
}
در خط سیزدهم آبجکتی تحت عنوان ci$
از روی کلاس CachingIterator
ساخته و به عنوان پارامتر ورودی این کلاس نیز متغیر iterator$
را در نظر گرفتهایم که این متغیر حاوی آبجکتی است که دربرگیرندهٔ اِلِمانهای آرایهٔ numbers$
میباشد. در ادامه، با استفاده از foreach
شروع به چرخش در آبجکت ci$
کرده و تکتک اِلِمانهای آن را داخل متغیری به نام item$
ریخته سپس آنها را چاپ کردهایم. داخل این حلقه از یک دستور شرطی استفاده کردیم بدین شکل که متد ()hasNext
از کلاس CachingIterator
را فراخوانی کردهایم و همانطور که از نام این متد مشخص است، چک میکند ببیند که داخل آبجکت ci$
پس از آخرین اِلِمان، اِلِمان دیگری وجود دارد یا خیر که اگر نتیجه true
بود یک علامت ,
چاپ میشود و در غیر این صورت هیچ اتفاقی رخ نخواهد داد. پس از اجرای کدهای جدیدی که داخل فایل index.php
نوشتیم، در خروجی نیز خواهیم داشت:
1, 2, 3
چنانچه بخواهیم کاربردی عملیتر از کلاسهای SPL فوقالذکر را مثال بزنیم، میتوانیم به پروسهٔ ساخت یک منوی سایت اشاره کنیم و همانطور که در ادامه ملاحظه خواهید نمود، میبینیم که به چه نحوه میتوان از آنها برای ساخت اصولی یک منو استفاده نمود:
<?php
ini_set('display_errors', '1');
// $numbers = [1, 2, 3];
// $iterator = new ArrayIterator($numbers);
// echo $iterator->count();
// $limit = new LimitIterator($iterator, 0, 2);
// foreach($limit as $item) {
// echo $item . "\n";
// }
// $ci = new CachingIterator($iterator);
// foreach ($ci as $item) {
// echo $item;
// if ($ci->hasNext()) {
// echo ", ";
// }
// }
$nav = [
'Home' => '/home',
'Products' => '/products',
'About Us' => '/about',
'Privacy Policy' => '/privacy-policy',
];
$output = new ArrayIterator();
$ca = new CachingIterator(new ArrayIterator($nav));
foreach ($ca as $name => $url) {
if ($ca->hasNext()) {
$output->append('<li><a href="' . $url . '">' . $name . '</a></li>');
} else {
$output->append('<li class="last"><a href="' . $url . '">' . $name . '</a></li>');
}
}
if ($output->count()) {
$output = (array) $output;
echo '<ul id="nav">' . "\n" . implode("\n", $output) . "\n" . '</ul>';
}
ابتدا از کدهای فوق خروجی گرفته سپس به تفسیر آنها خواهیم پرداخت:
<ul id="nav">
<li>
<a href="/home">Home</a>
</li>
<li>
<a href="/products">Products</a>
</li>
<li>
<a href="/about">About Us</a>
</li>
<li class="last">
<a href="/privacy-policy">Privacy Policy</a>
</li>
</ul>
همانطور که میبینیم، توانستهایم آرایهٔ nav$
که حاوی یک سری Key/Value بود را به یک منوی اچتیامال مبدل سازیم. در تفسیر کدهای فوق میتوان گفت که در خط بیستوهفتم از روی کلاس ArrayIterator
آبجکتی ساختهایم تحت عنوان output$
که فعلاً خالی است و در ادامه قرار است تا حاوی خروجی نهایی منو گردد. در ادامه، آبجکت دیگر از روی کلاس CachingIterator
ساختهایم به نام ca$
که به عنوان پارامتر ورودی آن نیز (new ArrayIterator($nav
را قرار دادهایم بدان معنا که آرایهٔ nav$
تبدیل به آبجکتی از جنس این کلاس خواهد شد.
با استفاده از یک حلقه، قصد داریم تا داخل آبجکت ca$
گشتزنی کنیم و تکتک آنها را به کلیدها و مقادیر متناظرشان تفکیک کرده و به ترتیب در متغیرهای name$
و url$
ذخیرهسازیم. داخل این حلقه با استفاده از دستور if
تست کردهایم ببینیم که آیا آبجکت ca$
پس از آخرین اِلِمان، اِلِمان دیگری دارا است یا خیر که اگر پاسخ true
بود، وارد بلوک if
شده و با استفاده از متد از پیش تعریف شده داخل کلاس ArrayIterator
تحت عنوان ()append
یک تگ <li></li>
به آبجکت output$
که در حال حاضر خالی است میافزاییم و اگر پاسخ false
بود، وارد بلوک else
شده و دقیقاً همان تگ را میافزاییم با این تفاوت که کلاس last
را برای این تگ درج میکنیم تا بعداً با استفاده از کدهای سیاساس بتوان به آن استایل داد.
خارج از حلقهٔ foreach
نیز از یک دستور شرطی استفاده کردهایم و به عنوان شرط هم متد ()count
از کلاس ArrayIterator
را به آبجکت output$
منتسب نمودهایم بدان معنا که چک کنیم ببینیم اساساً آیا این آبجکت حاوی مقداری میباشد یا خیر که اگر پاسخ به این شرط true
بود، وارد بدنهٔ این دستور شرطی شده و ابتدا به ساکن با استفاده از مفهومی تحت عنوان Casting آبجکت output$
را به یک آرایه مبدل ساختهایم چرا که بعداً قرار است تا از آن به شکل یک آرایه استفاده نماییم. در ادامه هم یک جفت تگ <ul></ul>
با شناسهٔ nav
چاپ کرده و داخل آن نیز با استفاده از دستور ()implode
گفتهایم که آرایهٔ output$
به یک استرینگ تبدیل شده و در انتهای هر اِلِمان آن نیز با استفاده از دستور "n\"
به یک سطر جدید برویم.