نحوه تعریف کردن namespace ها در PHP

29 بهمن 1397
define-namespace-in-php

با سلام، در این مقاله سعی می کنیم تا با مبحث پایه ای "تعریف namespace ها" آشنا شویم و همچنین کلیتی از فراخوانی namespace ها ارائه دهیم. در قسمت قبل توضیح دادیم که:

نحوه ی تعریف namespace ها

تمامی ثابت ها، توابع و کلاس های PHP به صورت پیش فرض در فضای global قرار می گیرند. این همان فضایی است که قبل از ساخته شدن namespace ها وجود داشت و نام ها در آن قرار می گرفتند. برای تعریف یک namespace باید از دستور namespace در بالای فایل PHP خود استفاده کنید. توجه کنید که این دستور باید اولین خط در فایل PHP شما باشد (البته به استثناء دستور declare) و اجازه ندارید قبل از آن هیچ whitespace (فضای خالی مانند اسپیس یا اینتر) یا کدهایی به غیر از کد PHP قرار دهید. مثال از کد صحیح:

<?php
// define this code in the MyProject namespace
namespace MyProject;

هر کدی که پس از این کد نوشته شود مربوط به namespace ای به نام MyProject خواهد بود.

مثال از کد غلط:

<html>
<?php
namespace MyProject; // fatal error - namespace must be the first statement in the script
?>

در این کد قبل از کدهای PHP از کدِ HTML استفاده شده است که باعث بروز خطا می شود.

نکته: ما نمی توانیم برای یک گروه از کدها دو یا تعداد بیشتری namespace داشته باشیم. همچنین نمی توانیم به شیوه ی عادی از namespace ها به صورت "تو در تو" (nested) استفاده کنیم.

کد زیر در PHP غلط است:

<?php
namespace my\stuff {
    namespace nested {
        class foo {}
    }
}
?>

اگر بخواهید از namespace های تو در تو استفاده کنید باید آن را به شکل زیر پیاده کنید:

<?php
namespace my\stuff\nested {
    class foo {}
}
?>

در واقع این یک کد nest شده (تو در تو) نیست، بلکه یک نظام سلسله مراتبی از namespace ها است که در عمل همان کار nest کردن را انجام می دهد.

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

<?php
namespace MyProject1;
// PHP code for the MyProject1 namespace

namespace MyProject2;
// PHP code for the MyProject2 namespace

// Alternative syntax
namespace MyProject3 {
	// PHP code for the MyProject3 namespace
}
?>

اما طبق گفته ی متخصصین و خود وب سایت PHP این کار اصلا استاندارد نبوده، توصیه نمی شود و تا حد امکان باید از آن دوری کرد. سعی کنید هر namespace را در یک فایل جداگانه داشته باشید.

فراخوانی namespace ها

به نظر من برای نمایش این دستورات بهتر است از یک مثال واقعی استفاده کنیم. ابتدا یک فایل به نام lib1.php می سازیم و در آن یک تابع، یک کلاس و یک ثابت تعریف می کنم. نام namespace آن را نیز App\Lib1 می گذاریم؛ App مخفف Application (به معنی برنامه) و Lib مخفف Library (به معنی کتابخانه) است. محتوای این فایل به شکل زیر است:

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

const MYCONST = 'App\Lib1\MYCONST';

function MyFunction() {
	return __FUNCTION__;
}

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

می توانیم برای فراخوانی یا صدا زدن این کد به شکل زیر عمل کنیم:

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

<?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 ای را در فایل myapp.php تعریف نکرده ایم بنابراین کدهای آن در فضای global قرار گرفته اند. از طرفی دیگر، اگر MYCONST یا ()MyFunction یا MyClass را مستقیما صدا بزنید با یک خطا مواجه خواهید شد. چرا؟ به دلیل اینکه آن ها در namespace ای به آدرس App\Lib1 هستند اما کدهای ما در فضای global قرار دارند.

برای حل این مشکل (همانطور که در کد بالا می بینید) می توانیم از آدرس کامل App\Lib1\ استفاده کنیم. اگر فایل myapp.php را اجرا کنیم خروجی آن به این شکل خواهد بود:

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

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

پاسخ: باید توجه کنید فایده ی اصلی namespace ها این بود که نیازی به حفظ کردن نام توابع، کلاس ها و ... نداشته باشیم و دور شدن از نام های طولانی تنها یکی از فایده های namespace ها است. در عین حال حرف شما کاملا صحیح است! برای حل این مشکل در جلسه ی بعد با دستور use آشنا می شویم و اما قبل از آن باید چند اصطلاح را توضیح بدهم تا جلسه ی بعد مشکلی نداشته باشیم:

نام ها در namespace ها به این شکل هستند:

  • Unqualified name: این نوع نام ها، نام هایی هستند که جدا کننده ی namespace را ندارند. جدا کننده ی namespace همان علامت بک اسلش "\" است. مثال: ()MyFunction یا Foo
  • Qualified name: این نوع نام ها، نام هایی هستند که حداقل یک جداکننده ی namespace دارند. مثال: ()Lib1\MyFunction یا Foo\Bar
  • Fully qualified name: این نوع نام ها، کامل ترین شکل نام هستند و قبل از هر چیز با یک جداکننده ی namespace شروع می شوند. مانند: ()App\Lib2\MyFunction\ یا Foo\Bar\ و ... . اگر قبلا با اندروید و ویندوز (مخصوصا در زمینه ی دیرکتوری ها) آشنا باشید می دانید که بک اسلش اولیه که قبل از همه چیز می آید به معنی root (در لغت به معنی "ریشه") یا مبدا دستگاه است. این بک اسلش در namespace ها به معنی namespace اصلی و ریشه ای، یعنی همان فضای global، اشاره می کند.

نام های Fully qualified برای یک بار صدا زدن چیزی کفاف می کنند اما اگر بخواهیم چیزهای زیادی را صدا بزنیم، استفاده از آن ها بسیار سخت می شود و اینجاست که دستور use وارد می شود.

خلاصه ی مقاله

در این مقاله سعی شد تا با مبحث پایه ای "تعریف namespace ها" آشنا شویم و نکات ریز مربوط به آن را بشکافیم. همچنین مقدمه ای بر بحث فراخوانی namespace ها ارائه شد که در قسمت بعد به طور مفصل به آن خواهیم پرداخت. امیدوارم از این قسمت لذت برده باشید.

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

نویسنده شوید

دیدگاه‌های شما (1 دیدگاه)

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

میلاد
28 فروردین 1398
سلام مطالب ساده و خوب توضیح داده شده. قسمت لایک. یا همان پسندیدن! کار نمیکند؟ روی هیچ مقاله ای.

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

روکسو
28 فروردین 1398
لطفا صفحه خود را رفرش کنید. این دکمه در حال حاضر کار می کند و مشکلی ندارد.

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