inheritance در PHP شی گرا


آموزش وراثت / inheritance در PHP شی گرا

یکی از مزایای استفاده از تکنیک برنامه نویسی شی گرا برای توسعه ی اپلیکیشن های PHP، کاهش کدهای تکراری و اجتناب از نوشتن منطقی است که قبلا پیاده سازی شده. این کار با بهره گیری از مفهومی به نام inheritance امکان پذیر می باشد. code duplication زمانی رخ می دهد که برنامه نویس کدی که قبلا نوشته را برای بار دوم یا سوم پیاده سازی کرده و تکرار کند. Inheritance بر آن است تا همین معضل را برطرف نماید. در ارث بری، یک کلاس پدر (parent class) داریم که تعدادی متد و property دارد و یک کلاس فرزند یا مشتق (child) که قادرند از کد (اعضای) کلاس پدر استفاده کنند. در وراثت توسعه دهنده یک قطعه کد کارا با قابلیت استفاده ی مجدد تعبیه کرده و آن را در سطح کلاس پدر قرار می دهد. سپس از آن کد بارها (در بخش های مختلف پروژه) در قالب کلاس های فرزند یا مشتق شده از کلاس پدر بهره می گیرد.

آنچه خواهید آموخت:

  • یک کلاس چگونه می تواند کد کلاسی دیگر ار به ارث برده و استفاده کند.
  • چگونه یک کلاس می تواند متدها و property های اختصاصی خود (اضفه بر متدها و propertyاس والد) را داشته باشد.
  • با تنظیم کننده ی سطح دسترسی (access modifier) به نام protectedو کارایی آن آشنا شوید.
  • با نحوه ی بازنویسی (override) متدها و property های کلاس پدر در کلاس فرزند کاملا آشنا شوید.

چگونه یک کلاس از کلاس دیگر ارث بری می کند؟

Inheritance به توسعه دهنده این امکان را می دهد تا کد مورد نظر را یکبار داخل کلاس پدر نوشته، سپس آن را هم در کلاس پدر و هم در کلاس یا کلاس های فرزند مورد استفاده قرار داد.

برای اینکه مشخص کنیم یک کلاس می تواند اعضای کلاس دیگر را به ارث ببرد، در PHP از کلیدواژه ی extend استفاده می کنیم. ساختار نحوی آن به شرح زیر می باشد:

