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

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

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

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


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

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

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


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

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


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
در ادامه، می‌خواهیم ببینیم که تایپ هینتینگ در مورد کلاس‌ها به چه شکل است. برای این منظور، 2 کلاس به صورت زیر تحت عناوین Site و World می‌سازیم:


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

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

داخل هر ۲ کلاس، فانکشنی از نوع کانستراکتور ساخته‌ایم (توجه داشته باشیم که وظیفهٔ کانستراکتورها این است که به محض ساخت شدن یک آبجکت از روی کلاسی که داخل آن قرار گرفته‌اند، به صورت خودکار فراخوانی شوند).  

وظیفهٔ کانستراکتور قرار گرفته در کلاس 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 این امکان را به ما می‌دهد تا روی برنامه‌های خود کنترل بیشتری داشته و ساختارهای اصولی‌تر پیاده‌سازی کنیم و اهمیت این مسئله زمانی دوچندان می‌شود که تیمی از دولوپرها روی پروژه‌ای واحد کار کنند که در چنین شرایطی این اطمینان حاصل می‌گردد که تا حد قابل‌توجهی جلوی کدنویسی سلیقه‌ای دولوپرها گرفته خواهد شد.

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

منبع


بهزاد مرادی