ارث بری یا Inheritance در php چیست
یکی از مباحث مهم در برنامه نویسی ارث بری است. در برنامه های بزرگ و پیچیده، باید از کلاس ها استفاده کرد. هر کلاسی میتواند ویژگی ها و عملکرد های خاص خودش را داشته باشد.
بیشتر بخوانید: کلاس ها در php
بنابراین کلاس ها می توانند با یکدیگر در ارتباط باشند و از ویژگی های یکدیگر ارث بری کنند. یعنی کلاس A، علاوه بر ویژگی های خود، از کلاس B هم ویژگی هایی را به ارث ببرد و بتواند از آنها استفاده کند.
بنابراین ارث بری در برنامه نویسی مانند ارث بری فرزند و والدین می باشد. فرزند می تواند رنگ چشم و خیلی از رفتارها را از والدین خود به ارث ببرد. همچنین علاوه بر ویژگی های به ارث برده می تواند دارای ویژگی های شخصی خودش باشد.
ارث بری به یک کلاس اجازه میدهد تا اعضای کلاس دیگری را به دست آورد (ارث ببرد)
در php ارث بری همیشه بین دو کلاس انجام میشود و وراثت چندگانه (Multiple Inheritance) نداریم. یعنی یک کلاس فقط می تواند از یک کلاس دیگه ارث بری را انجام دهد.
در ادامه مثال عملی درباره ارث بری را بررسی خواهیم کرد.
کلمه کلیدی extends برای ارث بری در php
دو کلاس Parent و Child را در نظر بگیرید. میخواهیم کلاس Child از کلاس Parent ارث بری انجام دهد. اینکه بعد از ارث بری چه اتفاقی می افتد مهم نیست. فقط میخواهیم نحوه این کار در php را نشان دهیم. برای این کار از کلمه کلیدی extends استفاده میکنیم.
به کلاس Parent کلاس والد، کلاس پایه (Base class) یا کلاس مافوق (super class) گفته میشود.
به کلاس Child، کلاس فرزند یا کلاس مشتق شده (Drived class)، کلاس فرعی یا زیر کلاس (Sub class) گفته میشود.
در ادامه مقاله به کلاس های اصلی، کلاس والد و کلاس های مشتق شده از کلاس پایه را فرزند می نامیم
ابتدا کلاسی به نام Shape، سپس کلاسی با نام Rectangle ایجاد میکنیم. کلاس Rectangle از Shape ارث بری میکند. یعنی Shape به عنوان کلاس پایه (اصلی) و Rectangle به عنوان فرزند در نظر گرفته خواهند شد.
class Shape {
function __construct() {
// ...
}
}
class Rectangle extends Shape { }
ما در کد بالا نحوه استفاده از کلمه کلیدی extends را جهت استفاده ارث بری دو کلاس استفاده کردیم. extends را بعد از نام کلاس فرزند استفاده میکنیم، بعد از آن اسم کلاس پایه که میخواهیم از آن ارث بری انجام شود را مینویسیم.
سلسله مراتب ارث بری کلاس ها در php
همانطور که گفتیم، یک کلاس نمیتواند از چند کلاس پایه دیگر ارث بری کند، این ویژگی (Multiple Inheritance) در php وجود ندارد. این قابلیت بستگی به زبان برنامه نویسی که از آن استفاده میکنید دارد. برای مثال زبان سی پلاس پلاس از قابلیت وراثت چندگانه پشتیبانی میکنید. اما در php این امکان وجود ندارد.
هر کلاس پایه می تواند هر تعدادی کلاس فرزند داشته باشد و هرکدام از آن ها نیز می تواند کلاس پایه هر تعدادی از زیر کلاس های خود باشند
مثال عملی از ارث بری در php
کمی قبلتر اشاره کردیم، کلاس فرزند می تواند به اعضای کلاس والد دسترسی داشته باشد. برای مثال، کلاس B از کلاس A (پدر) ارث بری میکند. این موضوع را با یک مثال شرح خواهیم داد.
class A {
function say_hello() {
return 'Hello World';
}
}
class B extends A {
}
$b = new B();
echo $b->say_hello(); // خروجی: Hello World
کلاس A را کلاس والد (پایه) و کلاس B را فرزند در نظر میگیریم. حالا کلاس B از A ارث بری میکند. با این کار اعضای کلاس A در کلاس B قابل دسترس است.
منظور از اعضای کلاس A، متغیر ها و متد های آن می باشد
مثال دیگری را بررسی میکنیم.
// base class
class A {
public $parent_name = "A";
function parent_method() {
echo 'Print from prarent_method in A class';
}
}
// child class
class B extends A {
public $child_name = "B";
function child_method() {
echo 'Print from child_method in B class';
}
}
حالا ما از کلاس فرزند (یعنی B) نمونه ایجاد میکنیم.
$b = new B();
echo $b->child_method(); // خروجی: Printed from child_method in class B
echo $b->parent_method(); // خروجی: Printed from parent_method in class A
echo $b->parent_name; // خروجی: A
echo $b->child_name; // خروجی: B
کلاس B دارای متد child_method و متغیر child_name می باشد. این ویژگی ها فقط در کلاس B وجود دارد و به صورت طبیعی زمانی که از کلاس B شی ایجاد میکنیم قابل دسترس هستند.
اما اعضای کلاس A، یعنی متد parent_method و متغیر parent_name نیز با استفاده از شی ایجاد شده از کلاس B قابل دسترس است. زیرا کلاس B از کلاس A ارث بری کرده است و در طول مقاله به این موضوع اشاره کردیم.
ساده ترین استفاده از ارث بری را در مثال های بالا نشان دادیم. در ادامه بقیه مباحث مهم در ارث بری را بررسی خواهیم کرد.
لغو و باطل کردن یا Overriding اعضا در php
در مثال های بالا بررسی کردیم که کلاس فرزند می تواند به متد های کلاس پایه خود (والد) دسترسی داشته باشد. اما اگر در کلاس فرزند، متدی هم نام با متد موجود در کلاس والد ایجاد کنیم، چه اتفافی خواهد افتاد؟
بازتعریفی اعضای کلاس پایه در کلاس فرزند، برای اجرا و عملکردی جدید، لغو کردن یا Overriding نام دارد
به زبان ساده اگر شما در کلاس A متدی به نام m1 داشته باشید، سپس در کلاس B یک متد با نام m1 تعریف کنید، اصطلاحا متد m1 را override کرده اید.
کد زیر را ببینید.
class A {
function m1() {
echo "Print from class A -> m1()";
}
}
class B extends A {
function m1() {
echo "Print from class B -> m1()";
}
}
$obj = new B();
$obj->m1(); // خروجی: Print from class b -> m1()
همانطور که میبینید در خط آخر، زمانی که متد m1 فراخوانی میشود. متد m1 در کلاس B فراخوانی خواهد شد،زیرا متد m1 در B لغو یا override شده است.
کلمه کلیدی parent در php
زمانی که کلاس فرزند دارای یک سازنده یا کانستراکتور باشد، درواقع سازنده کلاس والد لغو یا override شده است.
کلمه کلیدی parent به عنوان نام مستعار برای نام کلاس والد محسوب میشود که به جای آن قابل استفاده است. با parent می توانید به اعضای کلاس والد در کلاس فرزند، دسترسی پیدا کرد. بنابراین زمانی که شما در کلاس فرزند، سازنده تعریف میکنید، برای اینکه سازنده کلاس والد نیز فراخوانی شود، این دستور باید در کلاس فرزند مشخص شود.
باز هم از A و B استفادده میکنیم. در سازنده B (کلاس فرزند) از کلمه کلیدی parent برای فراخوانی سازنده کلاس والد (A) استفاده میکنیم.
class A {
public $num_2;
function __construct($number) {
$this->num_2 = $number;
}
}
class B extends A {
public $num_1;
function __construct($number) {
parent::__construct($number);
$this->num_1 = $number;
}
function get_numbers() {
return 'Number1: ' . $this->num_1 . ' Number2: ' . $this->num_2;
}
}
$obj = new B(10);
echo $obj->get_numbers(); // خروجی: Number1: 10 Number2: 10
همانطور که میبینید عدد 10 که در هنگام ساخت نمونه از B به سازنده آن ارسال کردیم با استفاده از parrent::__construct($number)
به سازنده والد خود ارسال شد. اگر این دستور را در سازنده کلاس A نداشته باشیم، بنابراین سازنده کلاس A بعد از ایجاد نمونه ازکلاس B فراخوانی نمیشود.
نحوه استفاده از parent در کد مشخص است. بعد از کلمه کلیدی parent با استفاده از ::
و سپس نام اعضای کلاس والد را می آوریم. کاراکتر :: به عنوان عملگر تفکیک حوزه شناخته میشود.
کلاس های نوع final در php
برای جلوگیری از ارث بری یک کلاس می توان آن را به صورت final تعریف کرد.
final class A {
// ...
}
با این کار، هیچ کلاسی نمیتواند از کلاس A ارث بری انجام دهد و در صورت انجام این کار با یک اخطار مواجه میشوید.
final class A {
// ...
}
class C extends A {
// ...
}
$obj = new C();
// output: Fatal error: Class C may not inherit from final class (A) in /opt/lampp/htdocs/my_file_destination.php on line 9
متد های نوع final در php
همچنین در کلاس والد، می توانید برای جلوگیری از لغو یا override نشدن آن در کلاس فرزند، متد ها را با استفاده از کلمه کلیدی final تعریف کنید.
class A {
final function a1() {
echo 'Printed form A';
}
}
class C extends A {
function a1() {
echo 'Printed form C';
}
}
$o = new C();
$o->a1();
// output: Cannot override final method A::a1() in /opt/lampp/htdocs/my_file_destination.php on line 13
ما در کلاس A به صورت واضح متد a1 را final تعریف کردیم. این کار مشخص میکند که کلاس های فرزند حق لغو یا override کردن ندارند. اما همچنان مانند قبل می توانند به این متد ها دسترسی داشته باشند. مثال زیر نشان میدهد که میتوان با استفاده از نمونه ایجاد شده کلاس فرزند به متد final کلاس والد دسترسی داشت.
class A {
final function a1() {
echo 'Printed form class A, a1() ';
}
}
class C extends A {
// ...
}
$o = new C();
$o->a1();