برنامه نویسی شی گرا   

از دانشنامه جوملا فارسی - مامبو فارسی
نسخهٔ تاریخ ‏۲۱ ژانویهٔ ۲۰۱۲، ساعت ۱۶:۵۱ توسط Shmata (بحث | مشارکت‌ها) (شی Object)

پرش به: ناوبری، جستجو

برنامه نویسی شی گرا در PHP با رویکرد آموزشی برای جوملا

PHP یک زبان برنامه نویسی شی گرا ست و همچنین از ساختار MVC برای پیاده سازی جوملا استفاده کرده است . برای توسعه جوملا درک قوی مفاهیم برنام نویسی شی گرا (OOP) لازم است . در این مقاله سعی داریم دلایل استفاده از Objectها و راههای استفاده از Objectهایی که PHP از آنها استفاده میکند را توضیح دهیم .
این موضوع برای ما به عنوان برنامه نویسی که قصد فراگیری برنامه نویسی شی گرا را داریم مهم است که دلایل استفاده از شی گرایی را بدانیم .
قبل از شی گرایی تمام برنامه ها بر اساس توابع (Function) و متغیرها (Variables) بود . مثلا اگر قرار باشد برنامه محاسبه ارتباط قد و وزن یک شخص BMI یک شخص را بدون استفاده از شی گرایی بنویسیم به سه متغیر $weight و $height و $name نیاز داریم که برای نگهداری وزن و قد و نام شخص مورد استفاده قرار میگیرند . همچنین به یک تابع مثلا calculateBMI() برای محاسبه قد و وزن نیاز داریم که باید پارامترهای $height و $weight را بپذیرد . که به این صورت نوشته میشود.
<source lang="php " > function calculateBMI( $height, $weight ) {

   return $weight / $height;

} </source> مشکل این روش اینست که در صورت تعدد توابع و متغیرها (که عموما در پروژه ها به دفعات مجبور به استفاده از آنها هستیم) قادر به تعقیب کد برنامه نخواهیم بود و برنامه نوشته برای سایر افرادی که قصد توسعه آن را داشتند گیج کننده بود . به این نوع کد نویسی برنامه نویسی اسپاگتی میگویند از این جهت که خروجی هر تابع ممکن است به عنوان ورودی یا ... در سایر توابع مورد استفاده قرار گیرد که ردیانی کدها را بسیار دشوار می سازد .

کلاس class

برای Objectها ایده encapsulate به منظور تغییر در function ها در داخل یک بسته (package) مطرح شددر واقع این بسته همان کلاس(class) میباشد. به عنوان مثال پیاده سازی مثال بالا با استفاده از کلاس به صورت زیر خواهد بود :
<source lang="php " > class person {

   var $name;
   var $height;
   var $weight;

   function getBMI() {
       return $this->weight / $this->height;
   }

} </source>

نمونه سازی instantiating

برای استفاده از توابع موجود کلاس ها (method) و متغیرهای داخل کلاس , ما باید حتما یک object از نوع آن کلاس ایجاد کنیم . به عنوان مثال اگر شما قصد دارید یک object بسازید که نشان دهنده کلاس person باشد (یعنی با استفاده از آن object بخواهید از متد و متغیرهای داخل کلاس person استفاده کنید) باید به صورت زیر عمل کنید : <source lang="php " > $person = new person(); </source> به ایجاد یک object از نوع یک کلاس instantiating میگویند چون در واقع یک نمونه instance از آن کلاس است . یک کلاس توسط یک شی مورد دسترسی قرار میگیرد.

خصوصیت property

شما با استفاده از object ها میتوانید به مقادیر متغیرهای یک کلاس (properties) را تغییر دهید به این صورت : <source lang="php " > $person->height = 2; $person->weight = 50; </source> همچنین شما میتوانید با استفاده از object توابع (method) ها را فراخوانی کنید : <source lang="php " > $bmi = $person->getBMI(); </source>

وراثت inheritance

