سرفصل‌های آموزشی
آموزش OOP در PHP
آشنایی با مفهوم Access Modifier در زبان PHP

آشنایی با مفهوم Access Modifier در زبان PHP

تا این مرحله از دورهٔ آموزش OOP در PHP بارها و بارها با کیورد public برخورد داشته‌ایم که این کلیدواژه در کنار کلیدواژگان protected و private تحت عنوان Access Modifier شناخته می‌شوند. به عبارتی، این کلیدواژگان مشخص‌کنندهٔ سطح دسترسی پراپرتی‌ها و متدهای داخل این کلاس هستند. برای آن که به طور عملی با این سطوح دسترسی آشنا شویم، داخل پوشهٔ oop پروژه‌ای تحت عنوان access-modifier ساخته و ساختار پروژه‌های قبلی را داخل آن ایجاد می‌کنیم. در ادامه، داخل پوشهٔ classes فایلی تحت عنوان Visibility.php ساخته و آن را به صورت زیر تکمیل می‌کنیم:

<?php
namespace SokanAcademy;

class Visibility
{
    public $publicProperty = "Public Property";
    protected $protectedProperty = "Protected Property";
    private $privateProperty = "Private Property";

    public function showPublicMethod()
    {
        echo "This is a public method\n";
    }

    protected function showProtectedMethod()
    {
        echo "This is a protected method\n";
    }

    private function showPrivateMethod()
    {
        echo "This is a private method\n";
    }
}

کلاسی هم‌نام با نام این فایل تحت عنوان Visibility ساخته و داخل بدنهٔ آن سه پراپرتی تعریف کرده و به ترتیب سطوح دسترسی protected ،public و private را برای آن‌ها در نظر گرفته‌ایم. در ادامه، سه متد مختلف نیز با سطوح دسترسی protected ،public و private ساخته‌ایم که تنها کاری که قرار است انجام دهند آن است که استرینگی را چاپ کنند. در ادامهٔ این آموزش، ابتدا به معرفی عملکرد این سطوح پرداخته سپس در عمل خواهیم دید که چگونه کار خواهند کرد.

آشنایی با سطح دسترسی public

همان‌طور که از نام این Access Modifier مشخص است، کیورد public یک سطح دسترسی سراسری در اختیار پراپرتی‌ها یا متدهای داخل یک کلاس قرار می‌دهد به طوری که هیچ گونه محدودیتی در دستیابی به آن‌ها از جای‌جای سورس‌کد وجود نخواهد داشت.

آشنایی با سطح دسترسی protected

سطح دسترسی protected به معنای «محافظت‌شده» بوده و حاکی از آن است که پراپرتی‌ها و متدهایی که از جنس protected باشند، فقط و فقط از طریق همان کلاسی که داخلش تعریف‌شده‌اند و همچنین کلاس‌های فرزندی که از آن کلاس ارث‌بری کرده‌اند در دسترس خواهند بود.

آشنایی با سطح دسترسی private

محدودترین سطح دسترسی در این بین private است به طوری که پراپرتی‌ها و متدهایی از این جنس فقط و فقط از طریق همان‌ کلاسی که داخلش تعریف شده‌اند قابل‌استفاده خواهند بود.

حال که با مفهوم تک‌تک سطوح دسترسی آشنا شدیم، جهت تست کلاس Visibility که پیش از اقدام به ساختش کردیم، وارد فایل index.php شده و کدهای زیر را داخل آن می‌نویسیم:

<?php
ini_set('display_errors', '1');
require_once 'vendor/autoload.php';

$obj = new SokanAcademy\Visibility();
echo $obj->publicProperty;
echo "\n";
echo $obj->protectedProperty;
echo "/n";
echo $obj->privateProperty;

ابتدا از روی کلاس Visibility آبجکتی تحت عنوان obj$ ساخته سپس هر سه پراپرتی را به این آبجکت منتسب کرده تا با استفاده از دستور echo مقادیر آن‌ها را چاپ کنیم. چنانچه این فایل را از طریق کامندلاین و یا مرورگر اجرا کنیم، در خروجی خواهیم داشت:

/var/www/oop/access-modifier$ php index.php 
Public Property
PHP Fatal error: Uncaught Error: Cannot access protected property SokanAcademy\Visibility::$protectedProperty in /var/www/oop/access-modifier/index.php:8
Stack trace:
#0 {main}
  thrown in /var/www/oop/5-access-modifier/index.php on line 8

