در آموزش آشنایی با مفهوم OOP و بررسی اصول چهارگانهٔ شیئگرایی، گفتیم که یکی از پایههای شیئگرایی مبحثی است تحت عنوان Inheritance که میتوان معادلی همچون «وراثت» برای آن در نظر گرفت. به طور خلاصه میتوان گفت که در متودولوژی اواوپی، وراثت این امکان را در اختیار توسعهدهندگان میگذارد تا بتوانند ویژگیهای کلاسی خاص را در دیگر کلاسها وارد سازند.
به منظور درک بهتر این موضوع، داخل پوشهٔ oop
پروژهای با نامی دلخواه تحت عنوان inheritance
ساخته و فولدر اِستراکچری که در ابتدای این دورهٔ آموزشی ایجاد کردیم را در آن میسازیم. سپس وارد پوشهٔ classes
شده و فایل User.php
را به صورت زیر تکمیل میکنیم:
<?php
namespace SokanAcademy;
class User
{
public $firstname;
public $lastname;
public $role = 'basic';
public $hasFullPermission = false;
public function __construct($firstname, $lastname, $role = null, $hasFullPermission = null)
{
$this->firstname = $firstname;
$this->lastname = $lastname;
if ($role) {
$this->role = $role;
}
if ($hasFullPermission) {
$this->hasFullPermission = $hasFullPermission;
}
}
public function isAdmin()
{
if ($this->role == 'admin') {
return "This user is an Administrator";
}
}
public function showFullName()
{
return $this->firstname . ' ' . $this->lastname;
}
}
در بدنهٔ این کلاس چهار پراپرتی تعریف کردهایم که از میان آنها پراپرتیهای role$
و hasFullPermission$
دارای مقادیری پیشفرض هستند. سپس کانستراکتور را موظف کردهایم که در پروسهٔ ساخت یک آبجکت جدید از روی کلاس User
، دو پارامتر ورودی اجباری و دو پارامتر ورودی اختیاری از کاربر بگیرد؛ به عبارت بهتر، پارامترهای ورودی firstname$
و lastname$
که دارای مقدار اولیهٔ null
نیستند الزامی بوده و در حین استفاده از این کلاس حتماً میباید در نظر گرفته شوند اما پارامترهای role$
و hasFullPermission$
دارای مقدار اولیهٔ null
هستند بدین معنا که اگر در حین استفاده از این کلاس آنها را سِت نکنیم، مقدار null
به آنها اختصاص خواهد یافت و در غیر این صورت، مقادیر جدید جایگزین خواهند شد.
همچنین داخل بدنهٔ کانستراکتور دستور دادهایم تا مقادیر پارامترهای ورودی به پراپرتیهای متناظرشان منتسب گردد به علاوه این که با استفاده از دو دستور شرطی چک کردهایم ببینیم که آیا پراپرتیهای role$
و hasFullPermission$
به اصطلاح سِت شدهاند (یا به عبارتی مقداری به غیر از null
دارند) یا خیر که اگر این گونه بود، مقادیر آنها را نیز به پراپرتیهای مربوطه منتسب خواهیم نمود.
در ادامه، فانکشن یا بهتر بگوییم متدی نوشتهایم تحت عنوان ()isAdmin
و داخل آن چک کردهایم ببینیم که آیا مقدار پراپرتی role$
برابر با استرینگ admin
میباشد یا خیر که اگر این طور بود، استرینگی مبنی بر ادمین بودن کاربر را ریترن خواهیم نمود. همچنین متد دیگری به نام ()showFullName
نوشته و داخل آن پراپرتیهای firstname$
و lastname$
را با یکدیگر کانکت نموده و نتیجهٔ نهایی را ریترن کردهایم. حال جهت تست، وارد فایل index.php
شده و آن را به صورت زیر تکمیل مینماییم:
<?php
ini_set('display_errors', '1');
require_once 'vendor/autoload.php';
$user = new SokanAcademy\User();
تنها کاری که انجام دادهایم این است که آبجکتی تحت عنوان user$
از روی کلاس User
ساختهایم و چنانچه این فایل را اجرا کنیم، در خروجی خواهیم داشت:
/var/www/oop/inheritance$ php index.php
PHP Fatal error: Uncaught ArgumentCountError: Too few arguments to function SokanAcademy\User::__construct(), 0 passed in /var/www/oop/inheritance/index.php on line 5 and at least 2 expected in /var/www/oop/inheritance/classes/User.php:11
این ارور به درستی اشاره میکند که کلاس User
حداقل به دو پارامتر الزامی نیاز دارد اما این در حالی است که ما در حین ساخت آبجکت هیچ گونه پارامتری را به آن پاس ندادهایم که برای رفع این ارور، کد فوق را به صورت زیر تصحیح مینماییم:
<?php
ini_set('display_errors', '1');
require_once 'vendor/autoload.php';
$user = new SokanAcademy\User('Behzad', 'Moradi');
در واقع، با در نظر گرفتن دو پارامتر اول که اجباری بودند، ارور فوق نیز مرتفع خواهد شد. حال در خط بعد کد زیر را وارد میکنیم:
echo $user->isAdmin();
اما در خروجی هیچ چیزی ملاحظه نخواهد شد چرا که داخل این متد دستور دادهایم که چنانچه پراپرتی role$
برابر با استرینگ admin
بود چیزی را ریترن کند و در غیر این صورت هیچ کار خاصی انجام ندهد.
در این مرحله از آموزش، نیاز داریم تا به مبحث وراثت ورود پیدا کنیم که برای این منظور، فایلی با نامی دلخواه همچون Administrator.php
داخل پوشهٔ classes
میسازیم و کاری میکنیم تا کلیهٔ خصوصیاتش را از کلاس User
به ارث ببرد.
در زبان برنامهنویسی پیاچپی پروسهٔ ارثبری با استفاده از کیورد extends
آغاز میگردد. به طور مثال، اگر بخواهیم کاری کنیم که کلاسی همچون Administrator
از User
ارثبری کند، وارد فایل Administrator.php
شده و کدهای زیر را داخل آن درج میکنیم:
<?php
namespace SokanAcademy;
class Administrator extends User
{
}
آنچه در ارتباط با کلاس فوق نیاز به تفسیر دارد این است که پس از نام کلاس، از کیورد extends
که در ظاهر نامی بامسمی است استفاده کرده سپس نام کلاسی را درج میکنیم که قصد داریم ویژگیهایش را به ارث ببریم.
در این مرحله کار خاصی با کلاس Administrator
نخواهیم داشت بلکه نیاز است تا وارد فایل index.php
شده تا ببینیم که به چه شکل میتوانیم اقدام با ساخت یک آبجکت از روی این کلاس کنیم به طوری که داریم:
<?php
ini_set('display_errors', '1');
require_once 'vendor/autoload.php';
// $user = new SokanAcademy\User('Behzad', 'Moradi');
// echo $user->isAdmin();
$admin = new SokanAcademy\Administrator('Sahand', 'Ahmadi', 'admin', true);
echo $admin->isAdmin();
میبینیم که از روی کلاس Administrator
آبجکتی تحت عنوان admin$
ساخته و هر چهار پارامتر ورودی این کلاس را نیز سِت کرده سپس اقدام به فراخوانی متد ()isAdmin
کردهایم. در واقع، میبینیم که به عنوان پارامتر سوم، از استرینگ admin
استفاده نمودهایم و چنانچه مجدد به کلاس User
باز گردیم که به عنوان کلاس Parent (والد) شناخته میشود، میبینیم که داخل کانستراکتور این کلاس دستور دادهایم که اگر پارامتر سوم این کلاس مقداری به غیر از null
داشت، وارد دستور شرطی اول شده و مقدار آن را به پراپرتی role$
که در بدنهٔ این کلاس قرار دارد منتسب نماید. همچنین مقدار true
را به عنوان پارامتر چهارم در نظر گرفتهایم که بر اساس توضیحات فوق، داخل کانستراکتور کلاس User
دستور شرطی دوم اجرا شده و این مقدار به پراپرتی hasFullPermission$
اختصاص داده خواهد شد. حال اگر این فایل را اجرا کنیم، در خروجی خواهیم داشت:
This user is an Administrator
در واقع میبینیم گرچه کلاس Administrator
که اصطلاحاً تحت عنوان کلاس Child (فرزند) شناخته میشود حاوی هیچ گونه کدی نیست، اما توانسته کلیهٔ خصوصیاتش را از کلاس والدش به ارث ببرد.
همچنین با توجه به سِت کردن پارامتر چهارم با مقدار true
، از این پس پراپرتی hasFullPermission$
این آبجکت مقداردهی شده است به طوری که جهت تست آن، میتوان کدهای زیر را مورد توجه قرار داد:
<?php
ini_set('display_errors', '1');
require_once 'vendor/autoload.php';
// $user = new SokanAcademy\User('Behzad', 'Moradi');
// echo $user->isAdmin();
$admin = new SokanAcademy\Administrator('Sahand', 'Ahmadi', 'admin', true);
echo $admin->isAdmin();
if ($admin->hasFullPermission) {
echo "\n";
echo $admin->showFullName();
}
در تفسیر کدهای فوق باید گفت که اول با استفاده از یک دستور شرطی چک کردهایم ببینیم که آیا پراپرتی hasFullPermission$
دارای مقدار true
است یا خیر که اگر این گونه بود، ابتدا با چاپ دستور n\
وارد یک خط جدید شده سپس متد ()showFullName
را فراخوانی کردهایم به طوری که از این پس در خروجی خواهیم داشت:
This user is an Administrator
Sahand Ahmadi
چنانچه بر اساس ارتباطات دنیای واقعی بخواهیم ارتباط مابین کلاسهای User
و Administrator
را شبیهسازی کنیم، میتوان گفت که کلاس User
همچون پدر است و Administrator
فرزند آن! حال قصد داریم تا برای کلاس پدر یک نوه نیز بسازیم که برای این منظور، داخل پوشهٔ classes
فایل جدیدی تحت عنوان SubAdmin.php
ساخته و کدهای زیر را داخل آن درج میکنیم:
<?php
namespace SokanAcademy;
class SubAdmin extends Administrator
{
}
همانطور که میبینیم، این کلاس ویژگیهایش را از کلاس Administrator
به ارث برده است و از آنجا که خودِ کلاس Administrator
نیز خصوصیاتش را از کلاس User
ارثبری کرده است، پس میتوان گفت که کلیهٔ ویژگیهای کلاس والدِ User
داخل کلاس نوهٔ SubAdmin
موجود هستند. در ادامه، مجدد به فایل index.php
بازگشته و آن را به صورت زیر آپدیت میکنیم:
<?php
ini_set('display_errors', '1');
require_once 'vendor/autoload.php';
// $user = new SokanAcademy\User('Behzad', 'Moradi');
// echo $user->isAdmin();
// $admin = new SokanAcademy\Administrator('Sahand', 'Ahmadi', 'admin', true);
// echo $admin->isAdmin();
// if ($admin->hasFullPermission) {
// echo "\n";
// echo $admin->showFullName();
// }
$grandChild = new SokanAcademy\SubAdmin('Mitra', 'Gholami');
echo $grandChild->showFullName();
میبینیم که آبجکتی تحت عنوان grandChild$
از روی کلاس SubAdmin
ساخته و پارامترهای الزامی را نیز سِت کردهایم و در خط بعد هم خروجی متد ()showFullName
را چاپ کردهایم به طوری که در خروجی خواهیم داشت:
Mitra Gholami
حال قصد داریم تا با مفهومی تحت عنوان Overriding در شیئگرایی آشنا شویم که در همین راستا، کلاس SubAdmin
را به صورت زیر آپدیت میکنیم:
<?php
namespace SokanAcademy;
class SubAdmin extends Administrator
{
public function showFullName()
{
return $this->firstname . ' ' . $this->lastname . ' from the SubAdmin class';
}
}
همانطور که میبینیم، متد ()showFullName
که در کلاسِ والدِ User
قرار دارد را مجدد نوشته و کدهای داخل آن را تغییر دادهایم که به این کار اصطلاحاً Method Overriding گفته میشود؛ به عبارت بهتر، با این کار الگوریتم اصلی متدی که داخل کلاس والد بود را بازنویسی کردهایم به طوری که اگر مجدد فایل index.php
را اجرا کنیم، در خروجی خواهیم داشت:
Mitra Gholami from the SubAdmin class
میبینیم که از این پس دیگر متد اصلی ()showFullName
که داخل کلاس User
قرار داشت اجرا نشده بلکه متدی با همین نام که داخل کلاس SubAdmin
نوشتیم به کار گرفته شده است.
موضوعی که در شیئگرایی حائز اهمیت میباشد این است که ما میتوانیم علاوه بر ارثبری از کلاس والد، یک سری خصوصیات نیز برای خود کلاس فرزند نیز در نظر بگیریم که در کنار خصوصیات به ارث برده از کلاس والد حضور خواهند داشت. به طور مثال، کلاس SubAdmin
را به صورت زیر تکمیل میکنیم:
<?php
namespace SokanAcademy;
class SubAdmin extends Administrator
{
public function showFullName()
{
return $this->firstname . ' ' . $this->lastname . ' from the SubAdmin class';
}
public function doSomething()
{
echo "This method is specific to SubAdmin class";
}
}
همانطور که میبینیم متدی تحت عنوان ()doSomething
نوشتهایم که فقط مختص به این کلاس است به طوری که در فایل index.php
میتوانیم آن را به صورت زیر فراخوانی کنیم:
<?php
ini_set('display_errors', '1');
require_once 'vendor/autoload.php';
// $user = new SokanAcademy\User('Behzad', 'Moradi');
// echo $user->isAdmin();
// $admin = new SokanAcademy\Administrator('Sahand', 'Ahmadi', 'admin', true);
// echo $admin->isAdmin();
// if ($admin->hasFullPermission) {
// echo "\n";
// echo $admin->showFullName();
// }
$grandChild = new SokanAcademy\SubAdmin('Mitra', 'Gholami');
// echo $grandChild->showFullName();
echo $grandChild->doSomething();
با فراخوانی این متد جدید، در خروجی خواهیم داشت:
This method is specific to SubAdmin class
میبینیم که خروجی این متد به درستی در معرض دیدمان قرار گرفته است.
جمعبندی
در این آموزش به بررسی یکی از پایههای کلیدی OOP تحت عنوان Inheritance پرداختیم که این امکان را در اختیار توسعهدهندگان زبان برنامهنویسی پیاچپی میگذارد تا از دوبارهکاری و نوشتن کدهای تکراری جلوگیری کنند و این فیچر چیزی است که در تمامی فریمورکها و لایبرریهای مطرح این زبان به کار گرفته میشود.