در پروژه ها معمولا خیلی از کلاسها شبیه به هم هستند اما مواردی هم وجود دارد که در داخل یک کلاس تفاوتهای زیادی با دیگر کلاسها وجود دارد به عنوان مثال : هم انسانها و هم حیوانات مثل گربه همگی شش دارند برای تنفس . از نظر OOP هر دوی آنها یک متغیر به نام $lung_capacity دارند که بین شان مشترک است ولی گربه دارای دم است که انسانها ندارند پس قاعدتا کلاس حیوانات باید دارای یک متغیر بیشتر به نام $tail_length باشد . پس در پروژه ما کلاس حیوانات تمام خصوصیات کلاس انسانها را دارد ولی با یکسری خصوصیات بیشتر (دم) . به کلاس انسانها Parent و به کلاس حیوانات Child یا Subclass میگوییم.
نکته : کلاسهای فرزند (Child) تمام خصوصیات کلاسهای والد (Parent) را دارند به علاوه یکسری خصوصیات بیشتر.
در جوملا اکثر کلاس ها فرزند کلاس JObject هستند. یعنی باید تمام خصوصیتهای کلاس JObject را داشته باشند به علاوه یکسری خصوصیات بیشتر.
<source lang="php " > class person extends JObject {

   var $name;
   var $height;
   var $weight;

   function getBMI() {
       return $this->weight / $this->height;
   }

} </source> کلاس JObject دارای متدهای set() و get() است که ما با استفاده از این متدها براحتی میتوانیم کلاس person را تغییر دهیم دقت کنید که ما در کلاس person متدهای set() و get() را نداریم ولی چون کلاس person فرزند کلاس JObject است ما میتوانیم از متدهای JObject نیز استفاده کنیم . به عمل در شی گرایی وراثت میگویند . وراثت(inheritance) با کلمه کلیدی extends مشخص می شود و الگوی آن در مثال بالا مشخص است .
کلاس JObject دارای متدهای set() و get() است که ما با استفاده از این متدها براحتی میتوانیم کلاس person را تغییر دهیم دقت کنید که ما در کلاس person متدهای set() و get() را نداریم ولی چون کلاس person فرزند کلاس JObject است ما میتوانیم از متدهای JObject نیز استفاده کنیم . به عمل در شی گرایی وراثت میگویند . وراثت(inheritance) با کلمه کلیدی extends مشخص می شود و الگوی آن در مثال بالا مشخص است .

توجه داشته باشید که $this در داخل کلاسها زیاد استفاده میشود در واقع $this به object جاری اشاره میکند . بنابراین اگر در داخل یک کلاس از
$this -> height = 2;
استفاده کنیم به این معنی است که خصوصیت height شی جاری برابر 2 ست شده است و وقتی که ما در کد از
$this->height
استفاده میکنیم به هیچ عنوان درباره مقدار height صحبت نکرده ایم بلکه راجب شی جاری height صحبت کرده ایم .

در مورد اشیا (object)ها بیشتر بدانیم

همانطور که گفتیم اشیا object نامیده میشوند به این دلیل : اگر در زندگی واقعی یک شی مثل یک دستگاه فتوکپی را تصور کنیم یک رابط خارجی دارد (مانند : یک سینی کاغذ و شیشه دستگاه کپی و صفحه کلید و ...)

متد method

یک کلاس به اسم copier داریم , چه عملیاتی را به طور معمول نیازداریم که برروی copier انجام دهیم ؟ یکی از مهم ترین کارهایی که این کلاس باید انجام دهد قابلیت کپی است پس من نیاز به یک متد با قابلیت کپی دارم و اسم آنرا copy میگذارم . <source lang="php " > class Copier {

   function copy() {
       echo 'One copy made';
   }

} </source> اینک این یک کلاس کپی کننده ی کاملا ابتدایی است . به نظر شما چه قابلیتها دیگری برای توسعه این کلاس نیاز داریم ؟ خوب برای توسعه قابلیتهای این کلاس باید یک کلاس فرزند از Copier ایجاد کنیم چون کلاس فرزند تمام قابلیتهای کلاس والد را به ارث میبرد و یک سری قابلیتهای دیگر به آن میافزاید و این همان چیزی است که ما میخواهیم . ما میخواهیم یک کلاس کپی دیگری ایجاد کنیم که آن کلاس تعداد کپی های گرفته شده را در خود نگه میدارد به این منظور به یک property نیاز داریم تا بتواند این خصوصیت (تعداد کپی های گرفته شده) را در خود حفظ کند بدین ترتیب که هرزمان کپی جدیدی گرفته شد یک واحد به آن اضافه گردد. کد کلاس فرزند کلاس copier به این صورت است : <source lang="php " > class CopierWithCounter extends Copier {

   var $counter;

   function copy() {
       $this->counter++;
       parent::copy();
   }

} </source> اینک ما یک خصوصیت به نام $counter داریم که تعداد کپی های گرفته شده در خود نگهداری میکند. توجه کنید که در کلاس فرزند (CopierWithCounter) یک متد وجود دارد به نام copy() یک متد دیگر هم با همین نام در کلاس پدر وجود دارد معنی این کار چیست ؟ به کد داخل متد copy() کلاس فرزند توجه نمایید در یک خط آن داریم

parent::copy();

parent یک کلمه کلیدی در PHP است که به کلاس پدر یا کلاس والد (parent class) اشاره میکند که در این مثال به Copier اشاره میکند.
بنابراین ما قابلیت مشابه کلاس Copier را داریم با ابن تفاوت که به ازای هر کپی یک واحد به شمارنده اضافه میکند.

مقدار دهی اولیه initialize

اگر اقدام به trace کردن این کلاس کرده باشد یک سوال برای شما مطرح میشود که مقدار اولیه $counter چقدر است ؟ ما فقط میدانیم که به این متغیر به ازای هر کپی یک مقدار اضافه میشود ولی از مقدار اولیه آن هیچ اطلاعی نداریم . این متغیر نیاز دارد که مقدار دهی اولیه شود (initialize) .
عمل مقدار دهی اولیه به متغیرهای کلاس توسط constructor انجام میشود . در واقع کار اصلی constructor همین است (مقدار دهی اولیه به متغیرها). constructorها در PHP4.0 توابعی هم نام با کلاس بودند یعنی مثلا اگر اسم کلاس Copy بود اسم constructor یک تابع به نام copy() میشد اما در PHP5.0 کانستراکتور با تابعی به نام

__constructor()
مشخص میشود. ما در جوملا و ادامه این آموزش نیز از
__constructor()

استفاده خواهیم کرد. بنابراین کلاس ما به صورت کد زیر تغییر خواهد کرد . <source lang="php " > class CopierWithCounter extends Copier {

   var $counter;

   function __construct() {
       $this->counter = 0;
   }

   function copy() {
       $this->counter++;
       parent::copy();
   }

} </source> ما میخواهیم که یک کلاس copier پیشرفته تر ایجاد کنیم . میخواهیم یک کلاس فرزند دیگر ایجاد کنیم . میخواهیم کلاس کپی ای ایجاد کنیم که توانایی کپی کردن نسخه متعددی را داشته باشد . ما نیاز به این داریم که مشخص کنیم چقدر کپی میخواهیم بگیریم ویک راهی که این تعداد را برای ما نگهداری کنید به این منظور متدی به نام setCopies() را اضافه میکنیم . <source lang="php " > class CopierMultipleCopies extends CopierWithCounter {

   var $copies;

   function setCopies( $copies ) {
       $this->copies = $copies;
   }

} </source> اینک ما توانستیم مشخص کنیم چه تعداد کپی میخواهیم بگیریم .
در شی گرایی مفهومی به نام scope وجود دارد که وقتی ما در مورد scope صحبت میکنیم منظورمان محدوده ای است که متغیرها میتوانند دیده و استفاده شوند . به کلاسمان توجه کنید یک property داریم که $copies (متغیر داخل کلاس) نام دارد همچنین در داخل متد setCopies نیز یک پارامتر داریم که $copies (متغیر ورودی به متد) نام دارد .

overriding

اگر یک متد پارامترهایی (متغیر ورودی به متد) داشته باشد مانند $copies در متدبالا . اگر من بخواهم از $copies در داخل آن متد استفاده کنم من باید به آن پارامتر مراجعه کنم ($this) ممکن متغیرهای دیگری در قسمت های مختلف کلاس وجود داشته باشند و حتی ممکن است اسم آن متغیرها $copies باشد. آنها برای ما هیچ اهمیتی ندارند اگر من بخواهم به یک property از شی جاری مراجعه کنم باید از کلمه کلیدی $this استفاده کنم . بنا براین اگر از