همان‌طور که در خروجی ملاحظه می‌شود، مقدار پراپرتی publicProperty$ که از جنس public می‌باشد به درستی چاپ شده است اما دو پراپرتی دیگر که از جنس protected و private هستند منجر به بروز ارور شده‌اند و این ارور حاکی از آن است که امکان دسترسی به پراپرتی protectedProperty$ را نخواهیم داشت. با توجه به این که این پراپرتی منجر به بروز ارور شده است، مفسر پی‌اچ‌پی دیگر به بررسی پراپرتی آخر که privateProperty$ نام دارد نخواهد رسید که جهت تست این موضوع، می‌توانیم کدهای فوق را به صورت زیر تغییر دهیم:

<?php
ini_set('display_errors', '1');
require_once 'vendor/autoload.php';

$obj = new SokanAcademy\Visibility();
echo $obj->publicProperty;
echo "\n";
// echo $obj->protectedProperty;
// echo "/n";
echo $obj->privateProperty;

در حقیقت، خطی که مسئول چاپ پراپرتی protectedProperty$ بود را کامنت کرده و مجدد فایل فوق را اجرا می‌کنیم:

/var/www/oop/access-modifier$ php index.php 
Public Property
PHP Fatal error: Uncaught Error: Cannot access private property SokanAcademy\Visibility::$privateProperty in /var/www/oop/access-modifier/index.php:10
Stack trace:
#0 {main}
  thrown in /var/www/oop/5-access-modifier/index.php on line 10

همان‌طور که انتظار می‌رفت، امکان دسترسی به پراپرتی‌هایی هم که از جنس private هستند را نخواهیم داشت. این موضوع در ارتباط با متدهایی هم که سطوح دسترسی متفاوتی دارند صادق است به طوری که داریم:

<?php
ini_set('display_errors', '1');
require_once 'vendor/autoload.php';

$obj = new SokanAcademy\Visibility();
// echo $obj->publicProperty;
// echo "\n";
// echo $obj->protectedProperty;
// echo "/n";
// echo $obj->privateProperty;
$obj->showPublicMethod();
$obj->showProtectedMethod();
$obj->showPrivateMethod();

پس از کامنت کردن کدهای مرتبط با چاپ پراپرتی‌ها، هر سه متد تعریف‌شده داخل کلاس Visibility را فراخوانی کرده‌ایم به طوری که در خروجی خواهیم داشت:

/var/www/oop/access-modifier$ php index.php 
This is a public method
PHP Fatal error: Uncaught Error: Call to protected method SokanAcademy\Visibility::showProtectedMethod() from context '' in /var/www/oop/access-modifier/index.php:12
Stack trace:
#0 {main}
  thrown in /var/www/oop/5-access-modifier/index.php on line 12

می‌بینیم که مجدد امکان دسترسی به متدهایی هم که از جنس protected یا private هستند را نخواهیم داشت.

پیش از این گفتیم که پراپرتی‌ها و متدهایی که از جنس protected باشند فقط از داخل همان کلاس و کلاس‌های دیگری که از آن ارث‌بری کنند در دسترس هستند که برای روشن‌تر شدن این موضوع، کلاس Visibility را به صورت زیر تغییر می‌دهیم:

<?php
namespace SokanAcademy;

class Visibility
{
    public $publicProperty = "Public Property";
    protected $protectedProperty = "Protected Property";
    private $privateProperty = "Private Property";

    public function __construct()
    {
        echo "The protected property is: $this->protectedProperty\n";
        echo "The private property is: $this->privateProperty\n";
        $this->showProtectedMethod();
        $this->showPrivateMethod();
    }

    public function showPublicMethod()
    {
        echo "This is a public method\n";
    }

    protected function showProtectedMethod()
    {
        echo "This is a protected method\n";
    }

    private function showPrivateMethod()
    {
        echo "This is a private method\n";
    }
}

حال فایل index.php را به صورت زیر آپدیت می‌کنیم:

<?php
ini_set('display_errors', '1');
require_once 'vendor/autoload.php';

$obj = new SokanAcademy\Visibility();
// echo $obj->publicProperty;
// echo "\n";
// echo $obj->protectedProperty;
// echo "/n";
// echo $obj->privateProperty;
// $obj->showPublicMethod();
// $obj->showProtectedMethod();
// $obj->showPrivateMethod();

در واقع، با توجه به این که کانستراکتور به محض ساخت یک آبجکت از روی کلاس فراخوانی می‌شود، صرفاً با ساخت یک آبجکت از روی کلاس Visibility می‌توانیم عملکرد آن را تست کنیم به طوری که در خروجی خواهیم داشت:

/var/www/oop/access-modifier$ php index.php 
The protected property is: Protected Property
The private property is: Private Property
This is a protected method
This is a private method

می‌بینیم که به سادگی از داخل همان کلاس توانستیم به پراپرتی‌ها و متدهایی که از جنس protected یا private بودن دست یابیم. پیش از این گفتیم که سطح دسترسی protected این امکان را در اختیارمان می‌گذارد تا علاوه بر دسترسی داشتن از داخل همان کلاس، در کلاس‌های فرزندی که از کلاس والد ارث‌بری می‌کنند نیز در دسترس خواهند بود که به منظور تست این موضوع، داخل پوشهٔ classes فایلی تحت عنوان ChildClass.php ساخته و آن را به صورت زیر تکمیل می‌کنیم:

<?php
namespace SokanAcademy;

class ChildClass extends Visibility
{

}

تنها کاری که کرده‌ایم آن است که با استفاده از کیورد extends گفته‌ایم که کلاس ChildClass کلیهٔ ویژگی‌هایش را از کلاس Visibility به ارث خواهد برد. در ادامه، قصد داریم تا داخل فایل index.php آبجکتی از روی کلاس ChildClass بسازیم به طوری که خواهیم داشت:

<?php
ini_set('display_errors', '1');
require_once 'vendor/autoload.php';

$obj = new SokanAcademy\Visibility();
// echo $obj->publicProperty;
// echo "\n";
// echo $obj->protectedProperty;
// echo "/n";
// echo $obj->privateProperty;
// $obj->showPublicMethod();
// $obj->showProtectedMethod();
// $obj->showPrivateMethod();
$child = new SokanAcademy\ChildClass();
echo $child->publicProperty;
echo "\n";
$child->showPublicMethod();

آبجکت جدیدی تحت عنوان child$ از روی کلاس ChildClass ساخته و اگر چه که داخل کلاس ChildClass هیچ کدی ننوشته‌ایم، اما در عین حال با توجه به این که کلاس مذکور کلیهٔ خصوصیاتش را از کلاس والدِ Visibility به ارث برده‌ است، به پراپرتی و متد public قرار گرفته داخل کلاس پدر دسترسی خواهیم داشت به طوری که در خروجی داریم:

The protected property is: Protected Property
The private property is: Private Property
This is a protected method
This is a private method
The protected property is: Protected Property
The private property is: Private Property
This is a protected method
This is a private method
Public Property
This is a public method

چهار خط اول به دلیل اجرای آبجکت obj$ است که کانستراکتور کلاس Visibility را فراخوانی کرده است و چهار خط دوم مربوطه به آبجکت child$ است که مجدد منجر به فراخوانی کانستراکتور کلاس Visibility اما این بار از طریق کلاس ChildClass شده است و دو خط آخر مرتبط با فراخوانی پراپرتی و متد public قرارگرفته داخل کلاس Visibility است که به کلاس ChildClass به ارث رسیده‌اند.

پیش از این گفتیم که گرچه پراپرتی‌ها و متدهای private فقط و فقط در همان کلاسی که ایجاد شده‌اند در دسترس هستند، اما هر چیزی که از جنس protected باشد علاوه بر همان کلاس، در کلاس‌ها فرزند نیز در دسترس است که برای همین منظور، کدهای فوق را به صورت زیر آپدیت کرده تا این موضوع را تست نماییم:

<?php
ini_set('display_errors', '1');
require_once 'vendor/autoload.php';

$obj = new SokanAcademy\Visibility();
// echo $obj->publicProperty;
// echo "\n";
// echo $obj->protectedProperty;
// echo "/n";
// echo $obj->privateProperty;
// $obj->showPublicMethod();
// $obj->showProtectedMethod();
// $obj->showPrivateMethod();
$child = new SokanAcademy\ChildClass();
echo $child->publicProperty;
echo "\n";
$child->showPublicMethod();
echo "\n";
echo $child->protectedProperty;

در واقع، سعی نموده‌ایم تا به پراپرتی protectedProperty$ در کلاس Visibility که از جنس protected است دست یابیم اما در خروجی خواهیم داشت:

/var/www/oop/access-modifier$ php index.php 
The protected property is: Protected Property
The private property is: Private Property
This is a protected method
This is a private method
The protected property is: Protected Property
The private property is: Private Property
This is a protected method
This is a private method
Public Property
This is a public method

