autoload و keywords و قوانین در namespace ها PHP

29 بهمن 1397
namespaces-in-OO-PHP-autoload-keywords

با سلام، در قسمت قبل به طور کامل با دستور use و مبحث aliasing آشنا شدیم. در این قسمت به سراغ مباحث متعددی می رویم که اولین آن ها بحث Name resolution (تجزیه یا ترجمه ی نام ها) است.

قوانین Name resolution

زمانی که کد شما کامپایل می شود بسیاری از نام هایی که ما به صورت قرار دادی تعیین کرده ایم (مثل alias ها) تبدیل به نام های اصلی می شوند، به این فرآیند Name resolution می گوییم.

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

اگر با این موارد آشنایی ندارید لطفا این فصل را مطالعه کنید:

البته یک نوع نامگذاری دیگر نیز وجود دارد که به آن Relative name می گوییم؛ در این نام گذاری namespace نیز ذکر می شود. مثال: namespace\Foo\Bar

چند مورد از قوانین اصلی name resolution به این شرح هستند:

  • علامت بک اسلش "\" در نام های Fully qualified برداشته می شوند. به طور مثال A\B\ تبدیل به A\B می شود.
  • نام های qualified و Unqualified با توجه به قوانین import (استفاده از دستور use) ترجمه می شوند. به طور مثال اگر namespace ای به آدرس A\B\C را با کلیدواژه ی as به C تبدیل کرده باشیم، فراخوانی C\D\E به A\B\C\D\E تبدیل می شود؛ یعنی به نام کامل و صحیحش برمیگردد.

سعی می کنم این قوانین را که بیشتر از دو مورد بالا هستند در یک مثال توضیح دهم تا مطلب کاملا مفهوم شود. من تنها قوانین مهم و کاربردی را ذکر می کنم. می توانید دیگر قوانین را در صفحه ی رسمی مربوطه در سایت PHP ببینید.

تصور کنید در ابتدای فایل ما این کد وجود دارد:

<?php
namespace A;
use B\D, C\E as F;

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

foo();
\foo();
my\foo();
F();

برای تابع ;()foo

  • ابتدا سعی می کند تابع foo را در namespace ای به نام A پیدا کند (یعنی namespace اصلی فایل).
  • اگر موفق نشود، سعی می کند تابع foo را در global namespace (فضای global) پیدا کند.

برای تابع ;()foo\

سعی می کند این تابع را در فضای گلوبال پیدا کند.

برای تابع ;()my\foo

سعی می کند تابع foo را در namespace به آدرس A\my پیدا کند.

برای تابع ;()F

  • سعی می کند F را در نیم‌اسپیسِ A پیدا کند.
  • اگر موفق نشد، سعی می کند، تابع F را در فضای global پیدا کند.

ثابت __NAMESPACE__

این دستور همیشه نام namespace فعلی را به صورت یک رشته بر میگرداند:

<?php
namespace App\Lib1;
echo __NAMESPACE__; // outputs: App\Lib1
?>

همانطور که در خود کد توضیح دادیم عبارت "App\Lib1" را به ما برمیگرداند.

نکته: اگر کدهای ما در فضای global باشند، یک رشته ی خالی به ما برگردانده می شود.

جدا از مزایایی که این دستور در هنگام دیباگ کردن سیستم به ما می دهد، می توان از آن برای تولید نام برای کلاس ها به صورت fully qualified و پویا استفاده کرد:

<?php
namespace App\Lib1;

class MyClass {
	public function WhoAmI() {
		return __METHOD__;
	}
}

$c = __NAMESPACE__ . '\\MyClass';
$m = new $c;
echo $m->WhoAmI(); // outputs: App\Lib1\MyClass::WhoAmI
?>

کلیدواژه ی namespace

در اینجا منظور ما مفهوم namespace (به معنی فضای نام) نیست بلکه منظورمان یک دستور برنامه نویسی به نام namespace است! این دو را اشتباه نگیرید!

میتوانیم از دستور namespace برای اشاره ی مستقیم به یک namespace یا namespace های زیرین (nested شده ها و ...) استفاده کنیم، بنابراین این دستور معادل همان دستور self در کلاس ها است.

