شی گرایی در PHP و توضیح مفهوم کلاس و شی — به زبان ساده
در این مقاله قصد داریم مبانی مفهوم کلاس و شی گرایی در PHP را بررسی کنیم. در ابتدا به معرفی کلاسها و شیءها خواهیم پرداخت و چند مفهوم پیشرفته مانند وراثت و چندریختی را در ادامه مورد بررسی قرار میدهیم. همچنین، لازم به ذکر است که یکی از موارد استفاده PHP در آموزش برنامه نویسی USSD است.
برنامهنویسی شیءگرا (OOP) یعنی چه؟
برنامهنویسی شیءگرا که به طور معمول به نام OOP شناخته میشود، رویکردی است که به ما کمک میکند تا اپلیکیشنهای پیچیده را به طرزی بنویسیم که به سادگی قابل نگهداری بوده و در بلند مدت مقیاسپذیر باشند. در دنیای OOP، با موجودیتهای دنیای واقعی مانند Person, Car یا Animal به عنوان شیء رفتار میشود. در برنامهنویسی شیءگرا ما با اپلیکیشنها از طریق استفاده از شیءها تعامل داریم. این وضعیت مخالف برنامهنویسی رویهای است که در آن به طور عمده با تابعها و متغیرهای سراسری سر و کار داریم.
در OOP مفهومی به نام کلاس وجود دارد که برای مدلسازی یا نگاشت موجودیتهای دنیای واقعی به یک قالب از دادهها (مشخصات) و کارکردها (متدها) استفاده میشود. شیء (object) وهلهای از یک کلاس محسوب میشود و میتوان چندین وهله از یک کلاس داشت. برای نمونه ممکن است یک کلاس منفرد person وجود داشته باشد؛ اما اشیای زیادی به صورت افراد مختلف با نامهای dan, zainab, hector و غیره، وهلههایی از این کلاس باشند.
مشخصات شیء در کلاس ارائه میشود. برای نمونه کلاس فرد (person) میتواند دارای مشخصات نام (name)، سن (age) و شماره تلفن (phoneNumber) باشد. هر شیء فرد مقادیر خاص خود را برای آن مشخصات خواهد داشت.
همچنین میتوان متدهایی را در کلاس تعریف کرد که امکان دستکاری مقادیر مشخصات شیء و اجرای عملیات روی اشیا را فراهم میسازد. به عنوان نمونه میتوان یک متد save تعریف کرد که اطلاعات شیء را در پایگاه داده ذخیره کند.
کلاس PHP چیست؟
یک کلاس به عنوان قالبی است که موجودیتهای دنیای واقعی را نمایندگی میکند و به تعریف مشخصات و متدهای موجودیت میپردازد. در این بخش به بررسی آناتومی مقدماتی یک کلاس معمول PHP میپردازیم.
بهترین روش برای درک مفاهیم جدید از طریق بررسی مثالها است. بنابراین در قطعه کدی که در ادامه آمده است، یک کلاس PHP به نام Employee ارائه کردهایم که موجودیت یک کارمند (employee) را نمایش میدهد:
<?php class Employee { private $first_name; private $last_name; private $age; public function __construct($first_name, $last_name, $age) { $this->first_name = $first_name; $this->last_name = $last_name; $this->age = $age; } public function getFirstName() { return $this->first_name; } public function getLastName() { return $this->last_name; } public function getAge() { return $this->age; } } ?>
گزاره class Employee در خط اول به تعریف کلاس Employee میپردازد. سپس اقدام به اعلان مشخصات، سازنده (constructor) و دیگر متدهای کلاس میکنیم.
مشخصات کلاس در PHP
مشخصات کلاس را میتوان به صورت متغیرهایی تصور کرد که اطلاعاتی را در مورد شیء نگهداری میکنند. در مثال فوق به تعریف سه مشخصه نام (first_name)، نام خانوادگی (last_name) و سن (age) پرداختیم. در اغلب موارد مشخصات کلاس از طریق شیءهای وهلهسازی شده مورد دسترسی قرار میگیرند.
این مشخصات به صورت خصوصی (private) هستند، یعنی دسترسی به آنها صرفاً از درون کلاس میسر است. این امنترین سطح دسترسی برای مشخصات است. ما در ادامه به بررسی سطوح مختلف دسترسی به مشخصات کلاس و متدها خواهیم پرداخت.
سازندهها در کلاسهای PHP
یک سازنده (constructor) متد خاصی در کلاس است که به طور خودکار هنگام وهلهسازی از یک شیء ایجاد میشود. شیوه وهلهسازی از اشیا را در بخشهای بعدی خواهیم دید؛ اما در حال حاضر کافی است بدانیم که یک متد سازنده برای مقداردهی اولیه مشخصات شیء، هنگام ایجاد شدن آن مورد استفاده قرار میگیرد. میتوان یک سازنده را از طریق تعریف کردن متد construct__ تعریف کرد.
متدهای کلاسهای PHP
متدهای کلاس را میتوان به صورت تابعهایی تصور کرد که کارهای خاصی را در ارتباط با شیءها انجام میدهند. در اغلب موارد از این متدها برای دسترسی و دستکاری مشخصات شیء و اجرای عملیات مرتبط استفاده میشود.
در مثال فوق متد getLastName را تعریف کردهایم که نام خانوادگی مرتبط با شیء را باز میگرداند. بدین ترتیب تلاش کردیم تا توضیح مختصری در مورد ساختار کلاس در PHP ارائه کنیم. در بخش بعدی خواهیم دید که چگونه میتوانیم شیءهایی را به صورت وهلههایی از کلاس Employee ایجاد کنیم.
شیء در PHP به چه معنا است؟
در بخش پیشین به بررسی ساختار مقدماتی یک کلاس در PHP پرداختیم.
اینک زمان آن رسیده است که از کلاس به صورت عملی استفاده کنیم. به این منظور باید وهلهای از آن ایجاد کنیم و نتیجه نهایی یک شیء خواهد بود. بنابراین کلاس را میتوان یک طرح اولیه دانست و شیء یک چیز واقعی است که میتوان با آن کار کرد. اگر بخواهیم در همان چارچوب کلاس Employee که در بخش قبل تعریف کردیم صحبت کنیم، باید به روش زیر یک شیء از آن کلاس را وهلهسازی کنیم.
<?php $objEmployee = new Employee('Bob', 'Smith', 30); echo $objEmployee->getFirstName(); // print 'Bob' echo $objEmployee->getLastName(); // prints 'Smith' echo $objEmployee->getAge(); // prints '30' ?>
بدین منظور میبایست از کلیدواژه new برای وهلهسازی یک شیء از یک کلاس به همراه نام آن کلاس استفاده کرد تا یک وهله جدید شیء از آن کلاس بازگشت یابد.
اگر در کلاسی متد construct__ تعریف شده و نیازمند آرگومانهایی باشد، باید آن آرگومانها هنگام وهلهسازی از کلاس به آن ارسال شوند. در مورد مثال ما؛ سازنده کلاس Employee نیازمند سه آرگومان است و از این رو این سه آرگومان در زمان ایجاد شیء objEmployee$ به آن ارسال شدهاند. همان طور که قبلاُ گفتیم، متد construct__ به طور خودکار هنگام ایجاد وهله از کلاس فراخوانی میشود.
سپس متدهای کلاس را روی شیء objEmployee$ فراخوانی میکنیم تا اطلاعاتی را که در زمان ایجاد شیء ارسال کردهایم نمایش دهند. البته میتوان چندین شیء از یک کلاس واحد ایجاد کرد که چگونگی آن در قطعه کد بعدی نمایش یافته است.
<?php $objEmployeeOne = new Employee('Bob', 'Smith', 30); echo $objEmployeeOne->getFirstName(); // prints 'Bob' echo $objEmployeeOne->getLastName(); // prints 'Smith' echo $objEmployeeOne->getAge(); // prints '30' $objEmployeeTwo = new Employee('John', 'Smith', 34); echo $objEmployeeTwo->getFirstName(); // prints 'John' echo $objEmployeeTwo->getLastName(); // prints 'Smith' echo $objEmployeeTwo->getAge(); // prints '34' ?>
تصور زیر بازنمایی گرافیکی از کلاس Employee و برخی وهلههای آن است.
به بیان سادهتر کلاس یک طرح اولیه است که میتوان از آن برای ایجاد شیءهای ساختیافته استفاده کرد.
کپسولهسازی (Encapsulation)
در بخش پیشین در مورد چگونگی وهلهسازی اشیا از کلاس Employee صحبت کردیم. شاید جالب باشد بدانید که شیء Employee خودش یک پوشش برای مشخصات و متدهای کلاس محسوب میشود. به بیان دیگر این شیء جزییات فوق را از دید بخشهای دیگر برنامه پنهان میکند. در دنیای برنامهنویسی شیءگرا این وضعیت به نام کپسولهسازی دادهها نامیده میشود.
کپسولهسازی یا Encapsulation جنبه مهمی از برنامهنویسی شیءگرا است که امکان محدودسازی دسترسی به مشخصات یا متدهای شیء را میسر میسازد و به این ترتیب به موضوع بحث یعنی سطوح دسترسی میرسیم.
سطوح دسترسی
زمانی که به تعریف مشخصات یا متد یک کلاس میپردازیم، میتوانیم آن را با یکی از سطوح دسترسی عمومی (public)، خصوصی (private) یا حفاظتشده (protected) اعلان کنیم.
دسترسی عمومی
وقتی که یک مشخصه یا متد به صورت عمومی اعلان میشود، میتوان از هر جایی در خارج از کلاس به آن دسترسی داشت. مقدار یک مشخصه عمومی میتواند از هر جایی در کد تغییر یابد. برای درک سطح دسترسی عمومی به مثال زیر توجه کنید:
<?php class Person { public $name; public function getName() { return $this->name; } } $person = new Person(); $person->name = 'Bob Smith'; echo $person->getName(); // prints 'Bob Smith' ?>
همان طور که در مثال فوق میبینید، ما مشخصه name را به صوت عمومی اعلان کردهایم. از این رو میتوان آن را در هر جایی خارج از کلاس مشاهده کرد و ما نیز چنین کردهایم.
دسترسی خصوصی
وقتی یک مشخصه یا متد را به صوت خصوصی اعلان میکنیم، این مشخصه یا متد تنها از درون همان کلاس قابل دسترسی است. این بدان معنی است که باید متدهای getter و setter تعریف کنید تا بتوانید مقدار آن مشخصه را دریافت کرده یا تنظیم کنید. در این مورد نیز با بازبینی مثال قبلی، نمونه کدی برای درک بهتر سطح دسترسی خصوصی ارائه کردهایم:
<?php class Person { private $name; public function getName() { return $this->name; } public function setName($name) { $this->name = $name; } } $person = new Person(); $person->name = 'Bob Smith'; // Throws an error $person->setName('Bob Smith'); echo $person->getName(); // prints 'Bob Smith' ?>
اگر تلاش کنید به یک مشخصه خصوصی از جایی خارج از کلاس دسترسی داشته باشید، با خطای مهمی به صورت Cannot access private property Person::$name مواجه میشوید. از این رو باید مقدار مشخصه خصوصی را با استفاده از متد setter تعیین کنید و ما نیز این کار را با بهرهگیری از متد setName انجام دادهایم.
دلایل خوبی برای این که چرا باید یک مشخصه را خصوصی اعلان کرد وجود دارند. برای نمونه شاید لازم باشد در صورت تغییر یافتن یک مشخصه، برخی اقدامهای خاص مانند بهروزرسانی پایگاه داده یا رندر گیری مجدد از یک قالب انجام یابند. در این حالت میتوان یک متد setter تعریف کرد و هر منطق خاصی که در زمان تغییر یافتن یک مشخصه مورد نیاز است را در آن جا پیادهسازی کرد.
دسترسی حفاظت شده
در نهایت هنگامی که یک مشخصه یا متد به صورت حفاظتشده (protected) اعلان میشود، میتوان آن را از طریق همان کلاسی که آن را تعریف کرده و کلاسهایی که از کلاس موصوف ارثبری کردهاند، مورد دسترسی قرار داد. موضوع وراثت در بخش بعدی این نوشته بررسی شده است و از این رو در مورد سطح دسترسی حفاظتشده در ادامه بیشتر صحبت خواهیم کرد.
وراثت (Inheritance)
وراثت جنبه مهمی از پارادایم برنامهنویسی شیءگرا است که امکان به ارث رسیدن مشخصات و متدها از کلاسهای دیگر و از طریق بسط دادن آنها را فراهم میسازد. کلاسی که به ارث میرسد به نام کلاس والد (parent class) و کلاسی که از کلاس دیگر چیزهایی را به ارث میبرد به نام کلاس فرزند (child class) نامیده میشوند. زمانی که یک شیء از کلاس فرزند به ارث میرسد، مشخصات و متدهای کلاس والد را نیز با خود به ارث میبرد. در تصویر زیر میتوانید مفهوم وراثت را به صورت گرافیکی مشاهده کنید.
در مثال فوق کلاس Person کلاس والد است و Employee کلاسی است که از کلاس Person به ارث میبرد و از این رو کلاس فرزند نام میگیرد. برای درک بهتر کارد وراثت به مثال عملی زیر توجه کنید.
<?php class Person { protected $name; protected $age; public function getName() { return $this->name; } public function setName($name) { $this->name = $name; } private function callToPrivateNameAndAge() { return "{$this->name} is {$this->age} years old."; } protected function callToProtectedNameAndAge() { return "{$this->name} is {$this->age} years old."; } } class Employee extends Person { private $designation; private $salary; public function getAge() { return $this->age; } public function setAge($age) { $this->age = $age; } public function getDesignation() { return $this->designation; } public function setDesignation($designation) { $this->designation = $designation; } public function getSalary() { return $this->salary; } public function setSalary($salary) { $this->salary = $salary; } public function getNameAndAge() { return $this->callToProtectedNameAndAge(); } } $employee = new Employee(); $employee->setName('Bob Smith'); $employee->setAge(30); $employee->setDesignation('Software Engineer'); $employee->setSalary('30K'); echo $employee->getName(); // prints 'Bob Smith' echo $employee->getAge(); // prints '30' echo $employee->getDesignation(); // prints 'Software Engineer' echo $employee->getSalary(); // prints '30K' echo $employee->getNameAndAge(); // prints 'Bob Smith is 30 years old.' echo $employee->callToPrivateNameAndAge(); // produces 'Fatal Error' ?>
نکته مهم که باید به خاطر داشت این است که کلاس Employee از کلیدواژه extends برای به ارث بردن کلاس Person استفاده کرده است. اکنون کلاس Employee میتواند همه مشخصات و متدهای کلاس Person را که به صورت عمومی یا حفاظتشده اعلان شدهاند را مورد دسترسی قرار دهد. با این وجود به اعضایی از آن کلاس که به صورت خصوصی اعلان شدهاند، دسترسی ندارد.
در مثال فوق، شیء employee$ میتواند به متدهای getName و setName که در کلاس Person تعریف شدهاند، دسترسی داشته باشد، چون آنها به صورت عمومی اعلان شدهاند. سپس با استفاده از متد getNameAndAge که در کلاس Employee تعریف شده است، به متد callToProtectedNameAndAge دسترسی مییابیم، زیرا این متد نیز به صوت حفاظتشده اعلان شده است. در نهایت باید گفت که شیء Person به متد callToPrivateNameAndAge در کلاس Person دسترسی ندارد، زیرا به صورت خصوصی اعلان شده است.
از سوی دیگر میتوان از شیء employee$ برای تعیین مشخصه age کلاس Person استفاده کرد و این کار در متد setAge که در کلاس Employee تعریف شده صورت میگیرد، زیرا مشخصه Age به صورت حفاظتشده اعلان شده است. بدین ترتیب به پایان این معرفی کوتاه از وراثت میرسیم. وراثت به ما کمک میکند که کدهای تکراری کمتری بنویسیم و از این رو قابلیت استفاده مجدد از کد را افزایش میدهد.
چندریختی (Polymorphism)
چندریختی نیز یکی دیگر از جنبههای مهم دنیای برنامهنویسی شیءگرا به حساب میآید که اشاره به توانایی پردازش شیءها به روشهای متفاوت بر مبنای انواع دادههایشان دارد. برای نمونه در چارچوب وراثت اگر کلاس فرزند بخواهد رفتار کلاس والد خود را تغییر دهد، میتواند آن متد را باطل (override) کند. این وضعیت به نام overriding نامیده میشود. در مثال عملی زیر میتوانید به خوبی مفهوم باطل کردن یک متد را مشاهده کنید.
<?php class Message { public function formatMessage($message) { return printf("<i>%s</i>", $message); } } class BoldMessage extends Message { public function formatMessage($message) { return printf("<b>%s</b>", $message); } } $message = new Message(); $message->formatMessage('Hello World'); // prints '<i>Hello World</i>' $message = new BoldMessage(); $message->formatMessage('Hello World'); // prints '<b>Hello World</b>' ?>
همان طور که مشاهده میکنید، ما رفتار متد formatMessage را با اُورراید کردن آن در کلاس BoldMessage تغییر دادهایم. نکته مهم این است که در این حالت یک پیام بر اساس نوع شیء و این که یک وهله از کلاس والد باشد یا کلاس فرزند، به طرز متفاوتی قالببندی میشود. برخی زبانهای شیءگرا نوعی باطل سازی متد دارند که امکان تعریف متدهای چندگانه کلاس با نام واحد و با تعداد آرگومانهای مختلف را میدهد. این وضعیت به طور مستقیم در PHP پشتیبانی نمیشود؛ اما چندین راهکار برای رسیدن به چنین کاربردی معرفی شدهاند.
سخن پایانی
برنامهنویسی شیءگرا موضوع بسیار گستردهای است و ما تنها به گوشه کوچکی از آن در این نوشته اشاره کردیم. امیدواریم این راهنما به شما کمک کرده باشد که با مبانی OOP آشنا شوید و انگیزهای برای ادامه یادگیری مباحث پیشرفته شیءگرایی به شما بدهد.
اگر این نوشته برای شما مفید بوده است، پیشنهاد ما استفاده از آموزشهای زیر است:
- مجموعه آموزشهای برنامهنویسی PHP
- گنجینه آموزشهای برنامه نویسی PHP
- مجموعه آموزشهای برنامهنویسی
- آموزش فریمورک لاراول PHP Laravel برای ساخت فروشگاه اینترنتی
- برنامهنویسی PHP و هر آنچه برای شروع باید بدانید — آموزش جامع
- نوشتن و خواندن فایل ها با PHP — به زبان ساده
- آموزش کامل MVC در PHP — از صفر تا صد و به زبان ساده
- مفهوم کلاس در برنامه نویسی — همراه با نمونه مثال عملی
==
عالی، مفید و با ارزش!
ممنون از شما بابت این مطلب مفید