PHP Fatal error:  Uncaught Error: Cannot access protected property SokanAcademy\ChildClass::$protectedProperty in /var/www/oop/access-modifier/index.php:19
Stack trace:
#0 {main}
  thrown in /var/www/oop/5-access-modifier/index.php on line 19

می‌بینیم که در خط نوزدهم به یک ارور برخورده‌ایم با این مضمون که به پراپرتی protectedProperty$ که داخل کلاس ChildClass است از داخل فایل index.php دسترسی نداریم! در واقع، این مشکل از آنجا ناشی می‌شود که نباید فراموش کنیم که پراپرتی‌ها و متدهای protected فقط در داخل کلاس فرزند در دسترس هستند و نَه در فایلی که آن کلاس را فراخوانی کرده‌ایم که برای درک بهتر این موضوع، کلاس ChildClass را به صورت زیر تغییر خواهیم داد:

<?php
namespace SokanAcademy;

class ChildClass extends Visibility
{
    public function __construct()
    {
        echo $this->protectedProperty . "from ChildClass\n";
        $this->showProtectedMethod();
    }
}

در واقع، داخل کانستراکتور کلاس ChildClass هم پراپرتی و هم متدی که از جنس protected بودند را مورد استفاده قرار داده‌ایم. حال فایل index.php را به صورت زیر آپدیت می‌کنیم:

<?php
ini_set('display_errors', '1');
require_once 'vendor/autoload.php';

$obj = new SokanAcademy\Visibility();
// echo $obj->publicProperty;
// echo "\n";
// echo $obj->protectedProperty;
// echo "/n";
// echo $obj->privateProperty;
// $obj->showPublicMethod();
// $obj->showProtectedMethod();
// $obj->showPrivateMethod();
$child = new SokanAcademy\ChildClass();
// echo $child->publicProperty;
// echo "\n";
// $child->showPublicMethod();
// echo "\n";
// echo $child->protectedProperty;

اکنون در خروجی خواهیم داشت:

/var/www/oop/access-modifier$ php index.php 
The protected property is: Protected Property
The private property is: Private Property
This is a protected method
This is a private method
Protected Propertyfrom ChildClass
This is a protected method

چهار خط اول مربوط به اجرای کانستراکتور کلاس ChildClass است که منجر به اجرای کانستراکتور کلاس Visibility شده است به علاوه این که دو خط آخر نیز حاکی از آنند که از داخل کلاس فرزند به پراپرتی‌ها و متدهای protected کلاس والد دسترسی داریم.

به عنوان نکتهٔ پایانی این آموزش، مجدد کلاس ChildClass که به صورت زیر آپدیت شده است را مد نظر قرار می‌دهیم:

<?php
namespace SokanAcademy;

class ChildClass extends Visibility
{
    public function __construct()
    {
        parent::__construct();
        echo $this->protectedProperty . "from ChildClass\n";
        $this->showProtectedMethod();
    }
}

همان‌طور که می‌بینیم، در خط هشتم از کلیدواژهٔ parent استفاده کرده سپس علائم :: را درج نموده و در نهایت دستور ()construct__ را نوشته‌ایم. کاری که این خط از کد انجام می‌دهد آن است که کانستراکتور کلاس والد که در این مثال Visibility است را نیز فراخوانی می‌کند به طوری که از این پس در خروجی خواهیم داشت:

The protected property is: Protected Property
The private property is: Private Property
This is a protected method
This is a private method
The protected property is: Protected Property
The private property is: Private Property
This is a protected method
This is a private method
Protected Propertyfrom ChildClass
This is a protected method

در تفسیر خروجی فوق می‌توان گفت که خطوط اول تا چهارم مرتبط با اجرای کانستراکتور کلاس Visibility است؛ خطوط پنجم تا هشتم مربوط به اجرای بخشی از کدهای کانستراکتور کلاس ChildClass است که از کلاس والدش به ارث برده است و دو خط آخر نیز اختصاصی کانستراکتور کلاس ChildClass هستند.

جمع‌بندی
در این آموزش به بررسی مفهوم Access Modifier در زبان برنامه‌نویسی پی‌اچ‌پی پرداختیم و دیدیم که سطوح دسترسی protected ،public و private چگونه می‌توانند منجر به ایجاد محدودیت در نحوهٔ دستیابی به پراپرتی‌ها و متدهای نوشته‌شده داخل یک کلاس گردند مضاف بر این که دیدیم در مبحث وراثت نیز چگونه می‌توانند مورد استفاده قرار گیرند.

online-support-icon