اگر از دستور self در کلاس ها چیزی به خاطر ندارید به مقاله ی زیر مراجعه کنید:

مثال:

<?php
namespace App\Lib1;

class MyClass {
	public function WhoAmI() {
		return __METHOD__;
	}
}

$m = new namespace\MyClass;
echo $m->WhoAmI(); // outputs: App\Lib1\MyClass::WhoAmI
?>

نکته: در خط دوم از کد بالا با کلمه ی namespace مواجه می شویم. این کلمه در اینجا برای تعریف کردن namespace ها است (همان چیزی که قبلا خوانده ایم). اما در خط های پایانی با دستور "new namespace\MyClass" مواجه می شویم. این همان دستوری است که به namespace فعلی اشاره دارد؛ اگر دقت کنید خروجی این کد نیز App\Lib1 را به ما برگردانده است.

Autoload کردن کلاس های namespace

کلمه ی Autoload به معنی "بارگذاری خودکار" است. این ویژگی زبان PHP هیچ اختصاصی به namespace ها و غیر آن ندارد بلکه یک قابلیت همگانی در این زبان است. در حالت عادی و فضای global، توابع autoload به این شکل نوشته می شوند:

<?php
$obj1 = new MyClass1(); // classes/MyClass1.php is auto-loaded
$obj2 = new MyClass2(); // classes/MyClass2.php is auto-loaded

// autoload function
function __autoload($class_name) {
	require_once("classes/$class_name.php");
}
?>

اما از PHP 5.3 به بعد شما می توانید یک نمونه از یک کلاس namespace شده را بسازید. در چنین حالتی نام namespace و کلاس، به صورت fully qualified، به تابع autoload__ تحویل داده می شود.

به طور مثال، در کد بالا مقدار class_name$ می تواند App\Lib1\MyClass باشد. شما می توانید تمام فایل های کلاس هایتان را در یک فولدر قرار دهید و namespace را از رشته ی برگردانده شده حذف کنید اما این کار توصیه نمی شود چرا که ممکن است باعث تصادم نام فایل ها شود (فایل هایی با نام یکسان و در یک محل).

از طرفی نظام سلسه مراتبی در فایل های کلاس های شما، می توانند دارای ساختاری مشابه با ساختار namespace ها باشند؛ به طور مثال میتوانید فایل MyClass.php را در آدرس classes/App/Lib1/ قرار دهید. به مثال زیر توجه کنید:

محتویات classes\App\Lib1\MyClass.php\ به این شکل است:

<?php
namespace App\Lib1;

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

حال، فایلی که در مسیر root (مسیر اصلی و ریشه ای) قرار دارد می تواند از کد زیر استفاده کند:

محتویات فایل myapp.php

<?php
use App\Lib1\MyClass as MC;

$obj = new MC();
echo $obj->WhoAmI();

// autoload function
function __autoload($class) {

	// به آدرس کامل فایل namespace تبدیل
	$class = 'classes\' . str_replace('\\', '/', $class) . '.php';
	require_once($class);

}
?>

نکات این کد:

  • کلاس App\Lib1\MyClass به صورت MC خلاصه نویسی شده (مبحث aliasing از جلسه ی قبل)
  • دستور ()new MC در هنگام کامپایل شدن کد، تبدیل به ()new App\Lib1\MyClass می شود.
  • دستور str_replace از این جهت استفاده شده است که تمام بک اسلش "\" های namespace را به فوروارد اسلش "/" تبدیل کند. چرا؟ زیرا مسیر فایل ها همیشه با فوروارد اِسلَش کار می کند. بنابراین App\Lib1\MyClass تبدیل به classes/App/Lib1/MyClass.php شده و همین فایل نیز بارگذاری می شود.

خلاصه ی مقاله

در این قسمت با برخی مباحث جسته و گریخته از namespace ها آشنا شدیم که برخی از آن ها عبارت اند از name resolution (ترجمه یا تجزیه ی نام ها)، برخی کلمات کلیدی و دستورات مانند __NAMESPACE__ و مبحث autoload یا بارگذاری خودکار. امیدوارم از این قسمت لذت برده باشید.

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

نویسنده شوید

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

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