$this -> copies

استفاده کنیم به منظورما خصوصیت $copies است که به شی جاری تعلق دارد.
متد setCopies یک پارامتر ورودی به نام $copies دارد که در داخل آن شی copiesذخیره میشود.
همچنین در کنار متد setCopies میخواهیم تعداد کپی های گرفته شده را ذخیره کنیم . توجه داشته باشید که برای کلاس CopierMultipleCopies متد copy() یا constructor ای تعریف نشده است اما بدلیل extends کردن آن از کلاس CopierWithCounter متد copy() و propertyهای دیگر را از کلاس CopierWithCounter به ارث میبرد بنابراین بدون انجام هیچ کار اضافه ما یک Copier با شمارنده داریم .
قصد داربم همچنان قابلیتهای متد copy() را که اینک قادر به گرفتن کپی های متعدد است توسعه دهیم به این منظور یک متد و یک constructor (که به متغیر ما مقدار اولیه دهد) به کلاسمان اضافه میکنیم . <source lang="php " > class CopierMultipleCopies extends CopierWithCounter {

   var $copies;

   function __construct() {
       $this->copies = 1;
       parent::__construct();
   }

   function setCopies( $copies ) {
       $this->copies = $copies;
   }

   function copy() {
       for ($i = 0; $i < $this->copies; $i++) {
           parent::copy();
       }
   }

} </source> در این کد ما دقیقا چه کاری انجام دادیم ؟ در ابتدا ما یک constructor داریم که به متغیر $copies مقدار اولیه 1 را میدهد . بعد ....
بناراین ما متد copy() را override کردیم . در داخل متد copy() کلاس CopierMultipleCopies یک حلقه تکرار داریم .
در خط اول در داخل حلقه تکرار سه بخش مجزا داریم که با semicolon از هم جدا میشوند .
قسمت اول برای مقدار دهی اولیه(intializing) است ما میخواهیم از $i به عنوان شمارنده استفاده کنیم و لازم است که این متغیر بتواند تعداد کپی ها را در خود نگهداری پس باید به آن مقدار اولیه اختصاص دهیم و به آن مقدار 0 را اختصاص میدهیم .
قسمت دوم مربوط به شرط(condition) است . قبل از انجام هر عملی در حلقه تکرار for این شرط بررسی میگردد اگر true بود حلقه تکرار اجرا میشوند.
قسمت آخر افزایش دهنده(increamentor) . این قسمت پس از هربار اجرای حلقه یکبار اجرا میشود.
آن باید به صورت زیر اجرا شود :

• ساختن یک متغیر و مقدار دهی اولیه آن 0
• چک کردن شرط حلقه
• اجرای دستورات داخل حلقه (ایجاد یک copy)
• سپس مقدار افزاینده به متغیر اضافه میشود و به مرحله دوم میرود.

شما میتوانید حلقه های تکرار به مراتب پیچیده تری ایجاد کنید . این حلقه تنها یک نمونه آموزشی است .
حال میتوانیم از copier استفاده کنیم .ما باید به این منظور از کدهای مانند کدهایی زیر استفاده کنیم : <source lang="php " > $copier = new CopierMultipleCopies(); $copier->copy(); $copier->copy(); $copier->setCopies( 10 ); $copier->copy(); </source> این آموزش ادامه دارد
منبع : http://docs.joomla.org/Getting_Started_with_Object_Oriented_Programming

ترجمه: شهاب مطاع پور

Indent support.png
هر گونه سوال و یا مشکلی در این رابطه دارید، می‌توانید در انجمن تخصصی تیم جوملا فارسی جستجو کرده و در صورت عدم دریافت نتیجه مورد نظر، سوال جدیدی را مطرح کنید.
8.pngاستفاده از مطالب دانشنامه جوملا فارسی - مامبو فارسی با ذکر منبع ( دانشنامه جوملا فارسی ) و لینک مستقیم به http://docs.joomlafarsi.com بلامانع است.