آشنایی با مفهوم Type Hinting در زبان PHP

آشنایی با مفهوم Type Hinting در زبان PHP

گاهی‌ اوقات در تعریف کردن فانکشن‌ها در زبان برنامه‌نویسی پی‌اچ‌پی نیاز داریم تا پارامترهای ورودی فانکشن مد نظر از نوع خاصی باشند بدین شکل که مثلاً پارامتر ورودی باید آبجکتی از روی کلاسی خاص، یک اینترفیس و یا یک آرایه باشد که برای این منظور نیاز داریم تا با مفهومی تحت عنوان Type Hinting آشنا شویم که در این پست در قالب مثال‌هایی عملی، یاد خواهیم گرفت که چگونه می‌توان با استفاده از مفهوم Type Hinting نوع پارامترهای ورودی یک فانکشن را از پیش تعریف کرد.

برای مثال، برای آنکه فانکشن خود را مجبور کنیم تا پارامتر ورودی‌اش از نوع آرایه باشد، باید از ساختار زیر تبعیت کنیم:

function functionName (array $argumentName) 
{
  //code
}

همان‌طور که در قطعه کد بالا مشاهده می‌شود، قبل از پارامتر ورودی این فانکشن از کلیدواژهٔ array استفاده کرده‌ایم به طوری که از این پس پارامتر argumentName$ همواره باید از نوع آرایه باشد که در غیر این صورت، با ارور مواجه خواهیم شد. حال قصد داریم فانکشنی بنویسیم تحت عنوان ()calculatePetrolCosumption (محاسبهٔ میزان مصرف سوخت) و ورودی این فانکشن باید آرایه‌ای از دیتای مرتبط با خودروهای مختلف باشد. پیش از هر چیز، آرایه‌ای حاوی اطلاعات چند خودرو به صورت زیر ایجاد می‌کنیم:

$models = array(
		array('pride', 6, 112),
		array('206', 7, 200),
		array('maxima', 14, 76)
	);

در آرایهٔ models$، سه آرایهٔ داخلی حاوی اطلاعات مرتبط با خودروهای پراید، پژو و ماگزیما را درج کرده‌ایم بدین صورت که اندیس اول دربرگیرندهٔ نام خودرو است، اندیس دوم حاوی میزان مصرف سوخت در هر یکصد کیلومتر است و اندیس سوم هم شامل مسافتی می‌باشد که قرار است میزان مصرف سوخت در آن را محاسبه کنیم. حال شروع به کدنویسی فانکشن خود می‌کنیم:

function calculatePetrolConsumption(array $models) 
{
    foreach ($models as $model) {
        echo $model[0];
        echo " consumes ";
        echo ($model[2] * $model[1]) / 100;
        echo " liters in $model[2] kilometers";
        echo "<br>";
    }
}

قبل از پارامتر ورودی model$، از کلیدواژهٔ array استفاده کردیم که تا به فانکشن خود بفهمانیم که پارامتر ورودی باید فقط و فقط از نوع آرایه باشد و در ادامه یک foreach روی آرایهٔ خودروها زده‌ایم تا به اجزای این آرایه دسترسی پیدا کنیم. پیش از هر چیز، اندیس ۰ آرایه که حاوی نام خودرو است را با استفاده از دستور echo چاپ می‌کنیم (نیاز به توضیح نیست که در PHP و دیگر زبان‌های برنامه‌نویسی، شمارش اندیس‌های هر آرایه برخلاف ریاضیات روزمره‌‌‌ای که با آن سر و کار داریم، به جای ۱ از 0 آغاز می‌شود.)

سپس اِسترینگ consumes به معنی «مصرف می‌کند» را نوشته و در خط بعد، الگوریتم محاسبهٔ میزان مصرف سوخت بر اساس مسافت را پیاده‌سازی می‌کنیم. در واقع، یک تناسب ساده بسته‌ایم بدین شکل که گفته‌ایم مثلاً پراید در هر ۱۰۰ کیلومتر ۶ لیتر بنزین مصرف می‌کند، حال در 112 کیلومتر چقدر مصرف خواهد کرد؟ ابتدا اندیس دوم که 112 است را در اندیس اول که 6 لیتر در هر ۱۰۰ کیلومتر است ضرب کرده سپس حاصل‌ضرب را بر 100 کیلومتر در هر ساعت تقسیم می‌کنیم (همچنین برای آنکه کد تمیزتر باشد، بخش تقسیم اعداد بر یکدیگر را داخل پرانتز قرار داده‌ایم.) در خط بعد هم ابتدا اِسترینگ liters in به معنی «لیتر در هر» را نوشته سپس اندیس دوم یا همان میزان مسافت را نوشته و در نهایت اِسترینگ kilometers به معنی «کیلومتر» را نوشته‌ایم و به عنوان مرحلهٔ آخر هم یک تگ <br> را چاپ کرده‌ایم تا در هر بار چرخش حلقه، خروجی در یک خط مجزا چاپ شود. یک بار فانکشن خود را صدا می‌زنیم:

calculatePetrolConsumption($models);

خروجی برنامهٔ بالا، به صورت زیر خواهد بود:

pride consumes 6.72 liters in 112 kilometers
206 consumes 14 liters in 200 kilometers
maxima consumes 10.64 liters in 76 kilometers

می‌بینیم که برنامه به درستی کار می‌کند. اکنون برای آنکه عملکرد تایپ هینتیگ را بهتر درک کنیم، به جای یک پارامتر ورودی از نوع آرایه، یک استرینگ برای فانکشن خود در نظر می‌گیریم:

calculatePetrolConsumption('pride');

فایل را ذخیره کرده و اسکریپت را مجدد اجرا می‌کنیم:

Catchable fatal error: Argument 1 passed to calculatePetrolConsumption() must be of the type array, string given, called in /var/www/exercise/index.php on line 19 and defined in /var/www/exercise/index.php on line 9

همان‌طور که از ارور بالا مشخص است، مفسر PHP به ما اعلام می کند که فانکشن ()calculatePetrolConsumption یک پارامتر ورودی از نوع آرایه می‌گیرد اما ما پارامتری از نوع اِسترینگ به آن پاس داده‌ایم!

Type Hinting کلاس‌ها در زبان PHP
در ادامه، می‌خواهیم ببینیم که تایپ هینتینگ در مورد کلاس‌ها به چه شکل است. برای این منظور، دو کلاس به صورت زیر با نام‌های Site و World می‌سازیم:

class Site
{
    public function __construct()
    {
	echo 'Hello SokanAcademy.com';
    }
}

class World
{
    public function __construct()
    {
	echo 'Hello World';
    }
}

داخل هر دو کلاس، فانکشنی از نوع کانستراکتور ساخته‌ایم (توجه داشته باشیم که وظیفهٔ کانستراکتورها این است که به محض ساخت شدن یک آبجکت از روی کلاسی که داخل آن قرار گرفته‌اند، به صورت خودکار فراخوانی شوند که برای آشنایی بیشتر، می‌توانید به مقالهٔ آشنایی با مفاهیم Constructor و Destructor در PHP مراجعه نمایید.) در واقع، وظیفهٔ کانستراکتور قرار گرفته در کلاس Site این است که اِسترینگ Hello SokanAcademy.com را نمایش دهد و کانستراکتور قرار گرفته داخل کلاس World این وظیفه را دارا است تا اِسترینگ Hello World را چاپ کند. حال فانکشنی تحت عنوان ()showResult به معنی «نتیجه را نمایش بده» ساخته با این شرط که پارامتر ورودی آن باید آبجکتی از نوع کلاس Site باشد:

function showResult(Site $className)
{
    // more statements code here
}

برای تست کردن برنامهٔ خود، ابتدا یک آبجکت از روی کلاس Site ساخته و نام آن را در متغیری تحت عنوان obj$ ذخیره می‌کنیم و سپس این آبجکت را به عنوان پارامتر ورودی فانکشن ()showResult در نظر می‌گیریم:

$obj = new Site();
showResult($obj);

خروجی دستورات بالا به صورت زیر است:

Hello SokanAcademy.com

با توجه به اینکه تایپ پارامتر ورودی این فانکشن آبجکتی از روی کلاس Site است و پیش از هم گفته بودیم که پارامتر ورودی فقط و فقط باید آبجکتی از روی این کلاس باشد، برنامه بدون هیچ مشکلی اجرا می‌شود. اکنون می‌خواهیم آبجکتی از روی کلاس World ساخته و به این فانکشن پاس دهیم:

$worldObject = new World();
showResult($worldObject);

همان‌طور که مشخص است، آبجکتی تحت عنوان worldObject$ از روی کلاس World ساخته‌ایم و آن را به عنوان پارامتر ورودی به فانکشن ()showResult پاس داده‌ایم که خروجی دستور بالا به صورت زیر خواهد بود:

Catchable fatal error: Argument 1 passed to showResult() must be an instance of Site, instance of World given, called in /var/www/exercise/index.php on line 29 and defined in /var/www/exercise/index.php on line 21

می‌بینیم که با یک ارور از جنس Fatal (حاد) مواجه شده‌ایم چرا که ما فقط اجازه داریم تا آبجکتی از روی کلاس Site را به عنوان پارامتر ورودی این فانکشن در نظر بگیریم.

به طور کلی، Type Hinting در زبان برنامه‌نویسی PHP این امکان را به ما می‌دهد تا روی برنامه‌های خود کنترل بیشتری داشته و ساختارهای اصولی‌تر پیاده‌سازی کنیم و اهمیت این مسئله زمانی دوچندان می‌شود که تیمی از دولوپرها روی پروژه‌ای واحد کار کنند که در چنین شرایطی این اطمینان حاصل می‌گردد که تا حد قابل‌توجهی جلوی کدنویسی سلیقه‌ای دولوپرها گرفته خواهد شد (چنانچه علاقمند به فراگیری گام به گام زبان برنامه‌نویسی PHP هستید، می‌توانید به دورهٔ آموزش PHP در سکان آکادمی مراجعه نمایید.)

حال نوبت به نظرات شما می‌رسد. آیا تجربهٔ استفاده از Type Hinting در زبان PHP و یا دیگر زبان‌های برنامه‌نویسی را داشته‌اید؟ به نظر شما این مفهوم چه نقاط قوتی دارا است و در عین حال چه محدودیت‌هایی برای دولوپرها ایجاد می‌کند؟ نظرات، دیدگاه‌ها و تجربیات خود را با ما و سایر کاربران سکان آکادمی به اشتراک بگذارید.



بهزاد مرادی