با سلام و عرض ادب خدمت شما خواننده ی گرامی، با قسمت ششم از سری مباحث آموزش برنامه نویسی شیء گرای PHP در خدمت شما هستیم. در قسمت قبلی وارد مبحث وراثت یا inheritance شدیم و مفهوم کلی وراثت در برنامه نویسی شیء گرا را توضیح دادیم. در این قسمت نیز مطالب بیشتری در مورد وراثت خواهیم آموخت. از آن جهت که آموزش ها به صورت عملی و در عین حال مفید و کوتاه باشند مفاهیم مبحث وراثت را به صورت سوال و جواب طی خواهیم کرد! در ادامه متوجه خواهید شد.
آیا یک کلاس فرزند میتواند در عین حالی که از کدهای کلاس پدر استفاده می کند، خصوصیات و متدهای مخصوص خودش را داشته باشد؟ جواب مثبت است اما این ارتباط یک طرفه است!
این مسئله بدین معنی است که کلاس های فرزند می توانند از کدهای کلاس پدر استفاده کنند اما کلاس پدر نمی تواند از کدهای کلاس فرزند استفاده کند.
اگر این سری آموزشی را دنبال می کنید باید با مثال معروف ماشین در دوره ی ما آشنایی داشته باشید! در این قسمت برای اثبات استقلال کلاس های فرزند میتوانیم از همان مثال ماشین استفاده کنیم:
// کلاس پدر خصوصیات و متدهای خود را دارد class Car { //یک خصوصیت خصوص تنها از طریق خود پدر قابل دسترسی است private $model; // خصوصیات و متدهای عمومی میتوانند توسط پدر یا فرزند استفاده شوند public function setModel($model) { $this -> model = $model; } public function getModel() { return $this -> model; } } // کلاس های فرزند میتوانند علاوه بر کدهایی که از پدر به ارث برده اند می توانند کدهای خودشان را نیز داشته باشند class SportsCar extends Car{ private $style = 'fast and furious'; public function driveItWithStyle() { return 'Drive a ' . $this -> getModel() . ' <i>' . $this -> style . '</i>'; } } // یک نمونه از کلاس فرزند میسازیم $sportsCar1 = new SportsCar(); // از متدی استفاده میکنیم که کلاس فرزند از کلاس پدر به ارث برده است $sportsCar1 -> setModel('Ferrari'); // از متدی استفاده میکنیم که مستقیما به کلاس فرزند اضافه شده بود echo $sportsCar1 -> driveItWithStyle();
نکات مربوط به کد شماره 1:
;private $model
متوجه می شوید که خصوصیت model یک خصوصیت private (خصوصی) است که تنها توسط کلاس دارنده ی آن قابل استفاده است. با استفاده از یک setter به نام setModel، مقدار این خصوصیت را تعیین و برابر با Ferrari قرار دادیم. اگر در رابطه با setter ها و getter ها چیزی نمی دانید به قسمت های قبلی مراجعه کنید: برنامه نویسی شی گرا در PHP – مفاهیم Setter ،Getter و ConstructorDrive a Ferrari fast and furious.
سوال: من چنین کدی نوشته ام اما با خطایی مواجه می شوم. چطور ممکن است؟
پاسخ: تصور کنید کد بالا (کد شماره 1)، به صورت زیر نوشته می شد:
// کلاس پدر class Car { //خصوصیت مدل ماشین یک خصوصیت خصوصی است بنابراین فقط از داخل خود کلاس قابل دسترسی است private $model; //عمومی setter متد public function setModel($model) { $this -> model = $model; } } // کلاس فرزند class SportsCar extends Car{ //سعی میکند یک ویژگی خصوصی که متعلق به کلاس پدر است را دریافت کند public function hello() { return "beep! I am a <i>" . $this -> model . "</i><br />"; } } //ساخت نمونه از کلاس فرزند $sportsCar1 = new SportsCar(); //تعیین مدل ماشین $sportsCar1 -> setModel('Mercedes Benz'); //دریافت یا خروجی گرفتن از مدل ماشین echo $sportsCar1 -> hello();
خروجی کد ما در این صورت، خطای زیر خواهد بود:
Notice: Undefined property: SportsCar::$model
این یکی از رایج ترین اشتباهات برنامه نویسان مبتدی است؛ توجه کنید که این دو کد منطق کاملا متفاوتی دارند! در این مثال ما setter داریم اما getter نداریم. از طرفی در کدِ تابعِ hello در کلاس فرزند نوشته ایم:
public function hello() { return "beep! I am a <i>" . $this -> model . "</i><br />"; }
در واقع به خاطر استفاده ی مستقیم از this$
به جای استفاده از getter، زبان PHP تصور میکند که ما میگوییم به دنبال خصوصیت model درونِ کلاس sportsCar (کلاس فرزند) بگرد. چنین خصوصیتی در کلاس فرزند وجود ندارد (در کلاس پدر تعریف شده است) و از همین جهت به خطای مذکور برمیخوریم. ترجمه ی این خطا برابر است با "اخطار: خصوصیت تعریف نشده: ماشیناسپرت::مدل". در واقع به ما میگوید که چنین خصوصیتی وجود ندارد!
سوال: اگر نخواهیم از getter استفاده کنیم چطور؟
پاسخ: راه حل ساده ی شما این است که خصوصیت model را از private به protected تغییر دهید! به همین سادگی! در این حالت خروجی ما صحیح و سالم و برابر عبارت زیر خواهد بود:
beep! I am a Mercedes Benz
به کد زیر (کد شماره 3) توجه کنید:
// نکته 1 class Car { public function hello() { return "beep"; } } //نکته 2 class SportsCar extends Car { public function hello() { return "Hallo"; } } //ساخت شیء جدید $sportsCar1 = new SportsCar(); //hello دریافت خروجی از تابع echo $sportsCar1 -> hello();
نکات کد شماره بالا (کد شماره 3):
سوال: زمانی که درخواست خروجی از تابع hello میکنیم کدام خروجی به ما نمایش داده می شود؟
بدون اینکه جواب سوال را بخوانید سعی کنید خودتان آن را جواب بدهید.
پاسخ ساده است؛ Hallo خروجی ما خواهد بود اما چرا؟ اگر ما تابع hello را در کلاس فرزند تعریف نمیکردیم، در هنگام دریافت خروجی از تابع hello که در کلاس پدر نوشته شده بود استفاده می شد (کلاس فرزند کدهای کلاس پدر را به ارث می برد). حالا که این تابع را دوباره در کلاس فرزند تعریف کردیم، مقدار آن override می شود؛ یعنی مقدار ثانویه جایگزین مقدار اولیه می شود.
بر همین اساس می توان فرآیند override شدن را این گونه تعریف کرد: زمانی که یک خصوصیت یا متد را override میکنیم، خصوصیت یا متدی را که در کلاس پدر وجود دارد دوباره در کلاس فرزند تعریف میکنیم، اما با مقادیر متفاوت!
اگر شما دوست ندارید که کلاس های فرزند بتوانند خصوصیات و یا متدهای کلاس پدر را override کنند میتوانید از کلید واژه ی final (به معنی "نهایی") استفاده کنید. به مثال زیر توجه کنید:
// را برمیگداند beep کلاس پدر متد عمومی دارد که class Car { final public function hello() { return "beep"; } } //کلاس فرزند متدی دارد که میخواهد متد کلاس پدر را باطل کند class SportsCar extends Car { public function hello() { return "Hallo"; } } //ساخت شیء جدید $sportsCar1 = new SportsCar(); //hello دریافت خروجی متد echo $sportsCar1 -> hello();
توضیح کد بالا (کد شماره 4):
از آنجایی که در متد ()hello در کلاس پدر از کلید واژه ی final استفاده شده است خروجی کد ما به صورت زیر خواهد بود:
Fatal error: Cannot override final method Car::hello()
این خطا به ما می گوید:
خطا از نوع Fatal: شما نمیتوانید متد hello در کلاس car را که دارای کلید واژه ی final است، تغییر داده یا override کنید.
سه نکته ی مهم در رابطه با کلید واژه ی final وجود دارد که برنامه نویسان معمولا در رابطه با آنها دچار سردرگمی می شوند:
برای کسب اطلاعات بیشتر به صفحه ی رسمی PHP در مورد کلید واژه ی final مراجعه کنید.
امیدوارم از این قسمت از سری آموزشی برنامه نویسی شیء گرا PHP استفاده ی کامل را برده باشید.
تا قسمت بعدی در پناه حق.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.