استفاده از دستور use در namespace ها

29 بهمن 1397
namespaces-in-OO-PHP-use-and-alias

در قسمت قبل به ساختار کلی namespace ها و نکاتی در مورد تعریف شان آشنا شدیم و به آن جا رسیدیم که اگر بخواهیم namespace ها را فراخوانی کنیم مجبوریم آدرس کامل namespace را ارائه بدهیم:

<?php
header('Content-type: text/plain');
require_once('lib1.php');

echo \App\Lib1\MYCONST . "\n";
echo \App\Lib1\MyFunction() . "\n";
echo \App\Lib1\MyClass::WhoAmI() . "\n";
?>

سپس سوال زیر را مطرح کردیم:

سوال: مگر قرار نبود یکی از مزایای استفاده از namespace ها این باشد که دیگر مجبور به استفاده از نام های طولانی و غیره نشویم؟ با این پسوند های پشت سر هم، نام ها باز هم طولانی می شوند. این که شد همان آش و همان کاسه!

و در جواب گفتیم که می توانیم از دستور use استفاده کنیم. در این قسمت به بررسی این موضوع خواهیم پرداخت.

برای درک بهتر این موضوع، دو فایل جداگانه می سازیم و درونشان کدهای یکسانی قرار می دهیم. تنها فرق این دو فایل این است که namespace متفاوتی دارند.

فایل اول lib1.php

<?php
// application library 1
namespace App\Lib1;

const MYCONST = 'App\Lib1\MYCONST';

function MyFunction() {
	return __FUNCTION__;
}

class MyClass {
	static function WhoAmI() {
		return __METHOD__;
	}
}
?>

فایل دوم lib2.php

<?php
// application library 2
namespace App\Lib2;

const MYCONST = 'App\Lib2\MYCONST';

function MyFunction() {
	return __FUNCTION__;
}

class MyClass {
	static function WhoAmI() {
		return __METHOD__;
	}
}
?>

حال برای دنبال کردن ادامه ی بحث باید با مفاهیم Unqualified name (مانند ()MyFunction) و Qualified name (مانند ()Lib1\MyFunctionو Fully qualified name مانند (()App\Lib2\MyFunction\آشنا باشید.

اگر با این موارد آشنایی ندارید به این قسمت مراجعه کنید.

حتما متوجه شده اید که این نام ها مبحث جدیدی نیستند و زمانی که برای فراخوانی namespace ها آن ها را صدا می زدیم از همین سیستم استفاده می کردیم اما آشنایی شما با آن ها برای ما مهم است.

حالا که فایل های lib2.php و lib1.php را تعریف کرده ایم می خواهیم کدی بنویسیم که تابع، ثابت و کلاس ما را فراخوانی کند. نام این فایل را myapp1.php می گذاریم:

<?php
namespace App\Lib1;

require_once('lib1.php');
require_once('lib2.php');

header('Content-type: text/plain');
echo MYCONST . "\n";
echo MyFunction() . "\n";
echo MyClass::WhoAmI() . "\n";
?>

خروجی این کد به شکل زیر است:

App\Lib1\MYCONST
App\Lib1\MyFunction
App\Lib1\MyClass::WhoAmI

اگر به کدهای بالا توجه کنید، می بینید که ما هر دو فایل lib1.php و lib2.php را include کرده ایم اما ثابت ما (MYCONST)، تابع ما (MyFunction) و کلاس ما (MyClass) تنها از کدهای فایل lib1.php فراخوانی می شوند. می دانید چرا؟ سعی کنید چند لحظه فکر کنید تا خودتان به جواب برسید...

دلیل این است که کدهای lib1.php و کدهای myapp1.php دارای namespace یکسانی هستند و هر دو در AppLib1 قرار دارند اما AppLib2 دارای namespace کاملا جداگانه ای است.

وارد کردن namespace ها در فایل های دیگر با دستور use

برای اینکه مشکل کدهای قبل را حل کنیم می توانیم از دستور use استفاده کنیم. این بار کدها را در فایلی به نام myapp2.php و به این شکل می نویسیم:

<?php
use App\Lib2;

require_once('lib1.php');
require_once('lib2.php');

header('Content-type: text/plain');
echo Lib2\MYCONST . "\n";
echo Lib2\MyFunction() . "\n";
echo Lib2\MyClass::WhoAmI() . "\n";
?>

خروجی این کد به شکل زیر است:

App\Lib2\MYCONST
App\Lib2\MyFunction
App\Lib2\MyClass::WhoAmI

به کدهای بالا توجه کنید؛ ما AppLib2 را وارد فایل خود کرده ایم اما هنوز هم نمی توانیم مستقیما و بدون هیچ پیشوندی به MYCONST و MyFunction و MyClass اشاره کنیم. چرا؟

به دلیل اینکه کدهایی که نوشتیم (فایل myapp2.php) در فضای global قرار دارند و اگر هیچ پیشوند و نام کاملی به ثابت، تابع و کلاس خود ندهیم، PHP در فضای global به دنبال این موارد خواهد گشت. از کجا می دانیم کد ما در فضای global است؟ اگر به کدها نگاهی بیندازید (فایل myapp2.php) متوجه می شوید که برای این فایل هیچ namespace ای تعریف نکرده ایم، بلکه به آن اجازه داده ایم از namespace ای به نام App\Lib2 استفاده کند.

همانطور که در جلسه ی قبل گفتیم زمانی که برای فایلی namespace تعریف نکنید، آن فایل در فضای global قرار می گیرد اما پیشوند Lib2 به فایل ما می گوید در فضای global دنبال این تابع، ثابت و کلاس نگرد بلکه فلان namespace را جست و جو کن.

مبحث aliasing در namespace ها

کلمه ی alias در لغت به معنی "نام مستعار" است یا هر اسمی که واقعی نباشد اما به چیزی واقعی اشاره کند.

به طور مثال تخلص شعرا یک نوع alias محسوب می شود چرا که اسم واقعی شان نیست اما به خودشان اشاره دارد. مثلا خواجه شمس‌الدین محمد تخلص خود را حافظ گذاشته است و ما همه می دانیم منظور از حافظ چه کسی است.

این کلمه در مبحث namespace ها معنی آن چنان متفاوتی ندارد! alias به ما اجازه می دهند نام های مستعار و کوتاه تری انتخاب کنیم تا راحت تر کدنویسی کنیم. مثال خود را در فایل به نام myapp3.php می نویسیم:

<?php
use App\Lib1 as L;
use App\Lib2\MyClass as Obj;

header('Content-type: text/plain');
require_once('lib1.php');
require_once('lib2.php');

echo L\MYCONST . "\n";
echo L\MyFunction() . "\n";
echo L\MyClass::WhoAmI() . "\n";
echo Obj::WhoAmI() . "\n";
?>

خروجی این کد به شکل زیر خواهد بود:

App\Lib1\MYCONST
App\Lib1\MyFunction
App\Lib1\MyClass::WhoAmI
App\Lib2\MyClass::WhoAmI

همانطور که متوجه شده اید این کار را با کلمه ی کلیدی as (به معنی "به عنوان") انجام می دهیم. در کد بالا اولین دستورِ use می گوید:

از این به بعد دوست داریم به جای AppLib1 بگوییم L و هر نام qualified ای که از حرف L استفاده کند، در زمان کامپایل شدن تبدیل به AppLib1 خواهد شد.

بدین صورت می توانیم به جای استفاده از نام های کامل مانند Lib2\MyFunction از نام های کوتاه تری مانند L\MyFunction استفاده کنیم.

دومین دستور use جالب تر است. این خط از کد می گوید به جای کلاسی که در AppLib2 تعریف کرده ایم (MyClass) می‌خواهیم بگوییم Obj. به همین دلیل می توانید از دستوری مانند ()new Obj استفاده کنید. البته این قابلیت تنها مخصوص کلاس ها است و مثلا برای توابع باید از ورژن PHP 5.6 به بالا و از روش دیگری استفاده کنید:

use function My\Full\functionName as func;

نکته: اگر بخواهیم چند namespace را وارد یک فایل کنیم، دو راه داریم:

  • مثل ما چند بار از دستور use استفاده کنیم.
  • یک بار از دستور use استفاده کنیم و namespace های مختلف را با ویرگول از هم جدا کنیم.
    مانند ;use My\Full\Classname as Another, My\Full\NSname

خلاصه ی مقاله

در این قسمت با استفاده از دستور use در موقعیت های مختلف و همچنین مبحث aliasing و استفاده ی عملی از آن آشنا شدیم. در قسمت بعد به سراغ برخی قوانین نام گذاری و مباحث ریز تر می رویم. امیدوارم از این قسمت لذت برده باشید.

برای دسترسی به تمام مقاله های پیرامون namespace‌ ها در PHP لطفا روی این لینک کلیک کنید.

نویسنده شوید

دیدگاه‌های شما

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.