class Parent {    // The parent’s class code  }  class Child extends Parent {    // The  child can use the parent's class code  }  

کلاس فرزند می تواند تمامی متدها و فیلد هایی (property) از کلاس پدر را که با سطح دسترسی private تعریف نشده به ارث برده و مورد استفاده قرار دهد. این امکان توسعه دهنده را قادر می سازد تا کد را یکبار در کلاس سطح پدر نوشته و سپس آن را بارها در کلاس هایی که از آن ارث بری دارند، مورد استفاده قرار دهد (هم در کلاس پدر و هم در کلاس های فرزند).

در مثال زیر، SportsCar از کلاس Car ارث بری دارد، بنابراین می تواند به تمامی متدها و property هایی که با کلیدواژه ی private نشانه گذاری نشده اند، دسترسی داشته باشد. بدین وسیله توسعه دهنده متدهای setModel() و hello() که به صورت public تعریف شده اند را یکبار در کلاس پدر پیاده سازی کرده و سپس این متدها را هم در کلاس پدر و هم در کلاس های فرزند استفاده می کند.

//The parent class  class Car {    // Private property inside the class    private $model;    //Public setter method    public function setModel($model)    {      $this -> model = $model;    }    public function hello()    {      return "beep! I am a " . $this -> model . "
"; } } //The child class inherits the code from the parent class class SportsCar extends Car { //No code in the child class } //Create an instance from the child class $sportsCar1 = new SportsCar(); // Set the value of the class’ property. // For this aim, we use a method that we created in the parent $sportsCar1 -> setModel('Mercedes Benz'); //Use another method that the child class inherited from the parent class echo $sportsCar1 -> hello();

خروجی:

beep! I am a Mercedes Benz

چگونه یک کلاس فرزند می تواند متدها و property های اختصاصی خود را داشته باشد

کلاس فرزند می تواند علاوه بر متدها و property های کلاس پدر، توابع و فیلدهای اختصاصی خود را داشته باشد. این در حالی است که کلاس پدر نمی تواند از متدها و property های کلاس فرزند استفاده نماید.

در مثال زیر، داخل کلاس فرزند یک متد و property جدید تعریف می کنیم که در کلاس پدر موجود نبود. این اعضای جدید، فیلدهای اختصاصی کلاس فرزند (متغیر$style و متد driveItWithStyle()) محسوب می شوند:

// The parent class has its properties and methods  class Car {    //A private property or method can be used only by the parent.    private $model;    // Public methods and properties can be used by both the parent and the child classes.    public function setModel($model)    {      $this -> model = $model;    }    public function getModel()    {      return $this -> model;    }  }  //The child class can use the code it inherited from the parent class,   // and it can also have its own code   class SportsCar extends Car{    private $style = 'fast and furious';    public function driveItWithStyle()    {      return 'Drive a '  . $this -> getModel() . ' ' . $this -> style . '';    }  }  //create an instance from the child class  $sportsCar1 = new SportsCar();  // Use a method that the child class inherited from the parent class  $sportsCar1 -> setModel('Ferrari');  // Use a method that was added to the child class  echo $sportsCar1 -> driveItWithStyle();  

خروجی:

Drive a Ferrari fast and furious.

استفاده از تنظیم کننده ی سطح دسترسی protected

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

اگر بخاطر داشته باشید، متدها و property هایی که به صورت public تعریف شده اند از بیرون کلاس نیز قابل دسترسی هستند. همچنین عضوهایی از کلاس که با سطح دسترسی private اعلان شده اند، تنها داخل خود کلاس میزبان قابل دسترسی می باشند.

در مبحث حاضر می خواهیم به شرح access modifier دیگری به نام protected که امکان دسترسی را هم داخل کلاس پدر و در هم در کلاس های ارث بری شده از آن فراهم می کند، بپردازیم.

در مثال زیر $model را در کلاس پدر به صورت private تعریف کرده و سپس آن را در کلاس فرزند فراخوانی می کنیم. خواهید دید که در کد خطا رخ می دهد:

// The parent class  class Car {    //The $model property is private, thus it can be accessed     // only from inside the class    private $model;     //Public setter method    public function setModel($model)    {      $this -> model = $model;    }  }  // The child class  class SportsCar extends Car{    //Tries to get a private property that belongs to the parent    public function hello()    {      return "beep! I am a " . $this -> model . "
"; } } //Create an instance from the child class $sportsCar1 = new SportsCar(); //Set the class model name $sportsCar1 -> setModel('Mercedes Benz'); //Get the class model name echo $sportsCar1 -> hello();

خروجی:

Notice: Undefined property: SportsCar::$model

همان طور که در خروجی مشاهده می کنید، کد برنامه خطا می دهد چراکه متد hello() در کلاس فرزند سعی دارد به property کلاس پدر ($model) که به صورت private تعریف شده، دست پیدا کند.

برای رفع این مشکل کافی است property نام برده را داخل کلاس پدر با کلیدواژه ی protected اعلان نمایید. بدین وسیله عضو مورد نظر علاوه بر اینکه داخل کلاس پدر قابل دسترسی است بلکه می توان در کلاس فرزند نیز آن را فراخوانی کرد.

// The parent class  class Car {    //The $model property is now protected, so it can be accessed     // from within the class and its child classes    protected $model;    //Public setter method    public function setModel($model)    {      $this -> model = $model;    }  }  // The child class  class SportsCar extends Car {    //Has no problem to get a protected property that belongs to the parent    public function hello()    {      return "beep! I am a " . $this -> model . "
"; } } //Create an instance from the child class $sportsCar1 = new SportsCar(); //Set the class model name $sportsCar1 -> setModel('Mercedes Benz'); //Get the class model name echo $sportsCar1 -> hello();

خروجی:

beep! I am a Mercedes Benz

همان طور که می بینید، عضو اعلان شده با سطح دسترسی protected نه تنها در کلاس پدر بلکه در کلاس مشتق (فرزند) نیز قابل استفاده می باشد.

نحوه بازنویسی (override) property ها و متدهای کلاس پدر در کلاس فرزند

پیش تر توضیح دادیم که کلاس مشتق می تواند متدها و property های اختصاصی خود را اضافه بر متدها و property های کلاس پدر داشته باشد. می توان متدها و property های کلاس پدر را در بدنه ی کلاس فرزند بازنویسی کرد. زمانی که یک متد یا property کلاس پدر را داخل کلاس فرزند override می کنیم، در واقع عین همان property یا متد را بار دیگر داخل کلاس فرزند می نویسیم با این تفاوت که داخل بدنه ی فرزند مقدار یا کد متفاوتی را به آن تخصیص می دهیم.

در مثال زیر، یک متد به نام hello() در کلاس پدر تعریف می کنیم که رشته ی “beep” را بازگردانی می کند. سپس این متد را در کلاس فرزند طوری بازنویسی می کنیم که بجای رشته مذکور، مقدار متنی “Halllo” را برگرداند:

// The parent class has hello method that returns "beep".  class Car {    public function hello()    {      return "beep";    }  }  //The child class has hello method that returns "Halllo"  class SportsCar extends Car {    public function hello()    {      return "Hallo";    }  }  //Create a new object  $sportsCar1 = new SportsCar();  //Get the result of the hello method  echo $sportsCar1 -> hello();  

خروجی:

Halllo

از خروجی کد بر می آید که پیاده سازی یا بدنه ی متد hello() از کلاس پدر، داخل کلاس فرزند بازنویسی شده است.

چگونه می توان از بازنویسی متد کلاس پدر در کلاس فرزند جلوگیری کرد؟

می توان با درج کلیدواژه ی final قبل از متد مورد نظر در کلاس پدر، از بازنویسی آن در بدنه ی کلاس فرزند جلوگیری کرد.

در نمونه ی زیر مشاهده می کنید که متد hello() در سطح کلاس پدر با final تعریف شده و در کلاس فرزند سعی بر بازنویسی بدنه ی آن می کنیم. خواهید دید که به هنگام جرای برنامه در کد خطا رخ می دهد:

// The parent class has hello method that returns "beep".  class Car {    final public function hello()    {      return "beep";    }  }  //The child class has hello method that tries to override the hello method in the parent  class SportsCar extends Car {    public function hello()    {      return "Hallo";    }  }  //Create a new object  $sportsCar1 = new SportsCar();  //Get the result of the hello method  echo $sportsCar1 -> hello();  

خروجی:

Fatal error: Cannot override final method Car::hello()

از آنجایی که متد ()hello را در کلاس پدر به صورت final و غیر قابل ویرایش تعریف کردیم، امکان بازنویسی منطق آن در کلاس فرزند وجود ندارد.

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *