الفرق بين المراجعتين لصفحة: «PHP/namespaces»
ط استبدال النص - 'PHP/Namespaces/nsconstants' ب'PHP/namespaces' |
ط نقل عبد اللطيف ايمش صفحة PHP/Namespaces إلى PHP/namespaces: إعادة هيكلة التوثيق |
||
(2 مراجعات متوسطة بواسطة نفس المستخدم غير معروضة) | |||
سطر 1: | سطر 1: | ||
<noinclude>{{DISPLAYTITLE:مجالات الأسماء في PHP}}</noinclude> | <noinclude>{{DISPLAYTITLE:مجالات الأسماء في PHP}}</noinclude> | ||
__TOC__ | __TOC__ | ||
ما هي مجالات الأسماء؟ التعريف الواسع لمجالات الأسماء هو: طريقة لتغليف العناصر، ويمكن رؤية هذا الأمر كمفهوم مجرد في عدة أماكن. فعلى سبيل المثال، تعمل المجلدات في أنظمة التشغيل المختلفة على تجميع الملفات المرتبطة ببعضها البعض، وهي بمثابة مجال أسماء لتلك الملفات. لنأخذ المثال التالي للتوضيح: يمكن أن يكون الملف <code>foo.txt</code> موجودًا في كلا المجلدين <code>/home/greg</code> و <code>/home/other</code> ولكن لا يمكن لنسختين من هذا الملف أن تكونا في المجلد ذاته، وإضافة لذلك يتطلب الوصول إلى الملف <code>foo.txt</code> من خارج المجلد <code>/home/greg</code> إضافة اسم المجلّد إلى اسم الملف باستخدام فاصل المجلدات للحصول على المسار <code>/home/greg/foo.txt</code>. وهذا المبدأ مشابه لمفهوم مجالات الأسماء في عالم البرمجة. | ما هي مجالات الأسماء؟ التعريف الواسع لمجالات الأسماء هو: طريقة لتغليف العناصر، ويمكن رؤية هذا الأمر كمفهوم مجرد في عدة أماكن. فعلى سبيل المثال، تعمل المجلدات في أنظمة التشغيل المختلفة على تجميع الملفات المرتبطة ببعضها البعض، وهي بمثابة مجال أسماء لتلك الملفات. لنأخذ المثال التالي للتوضيح: يمكن أن يكون الملف <code>foo.txt</code> موجودًا في كلا المجلدين <code>/home/greg</code> و <code>/home/other</code> ولكن لا يمكن لنسختين من هذا الملف أن تكونا في المجلد ذاته، وإضافة لذلك يتطلب الوصول إلى الملف <code>foo.txt</code> من خارج المجلد <code>/home/greg</code> إضافة اسم المجلّد إلى اسم الملف باستخدام فاصل المجلدات للحصول على المسار <code>/home/greg/foo.txt</code>. وهذا المبدأ مشابه لمفهوم مجالات الأسماء في عالم البرمجة. | ||
{| class="wikitable" | {| class="wikitable" | ||
سطر 38: | سطر 39: | ||
ملاحظة: أسماء مجالات الأسماء PHP و php والأسماء المركبة منها (مثل <code>PHP\Classes</code>) هي أسماء محجوزة في اللغة ولا يمكن استخدامها في الشيفرة. | ملاحظة: أسماء مجالات الأسماء PHP و php والأسماء المركبة منها (مثل <code>PHP\Classes</code>) هي أسماء محجوزة في اللغة ولا يمكن استخدامها في الشيفرة. | ||
== | == تعريف مجالات الأسماء == | ||
تعرّف مجالات الأسماء باستخدام الكلمة المفتاحية namespace، ويجب التصريح عن مجال الأسماء في بداية الملف قبل أي شيفرة أخرى، باستثناء الكلمة | صحيح أنّه يمكن لأي شيفرة صالحة أن تكون ضمن مجال الأسماء إلا أنّ أنواع الشيفرة التالي هي الوحيدة التي تتأثر بمجالات الأسماء: الأصناف (وبضمنها الأصناف المجردة [abstract classes] والسمات [traits]) والواجهات (interfaces) والدوال والثوابت. | ||
تعرّف مجالات الأسماء باستخدام الكلمة المفتاحية namespace، ويجب التصريح عن مجال الأسماء في بداية الملف قبل أي شيفرة أخرى، باستثناء الكلمة المفتاحية [[PHP/declare|declare]]. | |||
المثال 2: التصريح عن مجال أسماء مفرد<syntaxhighlight lang="php"> | |||
<?php | |||
namespace MyProject; | |||
const CONNECT_OK = 1; | |||
class Connection { /* ... */ } | |||
function connect() { /* ... */ } | |||
?> | |||
</syntaxhighlight>تسمح اللغة بالتصريح عن البنية <code>declare</code> فقط قبل التصريح عن مجال الأسماء وذلك لتعريف الترميز الذي يعتمد ملف الشيفرة المصدرية، ولا تسمح باستخدام أي شيفرة غير تابعة للغة أو حتّى المسافات البيضاء: | |||
المثال 3: التصريح عن مجال أسماء مفرد<syntaxhighlight lang="php"> | |||
<?php | |||
namespace MyProject; | |||
// ستطلق هذه الشيفرة خطأً، إذ يجب أن يكون التصريح عن مجال الاسم في بداية الشيفرة. | |||
?> | |||
</syntaxhighlight><span> </span>بالإضافة إلى ذلك، وعلى العكس من بنى PHP الأخرى، فإنّ اللغة تسمح بتعريف نطاق الاسم نفسه في ملفات متعدّدة، ممّا يسمح بتقسيم محتويات نطاق الاسم عبر الملفات. | |||
== تعريف مجالات الأسماء الفرعية == | |||
كما هو الحال مع المجلدات والملفات فإنّ بالإمكان تحديد تسلسل هرمي لأسماء مجالات الأسماء؛ لذا يمكن تعريف مجالات أسماء فرعية: | |||
المثال 4: التصريح عن مجال اسم مفرد مع تسلسل هرمي<syntaxhighlight lang="php"> | |||
<?php | |||
namespace MyProject\Sub\Level; | |||
const CONNECT_OK = 1; | |||
class Connection { /* ... */ } | |||
function connect() { /* ... */ } | |||
?> | |||
</syntaxhighlight><span> </span>ينشئ المثال السابق الثابت <code>MyProject\Sub\Level\CONNECT_OK</code>، والصنف <code>MyProject\Sub\Level\Connection</code> والدالة <code>MyProject\Sub\Level\connect</code>. | |||
== تعريف مجالات أسماء متعددة في نفس الملف == | |||
يمكن التصريح عن مجالات أسماء متعددة في الملف نفسه، وهناك صيغتان للقيام بذلك: | |||
المثال 5: التصريح عن مجالات أسماء متعددة بصيغة الجمع البسيطة (simple combination syntax)<syntaxhighlight lang="php"> | |||
<?php | |||
namespace MyProject; | |||
const CONNECT_OK = 1; | |||
class Connection { /* ... */ } | |||
function connect() { /* ... */ } | |||
namespace AnotherProject; | |||
const CONNECT_OK = 1; | |||
class Connection { /* ... */ } | |||
function connect() { /* ... */ } | |||
?> | |||
</syntaxhighlight>لا ينصح باستخدام هذه الصيغة لجمع مجالات الأسماء في ملف واحد، بل ينصح باستخدام صيغة الأقواس البديلة. | |||
المثال 6: التصريح عن مجالات أسماء متعددة بواسطة صيغة الأقواس (bracketed syntax)<syntaxhighlight lang="php"> | |||
== | <?php | ||
namespace MyProject { | |||
const CONNECT_OK = 1; | |||
class Connection { /* ... */ } | |||
function connect() { /* ... */ } | |||
} | |||
namespace AnotherProject { | |||
const CONNECT_OK = 1; | |||
class Connection { /* ... */ } | |||
function connect() { /* ... */ } | |||
} | |||
?> | |||
</syntaxhighlight>ينصح بشدّة تجنّب دمج نطاقات أسماء متعددة في ملف مفرد، والحالة الشائعة هي دمج شيفرات PHP متعددة في الملف نفسه. | |||
يسمح باستخدام صيغة الأقواس فقط في حال الرغبة في دمج شيفرة عامة ليست موجودة في مجال أسماء مع شيفرة أخرى موجودة ضمن مجال أسماء، ويجب إحاطة الشيفرة العامة بعبارة namespace دون تحديد اسم لهذا المجال: | |||
== | المثال 7: التصريح عن مجالات أسماء متعددة مع شيفرة غير موجودة ضمن مجال أسماء<syntaxhighlight lang="php"> | ||
من الضروري قبل الخوض في موضوع استخدام مجالات الأسماء أن تستوعب الطريق التي تتبعها PHP في التعرف على العنصر الذي ينتمي إلى مجال أسماء معين والذي تطلبه الشيفرة الخاصة بك. | |||
<?php | |||
namespace MyProject { | |||
const CONNECT_OK = 1; | |||
class Connection { /* ... */ } | |||
function connect() { /* ... */ } | |||
} | |||
namespace { | |||
// الشيفرة العامة | |||
session_start(); | |||
$a = MyProject\connect(); | |||
echo MyProject\Connection::start(); | |||
} | |||
?> | |||
</syntaxhighlight>لا تسمح اللغة بوجود أي شيفرة خارج أقواس مجال الأسماء باستثناء عبارة declare. | |||
المثال 8: التصريح عن مجالات أسماء متعددة وشيفرة غير موجودة في مجال أسماء<syntaxhighlight lang="php"> | |||
<?php | |||
declare(encoding='UTF-8'); | |||
namespace MyProject { | |||
const CONNECT_OK = 1; | |||
class Connection { /* ... */ } | |||
function connect() { /* ... */ } | |||
} | |||
namespace { | |||
// شيفرة عامة | |||
session_start(); | |||
$a = MyProject\connect(); | |||
echo MyProject\Connection::start(); | |||
} | |||
?> | |||
</syntaxhighlight> | |||
== استخدام مجالات الأسماء: الأساسيات == | |||
من الضروري قبل الخوض في موضوع استخدام مجالات الأسماء أن تستوعب الطريق التي تتبعها PHP في التعرف على العنصر الذي ينتمي إلى مجال أسماء معين والذي تطلبه الشيفرة الخاصة بك. يمكننا في هذا الصدد أن نقارن بين مجالات الأسماء وملفات النظام. هناك ثلاث طرائق للوصول إلى ملف معيّن ضمن ملفات النظام: | |||
#الاسم النسبي للملف مثل <code>foo.txt</code>، والذي يُحلَّل إلى المسار <code>currentdirectory/foo.txt</code> حيث <code>currentdirectory</code> هو المجلد الحالي، فلو كان المجلّد الحالي هو <code>/home/foo</code>، فإنّ اسم الملف يصبح <code>/home/foo/foo.txt</code> | |||
#المسار النسبي مثل <code>subdirectory/foo.txt</code>، والذي يُحلَّل إلى <code>currentdirectory/subdirectory/foo.txt</code> | |||
#اسم الملف المطلق مثل <code>/main/foo.txt</code>، والذي يُحلّل إلى <code>/main/foo.txt</code> | |||
يمكن تطبيق المبدأ ذاته على العناصر المنتمية إلى مجال أسماء معيّن في PHP، فعلى سبيل المثال، يمكن الإشارة إلى اسم الصنف بثلاثة طرق: | |||
#الاسم غير المؤهّل (Unqualified name)، أو اسم الصنف غير المتضمن لسابقة مثل <code>$a = new foo();</code> أو <code>foo::staticmethod();</code>. إن كان مجال الأسماء الحالي هو <code>currentnamespace</code>، فإنّ اسم الصنف يُحلّل إلى <code>currentnamespace\foo</code>. وإذا كانت الشيفرة عامة وغير منتمية إلى مجال أسماء فإنّ اسم الصنف يُحلّل إلى foo.تُحلّل أسماء الدوال والثوابت غير المؤهّلة إلى دوال وثوابت عامة إن لم تعرّف الدالة أو الثابت غير المنتمي إلى مجال أسماء. راجع استخدام مجالات الأسماء: اللجوء إلى الدوال أو الثوابت العامة للمزيد من المعلومات. | |||
#الأسماء المؤهّلة (Qualified names)، أو اسم الصنف مع سابقة مثل <code>$a = new subnamespace\foo();</code> أو <code>subnamespace\foo::staticmethod();</code>. إن كان اسم مجال الأسماء الحالي هو <code>currentnamespace</code> فإنّ اسم الصنف يحلّل إلى <code>currentnamespace\subnamespace\foo</code> وإن كانت الشيفرة عامة لا تنتمي إلى مجال أسماء فإن اسم الصنف يحلّل إلى <code>subnamespace\foo</code>. | |||
#الاسم المؤهّل بالكامل (Fully qualified name)، أو اسم الصنف المسبوق بعامل السابقة العامة (global prefix operator) مثل: <code>$a = new\currentnamespace\foo();</code> أو <code>currentnamespace\foo::staticmethod();</code>. يُحلّل اسم الصنف دائمًا في هذه الحالة إلى الاسم الحرفي المحدّد في الشيفرة كما هو <code>currentnamespace\foo</code>. | |||
إليك مثالًا عن الأنواع الثلاثة في شيفرة حقيقية: | |||
file1.php<syntaxhighlight lang="php"> | |||
<?php | |||
namespace Foo\Bar\subnamespace; | |||
const FOO = 1; | |||
function foo() {} | |||
class foo | |||
{ | |||
static function staticmethod() {} | |||
} | |||
?> | |||
file2.php | |||
<?php | |||
namespace Foo\Bar; | |||
include 'file1.php'; | |||
const FOO = 2; | |||
function foo() {} | |||
class foo | |||
{ | |||
static function staticmethod() {} | |||
} | |||
/* اسم غير مؤهّل */ | |||
foo(); // resolves to function Foo\Bar\foo | |||
foo::staticmethod(); // resolves to class Foo\Bar\foo, method staticmethod | |||
echo FOO; // resolves to constant Foo\Bar\FOO | |||
/* اسم مؤهّل */ | |||
subnamespace\foo(); // resolves to function Foo\Bar\subnamespace\foo | |||
subnamespace\foo::staticmethod(); // resolves to class Foo\Bar\subnamespace\foo, | |||
// method staticmethod | |||
echo subnamespace\FOO; // resolves to constant Foo\Bar\subnamespace\FOO | |||
/* اسم مؤهّل بالكامل */ | |||
\Foo\Bar\foo(); // resolves to function Foo\Bar\foo | |||
\Foo\Bar\foo::staticmethod(); // resolves to class Foo\Bar\foo, method staticmethod | |||
echo \Foo\Bar\FOO; // resolves to constant Foo\Bar\FOO | |||
?> | |||
</syntaxhighlight>لاحظ أنّه لغرض الوصول إلى أي صنف أو دالة أو ثابت في النطاق العام global يمكن استخدام الاسم المؤهّل بالكامل مثل <code>\strlen()</code> أو <code>\Exception</code> أو <code>\INI_ALL</code>. | |||
المثال 9: الوصول إلى الأصناف والدوال والثوابت العامة ضمن مجال الأسماء<syntaxhighlight lang="php"> | |||
<?php | |||
namespace Foo; | |||
function strlen() {} | |||
const INI_ALL = 3; | |||
class Exception {} | |||
$a = \strlen('hi'); // calls global function strlen | |||
$b = \INI_ALL; // accesses global constant INI_ALL | |||
$c = new \Exception('error'); // instantiates global class Exception | |||
?> | |||
</syntaxhighlight> | |||
== [[PHP/namespaces|مجالات الأسماء وخصائص اللغة الديناميكية]] == | == [[PHP/namespaces|مجالات الأسماء وخصائص اللغة الديناميكية]] == | ||
تتأثر طريقة استخدام PHP لمجالات الأسماء بطبيعتها الديناميكية كلغة | تتأثر طريقة استخدام PHP لمجالات الأسماء بطبيعتها الديناميكية كلغة برمجية؛ لهذا لو أردنا تحويل الشيفرة في المثال التالي إلى شيفرة ضمن مجال أسماء: | ||
المثال 10: الوصول الديناميكي إلى العناصر<syntaxhighlight lang="php"> | |||
<?php | |||
class classname | |||
{ | |||
function __construct() | |||
{ | |||
echo __METHOD__,"\n"; | |||
} | |||
} | |||
function funcname() | |||
{ | |||
echo __FUNCTION__,"\n"; | |||
} | |||
const constname = "global"; | |||
$a = 'classname'; | |||
$obj = new $a; // prints classname::__construct | |||
$b = 'funcname'; | |||
$b(); // prints funcname | |||
echo constant('constname'), "\n"; // prints global | |||
?> | |||
</syntaxhighlight>يجب استخدام الاسم المؤهّل بالكامل (اسم الصنف مع سابقة اسم المجال). لاحظ أنّه نظرًا لعدم وجود فرق بين الاسم المؤهّل (qualified) والاسم المؤهّل بالكامل (fully qualified) داخل اسم صنف أو اسم دالة أو اسم ثابت ديناميكي، فلا حاجة لاستخدام الخط المائل. | |||
المثال 11: الوصول الديناميكي لعناصر ضمن مجال أسماء<syntaxhighlight lang="php"> | |||
<?php | |||
namespace namespacename; | |||
class classname | |||
{ | |||
function __construct() | |||
{ | |||
echo __METHOD__,"\n"; | |||
} | |||
} | |||
function funcname() | |||
{ | |||
echo __FUNCTION__,"\n"; | |||
} | |||
const constname = "namespaced"; | |||
/* لاحظ أنّه في حال استخدام علامات الاقتباس المزدوجة يجب استخدام | |||
"\\namespacename\\classname" */ | |||
$a = '\namespacename\classname'; | |||
$obj = new $a; // prints namespacename\classname::__construct | |||
$a = 'namespacename\classname'; | |||
$obj = new $a; // also prints namespacename\classname::__construct | |||
$b = 'namespacename\funcname'; | |||
$b(); // prints namespacename\funcname | |||
$b = '\namespacename\funcname'; | |||
$b(); // also prints namespacename\funcname | |||
echo constant('\namespacename\constname'), "\n"; // prints namespaced | |||
echo constant('namespacename\constname'), "\n"; // also prints namespaced | |||
?> | |||
</syntaxhighlight>تأكّد من قراءة الملاحظة حول تهريب أسماء مجالات الأسماء في السلاسل النصّية. | |||
== الكلمة المفتاحية namespace و الثابت __NAMESPACE__ == | |||
تقدّم PHP طريقتين للوصول المجرّد إلى العناصر ضمن مجال الأسماء الحالي، وهما الثابت السحري <code>__NAMESPACE__</code> والكلمة المفتاحية <code>namespace</code>. | |||
تكون قيمة الثابت السحري <code>__NMAESPACE__</code> سلسلة نصية تحتوي اسم مجال الأسماء الحالي، وبصورة عامة تكون هذه السلسلة النصية فارغة في حال كون الشيفرة لا تنتمي إلى أي مجال أسماء. | |||
المثال 12: مثال على الثابت السحري <code>__NAMESPACE__</code> وشيفرة تنتمي إلى مجال أسماء<syntaxhighlight lang="php"> | |||
<?php | |||
namespace MyProject; | |||
echo '"', __NAMESPACE__, '"'; // outputs "MyProject" | |||
?> | |||
</syntaxhighlight>المثال 13: مثال على الثابت السحري <code>__NAMESPACE__</code> وشيفرة لا تنتمي إلى مجال أسماء<syntaxhighlight lang="php"> | |||
<?php | |||
echo '"', __NAMESPACE__, '"'; // outputs "" | |||
?> | |||
</syntaxhighlight>يمكن الاستفادة من الثابت <code>__NAMESPACE__</code> في بناء الأسماء بطريقة ديناميكية، فعلى سبيل المثال: | |||
المثال 14: استخدام <code>__NAMESPACE__</code> لبناء الأسماء بصورة ديناميكية<syntaxhighlight lang="php"> | |||
<?php | |||
namespace MyProject; | |||
function get($classname) | |||
{ | |||
$a = __NAMESPACE__ . '\\' . $classname; | |||
return new $a; | |||
} | |||
?> | |||
</syntaxhighlight>يمكن استخدام الكلمة المفتاحية <code>namespace</code> لطلب عنصر من مجال الأسماء الحالي أو مجال الأسماء الفرعي، ويمكن اعتبار هذه الكملة المفتاحية مشابهة للعامل <code>self</code> في الأصناف. | |||
المثال 15: استخدام العامل <code>namespace</code> داخل مجال أسماء<syntaxhighlight lang="php"> | |||
<?php | |||
namespace MyProject; | |||
use blah\blah as mine; // see "Using namespaces: Aliasing/Importing" | |||
blah\mine(); // calls function MyProject\blah\mine() | |||
namespace\blah\mine(); // calls function MyProject\blah\mine() | |||
namespace\func(); // calls function MyProject\func() | |||
namespace\sub\func(); // calls function MyProject\sub\func() | |||
namespace\cname::method(); // calls static method "method" of class MyProject\cname | |||
$a = new namespace\sub\cname(); // instantiates object of class MyProject\sub\cname | |||
$b = namespace\CONSTANT; // assigns value of constant MyProject\CONSTANT to $b | |||
?> | |||
</syntaxhighlight>المثال 16: استخدام العامل <code>namespace</code> مع شيفرة عامة<syntaxhighlight lang="php"> | |||
== | <?php | ||
namespace\func(); // calls function func() | |||
namespace\sub\func(); // calls function sub\func() | |||
namespace\cname::method(); // calls static method "method" of class cname | |||
$a = new namespace\sub\cname(); // instantiates object of class sub\cname | |||
$b = namespace\CONSTANT; // assigns value of constant CONSTANT to $b | |||
?> | |||
</syntaxhighlight> | |||
== استخدام مجالات الأسماء: التسمية بأسماء بديلة/الاستيراد == | |||
من الميزات المهمة في مجالات الأسماء هي القدرة على الإشارة إلى اسم خارجي مؤهّل بالكامل (external fully qualified name) باستخدام اسم بديل (alias)، والقدرة على استيراد مجالات الأسماء. هذه الميزة مشابهة للقدرة على إنشاء روابط رمزية للملفات (symbolic links) أو المجلّدات في الأنظمة المبنية على يونكس (unix-based filesystems). | من الميزات المهمة في مجالات الأسماء هي القدرة على الإشارة إلى اسم خارجي مؤهّل بالكامل (external fully qualified name) باستخدام اسم بديل (alias)، والقدرة على استيراد مجالات الأسماء. هذه الميزة مشابهة للقدرة على إنشاء روابط رمزية للملفات (symbolic links) أو المجلّدات في الأنظمة المبنية على يونكس (unix-based filesystems). | ||
تتضمّن جميع إصدارات PHP التي تدعم مجالات الأسماء ثلاثة أنواع من التسمية البديلة والاستيراد: التسمية لبديلة لاسم الصنف، والتسمية البديلة لاسم الواجهة، والتسمية البديلة لاسم مجال الأسماء. يتيح الإصدار 5.6 وما بعده من PHP التسمية البديلة أو استيراد أسماء الدوال والثوابت. | |||
يمكن استخدام العامل <code>use</code> لإنشاء التسمية البديلة، والمثال التالي يوضّح الأنواع الخمسة للاستيراد: | |||
المثال 17: استيراد/التسمية البديلة باستخدام العامل <code>use</code><syntaxhighlight lang="php"> | |||
<?php | |||
namespace foo; | |||
use My\Full\Classname as Another; | |||
// هذا مطابق لما يلي | |||
// My\Full\NSname as NSname | |||
use My\Full\NSname; | |||
// استيراد صنف عام | |||
use ArrayObject; | |||
// استيراد دالة في الإصدار 5.6 وما بعده | |||
use function My\Full\functionName; | |||
// إعادة تسمية دالة في الإصدار 5.6 وما بعده | |||
use function My\Full\functionName as func; | |||
// استيراد ثابت (الإصدار 5.6 وما بعده) | |||
use const My\Full\CONSTANT; | |||
$obj = new namespace\Another; // instantiates object of class foo\Another | |||
$obj = new Another; // instantiates object of class My\Full\Classname | |||
NSname\subns\func(); // calls function My\Full\NSname\subns\func | |||
$a = new ArrayObject(array(1)); // instantiates object of class ArrayObject | |||
// without the "use ArrayObject" we would instantiate an object of class foo\ArrayObject | |||
func(); // calls function My\Full\functionName | |||
echo CONSTANT; // echoes the value of My\Full\CONSTANT | |||
?> | |||
</syntaxhighlight>لاحظ أنّه لا حاجة (ولا ينصح بذلك أيضًا) لاستخدام الخط المائل مع الأسماء المنتمية إلى نطاق أسماء معيّن (أسماء مؤهّلة بالكامل تتضمن الرمز الفاصل في مجالات الأسماء مثل <code>Foo\Bar</code>، مقارنة بالأسماء العامة والتي لا تتضمن هذا الرمز مثل <code>FooBar</code>)؛ إذ يجب أن تكون الأسماء المستوردة مؤهّلة بالكامل، ولن تعالج بالنسبة إلى مجال الأسماء الحالي. | |||
تدعم PHP كذلك اختصارًا يمكن عن طريقه استخدام عبارات use متعدّدة في نفس السطر. | |||
المثال 18: استيراد/التسمية البديلة باستخدام العامل <code>use</code> مع دمج عدة عبارات في سطر واحد<syntaxhighlight lang="php"> | |||
<?php | |||
use My\Full\Classname as Another, My\Full\NSname; | |||
$obj = new Another; // instantiates object of class My\Full\Classname | |||
NSname\subns\func(); // calls function My\Full\NSname\subns\func | |||
?> | |||
</syntaxhighlight>تنفّذ عملية الاستيراد في وقت التصريف؛ لذا فإنّها لا تؤثر على أسماء الأصناف أو الدوال أو الثوابت الديناميكية. | |||
المثال 19: الاستيراد والأسماء الديناميكية<syntaxhighlight lang="php"> | |||
<?php | |||
use My\Full\Classname as Another, My\Full\NSname; | |||
$obj = new Another; // instantiates object of class My\Full\Classname | |||
$a = 'Another'; | |||
$obj = new $a; // instantiates object of class Another | |||
?> | |||
</syntaxhighlight>تؤثّر عملية الاستيراد على الأسماء غير المؤهلة والمؤهّلة فقط، أما الأسماء المؤهّلة بالكامل فتكون مطلقة ولا تتأثر بعملية الاستيراد. | |||
المثال 20: الاستيراد والأسماء المؤهّلة بالكامل<syntaxhighlight lang="php"> | |||
<?php | |||
use My\Full\Classname as Another, My\Full\NSname; | |||
$obj = new Another; // instantiates object of class My\Full\Classname | |||
$obj = new \Another; // instantiates object of class Another | |||
$obj = new Another\thing; // instantiates object of class My\Full\Classname\thing | |||
$obj = new \Another\thing; // instantiates object of class Another\thing | |||
?> | |||
</syntaxhighlight> | |||
===قواعد النطاقات في عملية التصدير=== | |||
يجب التصريح عن الكلمة المفتاحية use في نطاق الملف الخارجي (أي النطاق العام global) أو داخل تصريحات مجالات الأسماء؛ وذلك لأن عملية الاستيراد تتمّ في وقت التصريف وليس في وقت التشغيل؛ لذا لا يمكن تحديدها بنطاق. يعرض المثال التالي طريقة غير صحيحة لاستخدام الكلمة المفتاحية use: | |||
المثال 21: طريقة استيراد غير صحيحة<syntaxhighlight lang="php"> | |||
<?php | |||
namespace Languages; | |||
function toGreenlandic() | |||
{ | |||
use Languages\Danish; | |||
// ... | |||
} | |||
?> | |||
</syntaxhighlight>ملاحظة: تسري قواعد الاستيراد في كلّ ملف على حدة، وهذا يعني أنّ الملفات المضمّنة لن ترث قواعد الاستيراد الخاصّة بالملف الأب. | |||
===تجميع تصريحات use=== | |||
في الإصدار 7.0 وما بعده من PHP أصبح بالإمكان تجميع الأصناف والدوال والثوابت المستوردة من مجال الأسماء ذاته في عبارة use واحدة.<syntaxhighlight lang="php"> | |||
<?php | |||
// قبل الإصدار السابع | |||
use some\namespace\ClassA; | |||
use some\namespace\ClassB; | |||
use some\namespace\ClassC as C; | |||
use function some\namespace\fn_a; | |||
use function some\namespace\fn_b; | |||
use function some\namespace\fn_c; | |||
use const some\namespace\ConstA; | |||
use const some\namespace\ConstB; | |||
use const some\namespace\ConstC; | |||
// بعد الإصدار السابع | |||
use some\namespace\{ClassA, ClassB, ClassC as C}; | |||
use function some\namespace\{fn_a, fn_b, fn_c}; | |||
use const some\namespace\{ConstA, ConstB, ConstC}; | |||
</syntaxhighlight> | |||
== [[PHP/namespaces|المجال العام]] == | == [[PHP/namespaces|المجال العام]] == | ||
تضع اللغة جميع الأصناف والدوال في المجال العام في حال عدم تعريف أي مجال أسماء، أي كما كان الحال قبل دعم ميزة مجالات الأسماء في PHP. | تضع اللغة جميع الأصناف والدوال في المجال العام في حال عدم تعريف أي مجال أسماء، أي كما كان الحال قبل دعم ميزة مجالات الأسماء في PHP. إن استخدام الرمز \ قبل اسم الصنف أو الدالة يعني أنّ ذلك الاسم مطلوب من المجال العام حتى لو استخدم ضمن مجال أسماء معين. | ||
المثال 22: استخدام المجال العام<syntaxhighlight lang="php"> | |||
<?php | |||
namespace A\B\C; | |||
/* This function is A\B\C\fopen */ | |||
function fopen() { | |||
/* ... */ | |||
$f = \fopen(...); // call global fopen | |||
return $f; | |||
} | |||
?> | |||
</syntaxhighlight> | |||
== [[PHP/namespaces|استخدام مجالات الأسماء: اللجوء إلى الدوال/الثوابت العامة]] == | == [[PHP/namespaces|استخدام مجالات الأسماء: اللجوء إلى الدوال/الثوابت العامة]] == | ||
عندما تلاقي اللغة اسمًا غير مؤهّل في اسم صنف أو دالة أو ثابت ما، فإنّها تحلل هذه الأسماء بأولويات مختلفة. | عندما تلاقي اللغة اسمًا غير مؤهّل في اسم صنف أو دالة أو ثابت ما، فإنّها تحلل هذه الأسماء بأولويات مختلفة. تحلّل اللغة أسماء الأصناف إلى اسم مجال الأسماء الحالي، وللوصول إلى الأصناف الداخلية أو غير المنتمية إلى مجال أسماء يجب الإشارة إلى هذه الأصناف باسمها المؤهّل بالكامل كما في المثال التالي: | ||
المثال 23: الوصول إلى الأصناف العامة داخل مجال الأسماء | |||
المتغير <code>$a</code> في المثال التالي هو كائن للصنف <code>A\B\C\Exception</code> أما المتغيّر <code>$b</code> فهو كائن للصنف <code>Exception</code>، أما المتغيّر $c فسيطلق خطأ من نوع fatal لأنّ الصنف <code>A\B\C\ArrayObject</code> غير موجود.<syntaxhighlight lang="php"> | |||
<?php | |||
namespace A\B\C; | |||
class Exception extends \Exception {} | |||
$a = new Exception('hi'); | |||
$b = new \Exception('hi'); | |||
$c = new ArrayObject; | |||
?> | |||
</syntaxhighlight>أما بالنسبة للدوال والثوابت فإنّ PHP تلجأ إلى الدوال أو الثوابت العامة في حال عدم وجود الدالة أو الثابت غير المنتميين إلى مجال أسماء. | |||
المثال 24: اللجوء إلى الدوال/الثوابت داخل مجال الأسماء<syntaxhighlight lang="php"> | |||
<?php | |||
namespace A\B\C; | |||
const E_ERROR = 45; | |||
function strlen($str) | |||
{ | |||
return \strlen($str) - 1; | |||
} | |||
echo E_ERROR, "\n"; // prints "45" | |||
echo INI_ALL, "\n"; // prints "7" - falls back to global INI_ALL | |||
echo strlen('hi'), "\n"; // prints "1" | |||
if (is_array('hi')) { // prints "is not array" | |||
echo "is array\n"; | |||
} else { | |||
echo "is not array\n"; | |||
} | |||
?> | |||
</syntaxhighlight> | |||
== قواعد تمييز الأسماء == | |||
فيما يلي بعض التعريفات المهمّة التي تمهّد لقواعد التمييز هذه: | |||
===تعريفات اسم مجال الأسماء=== | |||
*اسم غير مؤهّل (Unqualified name): هو المعرّف الذي لا يتضمن فاصل مجال الأسماء، مثل <code>Foo</code>. | |||
*اسم مؤهّل (Qualified name): هو المعرّف الذي يتضمّن فاصل مجال الأسماء، مثل <code>Foo\Bar</code>. | |||
*اسم مؤهّل بالكامل (Fully qualified name): هو المعرّف الذي يتضمّن فاصل مجال الأسماء والذي يبدأ بهذا الفاصل أيضًا، مثل <code>\Foo\Bar</code>. مجال الأسماء <code>\Foo</code> هو أيضًا اسم مؤهّل بالكامل. | |||
*الاسم النسبي (Relative name): هو المعرّف الذي يبدأ بمجال الأسماء، مثل <code>namespace\Foo\Bar</code>. | |||
تعالج الأسماء تبعًا لقواعد التمييز التالية: | |||
#تحلل الأسماء المؤهّلة بالكامل إلى الاسم من دون إضافة فاصل مجال الأسماء في البداية. تحلّل <code>\A\B</code> مثلًا إلى <code>A\B</code>. | |||
#الأسماء النسبية تحلّل دائمًا إلى الاسم ويستبدل مجال الأسماء بمجال الأسماء الحالي. إن كان الاسم موجودًا في مجال الأسماء العام، فإنّ المقطع <code>namespace\</code> يحذف من الاسم. على سبيل المثال يحلّل <code>namespace\A</code> داخل مجال الأسماء <code>X\Y</code> إلى <code>X\Y\A</code>، ويحلّل نفس الاسم في مجال الأسماء العام إلى <code>A</code>. | |||
#يترجم المقطع الأول من الأسماء المؤهّلة بالكامل حسب جدول استيراد <code>class/name</code> الحالي. على سبيل المثال: إن تم استيراد الاسم <code>A\B\C</code> على أنه <code>C</code>، فإن الاسم <code>C\D\E</code> سيترجم إلى <code>A\B\C\D\E</code>. | |||
#في حال عدم تطبيق أي قاعدة استيراد على الأسماء المؤهّلة بالكامل فإنّ مجال الأسماء الحالي يضاف إلى بداية الاسم. فمثلًا، يحلّل الاسم <code>C\D\E</code> في مجال الأسماء <code>A\B</code> إلى <code>A\B\C\D\E</code>. | |||
#يترجم الاسم غير المؤهّل بالاعتماد على جدول الاستيراد الحالي إلى نوع الرمز المقابل. وهذا يعني أن الأسماء الشبيهة بالأصناف ستترجم بالاعتماد على جدول استيراد <code>class/namespace</code>، وتترجم الدوال بالاعتماد على جدول استيراد الدالة والثوابت بالاعتماد على جدول استيراد الثابت. فمثلًا بعد استخدام <code>A\B\C</code> يحلّل التعبير <code>new C()</code> إلى الاسم <code>A\B\C()</code>. كذلك الأمر بعد استخدام الدالة <code>A\B\fn;</code> فإن التعبير <code>fn()</code> سيحلّل إلى الاسم <code>A\B\fn</code>. | |||
#إن كان الاسم غير المؤهّل يشير إلى رمز شبيه بالصنف وفي حال عدم تطبيق أي قاعدة استيراد، سيضاف إلى اسم المجال الحالي إلى بداية الاسم. فعلى سبيل المثال تحلّل العبارة <code>new C()</code> داخل مجال الأسماء <code>A\B</code> إلى الاسم <code>A\B\C</code>. | |||
#في حال عدم تطبيق أي قاعدة استيراد وكان الاسم غير المؤهل لدالة أو ثابت وكانت الشيفرة خارج المجال الام، فإن الاسم سيحلّل في وقت التشغيل. فلو افترضنا أن الشيفرة ضمن مجال الأسماء <code>A\B</code> فإن استدعاء الدالة <code>foo()</code> سيحّلل إلى: | |||
##سيجري البحث عن دالة من مجال الأسماء الحالي: <code>A\B\foo()</code>. | |||
##سيجري البحث عن الدالة العامة <code>foo()</code> واستدعائها. | |||
المثال 25: مثال يوضح طريقة تحليل الأسماء | |||
ليكن لدينا ملف PHP الذي يحتوي على ما يلي (قسّمناه إلى أقسام ليسهل شرحه):<syntaxhighlight lang="php"> | |||
<?php | |||
namespace A; | |||
use B\D, C\E as F; | |||
?> | |||
</syntaxhighlight>سنحاول أولًا استدعاء الدالة <code>foo</code> في مجال الأسماء <code>A</code>، ثم لن يُعثَر عليها وستُستدعى الدالة <code>foo</code> في المجال العام:<syntaxhighlight lang="php"> | |||
<?php | |||
foo(); | |||
?> | |||
</syntaxhighlight>استدعاء الدالة <code>foo</code> المُعرَّفة في المجال العام:<syntaxhighlight lang="php"> | |||
<?php | |||
\foo(); | |||
?> | |||
</syntaxhighlight>استدعاء الدالة <code>foo</code> المُعرَّفة في مجال الأسماء <code>A/my</code>:<syntaxhighlight lang="php"> | |||
<?php | |||
my\foo(); | |||
?> | |||
</syntaxhighlight>محاولة استدعاء الدالة <code>F</code> في مجال الأسماء <code>A</code>، ثم استدعاء الدالة العام <code>F</code>:<syntaxhighlight lang="php"> | |||
<?php | |||
F(); | |||
?> | |||
</syntaxhighlight>إنشاء كائن من الصنف <code>B</code> المُعرَّفة في مجال الأسماء <code>A</code>، وإن لم يُعثَر عليه فسيحاول المُفسِّر التحميل التلقائي للصنف <code>A/B</code>:<syntaxhighlight lang="php"> | |||
<?php | |||
new B(); | |||
?> | |||
</syntaxhighlight>إنشاء كائن من الصنف <code>D</code> المُعرَّفة في مجال الأسماء <code>B</code> (ألقِ نطرةً على تعبير <code>import</code> أعلاه)، وإن لم يُعثَر عليه فسيحاول المُفسِّر التحميل التلقائي للصنف <code>B/D</code>:<syntaxhighlight lang="php"> | |||
<?php | |||
new D(); | |||
?> | |||
</syntaxhighlight>إنشاء كائن من الصنف <code>E</code> المُعرَّف في مجال الأسماء <code>C</code> (أنظر مليًا إلى تعبير <code>import</code>)، وإن لم يُعثَر عليه فسيحاول المُفسِّر التحميل التلقائي للصنف <code>C/E</code>:<syntaxhighlight lang="php"> | |||
<?php | |||
new F(); | |||
?> | |||
</syntaxhighlight>إنشاء كائن من الصنف <code>B</code> المُعرَّف في المجال العام، وإن لم يكن موجودًا فسيحاول المُفسِّر التحميل التلقائي للصنف <code>B</code>:<syntaxhighlight lang="php"> | |||
<?php | |||
new \B(); | |||
?> | |||
</syntaxhighlight>إنشاء كائن من الصنف <code>D</code> المُعرَّف في المجال العام، وإن لم يكن موجودًا فسيحاول المُفسِّر التحميل التلقائي للصنف <code>D</code>:<syntaxhighlight lang="php"> | |||
<?php | |||
new \D(); | |||
?> | |||
</syntaxhighlight>إنشاء كائن من الصنف <code>F</code> المُعرَّف في المجال العام، وإن لم يكن موجودًا فسيحاول المُفسِّر التحميل التلقائي للصنف <code>F</code>:<syntaxhighlight lang="php"> | |||
== | <?php | ||
new \F(); | |||
?> | |||
</syntaxhighlight>استدعاء الدالة <code>foo</code> من مجال الأسماء <code>A/B</code>:<syntaxhighlight lang="php"> | |||
<?php | |||
B\foo(); | |||
?> | |||
</syntaxhighlight>استدعاء الدالة <code>foo</code> التابعة للصنف <code>B</code> المُعرَّف في مجال الأسماء <code>A</code>، وإذا لم الصنف <code>A/B</code> موجودًا فسيحاول المُفسِّر التحميل التلقائي للصنف <code>A/B</code>:<syntaxhighlight lang="php"> | |||
<?php | |||
B::foo(); | |||
?> | |||
</syntaxhighlight>استدعاء الدالة <code>foo</code> التابعة للصنف <code>D</code> المُعرَّف في مجال الأسماء <code>B</code>، وإذا لم الصنف <code>B/D</code> موجودًا فسيحاول المُفسِّر التحميل التلقائي للصنف <code>B/D</code>:<syntaxhighlight lang="php"> | |||
<?php | |||
D::foo(); | |||
?> | |||
</syntaxhighlight>استدعاء الدالة <code>foo</code> من مجال الأسماء <code>B</code>:<syntaxhighlight lang="php"> | |||
<?php | |||
\B\foo(); | |||
?> | |||
</syntaxhighlight>استدعاء الدالة <code>foo</code> من الصنف <code>B</code> المُعرَّف في المجال العام، وإن لم يكن الصنف <code>B</code> موجودًا فسيحاول المُفسِّر التحميل التلقائي للصنف <code>B</code>:<syntaxhighlight lang="php"> | |||
<?php | |||
\B::foo(); | |||
?> | |||
</syntaxhighlight>استدعاء الدالة <code>foo</code> التابعة للصنف <code>B</code> من مجال الأسماء <code>A/A</code>، وإذا لم يكن الصنف <code>A/A/B</code> موجودًا فسيحاول المُفسِّر التحميل التلقائي للصنف <code>A/A/B</code>:<syntaxhighlight lang="php"> | |||
<?php | |||
A\B::foo(); | |||
?> | |||
</syntaxhighlight>استدعاء الدالة <code>foo</code> التابعة للصنف <code>B</code> من مجال الأسماء <code>A</code>، وإذا لم يكن الصنف <code>A/B</code> موجودًا فسيحاول المُفسِّر التحميل التلقائي للصنف <code>A/B</code>:<syntaxhighlight lang="php"> | |||
<?php | |||
\A\B::foo(); | |||
?> | |||
</syntaxhighlight> | |||
== الأسئلة المتداولة: أمور يجب عليك معرفتها حول مجالات الأسماء == | |||
تقسم هذه الأسئلة المتداولة إلى قسمين: الأسئلة الشائعة، وبعض الاستخدامات التي من المفيد استيعابها بشكل كامل. | تقسم هذه الأسئلة المتداولة إلى قسمين: الأسئلة الشائعة، وبعض الاستخدامات التي من المفيد استيعابها بشكل كامل. | ||
===أنا لا أستخدم مجالات الأسماء هل علي الاهتمام بهذا؟=== | |||
لا. لن تؤثّر مجالات الأسماء على شيفرتك الحالية، أو شيفرة ستكتبها في المستقبل ولا تتضمن مجالات الأسماء. يمكنك كتابة الشيفرة التالية إن كنت ترغب بذلك: | |||
المثال 26: الوصول إلى الأصناف العامة خارج مجال الأسماء<syntaxhighlight lang="php"> | |||
<?php | |||
$a = new \stdClass; | |||
?> | |||
</syntaxhighlight>وهذا مكافئ لما يلي: | |||
المثال 27: الوصول إلى الأصناف العامة خارج مجال الأسماء<syntaxhighlight lang="php"> | |||
<?php | |||
$a = new stdClass; | |||
?> | |||
</syntaxhighlight> | |||
===كيف أستخدم الأصناف الداخلية أو العامة في مجال الأسماء؟=== | |||
المثال 28: الوصول إلى الأصناف الداخلية في مجالات الأسماء<syntaxhighlight lang="php"> | |||
<?php | |||
namespace foo; | |||
$a = new \stdClass; | |||
function test(\ArrayObject $typehintexample = null) {} | |||
$a = \DirectoryIterator::CURRENT_AS_FILEINFO; | |||
// توسيع صنف داخلي أو عام | |||
class MyException extends \Exception {} | |||
?> | |||
</syntaxhighlight> | |||
===كيف أستخدم الأصناف أو الدوال أو الثوابت التابعة لمجال أسماء معين داخل ذلك المجال؟=== | |||
المثال 29: الوصول إلى الأصناف أو الدوال أو الثوابت الداخلية في مجالات الأسماء<syntaxhighlight lang="php"> | |||
<?php | |||
namespace foo; | |||
class MyClass {} | |||
// استخدام صنف من مجال الأسماء الحالي كإشارة إلى النوع | |||
function test(MyClass $typehintexample = null) {} | |||
// طريقة أخرى لاستخدام الصنف من مجال الأسماء الحالي كإشارة إلى النوع | |||
function test(\foo\MyClass $typehintexample = null) {} | |||
// توسيع الصنف من مجال الأسماء الحالي | |||
class Extended extends MyClass {} | |||
// الوصول إلى دالة عامة | |||
$a = \globalfunc(); | |||
// الوصول إلى ثابت عام | |||
$b = \INI_ALL; | |||
?> | |||
</syntaxhighlight> | |||
===كيف سيُحلّل اسم مثل <code>\my\name</code> أو <code>\name</code>؟=== | |||
تحلّل الأسماء التي تبدأ بالرمز <code>\</code> دائمًا إلى الهيئة ذاتها، لذا فإنّ الاسم <code>\my\name</code> سيحلّل إلى <code>my\name</code> والاسم <code>\Exception</code> سيحلّل إلى <code>Exception</code>. | |||
المثال 30: الأسماء المؤهّلة بالكامل<syntaxhighlight lang="php"> | |||
<?php | |||
namespace foo; | |||
$a = new \my\name(); // instantiates "my\name" class | |||
echo \strlen('hi'); // calls function "strlen" | |||
$a = \INI_ALL; // $a is set to the value of constant "INI_ALL" | |||
?> | |||
</syntaxhighlight> | |||
===كيف سيحلّل اسم مثل <code>my\name</code>؟=== | |||
تحلّل الأسماء التي تحتوي على الرمز <code>\</code> ولكنّها لا تبدأ به بطريقتين مختلفتين: | |||
إن كانت هناك عبارة <code>import</code> تضع اسمًا بديلًا لـ <code>my</code> فإنّ الاسم البديل سيطبّق أيضًا على <code>my</code> في <code>my\name</code>. | |||
في حال عدم وجود اسم بديل، يصبح اسم مجال الأسماء الحالي هو <code>my\name</code>. | |||
المثال 31: الأسماء المؤهّلة<syntaxhighlight lang="php"> | |||
<?php | |||
namespace foo; | |||
use blah\blah as foo; | |||
$a = new my\name(); // instantiates "foo\my\name" class | |||
foo\bar::name(); // calls static method "name" in class "blah\blah\bar" | |||
my\bar(); // calls function "foo\my\bar" | |||
$a = my\BAR; // sets $a to the value of constant "foo\my\BAR" | |||
?> | |||
</syntaxhighlight> | |||
===كيف سيحلّل اسم صنف غير مؤهّل مثل <code>name</code>؟=== | |||
يمكن للأسماء التي لا تحتوي على الرمز <code>\</code> مثل <code>name</code> أن تحلّل بطريقتين مختلفتين: | |||
في حال وجود عبارة <code>import</code> تضع اسمًا بديلًا للاسم <code>name</code> فيستخدم الاسم البديل، وإلا فإنّ اسم مجال الأسماء الحالي يصبح <code>name</code>. | |||
المثال 23: أسماء الأصناف غير المؤهّلة<syntaxhighlight lang="php"> | |||
<?php | |||
namespace foo; | |||
use blah\blah as foo; | |||
$a = new name(); // instantiates "foo\name" class | |||
foo::name(); // calls static method "name" in class "blah\blah" | |||
?> | |||
</syntaxhighlight> | |||
===كيف سيحلّل اسم دالة أو ثابت غير مؤهّل مثل <code>name</code>؟=== | |||
تحلّل أسماء الدوال والثوابت التي لا تحتوي على الرمز <code>\</code> بطريقتين مختلفتين: | |||
الأولى: يصبح اسم مجال الأسماء الحالي <code>name</code>. | |||
الثانية: إن كان اسم الثابت أو الدالة غير موجود في مجال الأسماء الحالي، تلجأ اللغة إلى استخدام اسم عام للدالة أو الثابت في حال توفره. | |||
المثال 33: أسماء دوال وثوابت غير مؤهّلة<syntaxhighlight lang="php"> | |||
<?php | |||
namespace foo; | |||
use blah\blah as foo; | |||
const FOO = 1; | |||
function my() {} | |||
function foo() {} | |||
function sort(&$a) | |||
{ | |||
\sort($a); // calls the global function "sort" | |||
$a = array_flip($a); | |||
return $a; | |||
} | |||
my(); // calls "foo\my" | |||
$a = strlen('hi'); // calls global function "strlen" because "foo\strlen" does not exist | |||
$arr = array(1,3,2); | |||
$b = sort($arr); // calls function "foo\sort" | |||
$c = foo(); // calls function "foo\foo" - import is not applied | |||
$a = FOO; // sets $a to value of constant "foo\FOO" - import is not applied | |||
$b = INI_ALL; // sets $b to value of global constant "INI_ALL" | |||
?> | |||
</syntaxhighlight> | |||
===لا يمكن للأسماء المستوردة أن تتضارب مع الأصناف المعرّفة في نفس الملف=== | |||
لا توجد أي مشكلة في الشيفرة التالية: | |||
<code>file1.php</code><syntaxhighlight lang="php"> | |||
<?php | |||
namespace my\stuff; | |||
class MyClass {} | |||
?> | |||
another.php | |||
<?php | |||
namespace another; | |||
class thing {} | |||
?> | |||
</syntaxhighlight><code>file2.php</code><syntaxhighlight lang="php"> | |||
<?php | |||
namespace my\stuff; | |||
include 'file1.php'; | |||
include 'another.php'; | |||
use another\thing as MyClass; | |||
$a = new MyClass; // instantiates class "thing" from namespace another | |||
?> | |||
</syntaxhighlight>لا يوجد تضارب في الأسماء مع أنّ الصنف <code>MyClass</code> موجود ضمن مجال الأسماء <code>my\stuff</code>؛ وذلك لأنّ الصنف <code>MyClass</code> معرّف في ملف منفصل. ولكن المثال التالي سيتسبّب في حدوث خطأ من نوع fatal ناجم عن تضارب في الأسماء؛ وذلك لأنّ الصنف <code>MyClass</code> قد عُرِّف في الملف نفسه مع عبارة <code>use</code>.<syntaxhighlight lang="php"> | |||
<?php | |||
namespace my\stuff; | |||
use another\thing as MyClass; | |||
class MyClass {} // fatal error: MyClass conflicts with import statement | |||
$a = new MyClass; | |||
?> | |||
</syntaxhighlight> | |||
===لا يسمح بتداخل مجالات الأسماء=== | |||
لا تسمح PHP بتداخل مجالات الأسماء:<syntaxhighlight lang="php"> | |||
<?php | |||
namespace my\stuff { | |||
namespace nested { | |||
class foo {} | |||
} | |||
} | |||
?> | |||
</syntaxhighlight>ولكن يمكن محاكاة عملية تداخل مجالات الأسماء بسهولة:<syntaxhighlight lang="php"> | |||
<?php | |||
namespace my\stuff\nested { | |||
class foo {} | |||
} | |||
?> | |||
</syntaxhighlight> | |||
===قبل الإصدار 5.6 من PHP لا يمكن استيراد الدوال أو الثوابت باستخدام العبارة <code>use</code>=== | |||
قبل الإصدار 5.6 من اللغة كانت مجالات الأسماء وأسماء الأصناف هي العناصر الوحيدة التي تتأثر بعبارة <code>use</code>. ولغرض تقصير اسم ثابت أو دالة طويل يجب استيراد مجال الأسماء الذي يحتويها.<syntaxhighlight lang="php"> | |||
<?php | |||
namespace mine; | |||
use ultra\long\ns\name; | |||
$a = name\CONSTANT; | |||
name\func(); | |||
?> | |||
</syntaxhighlight>أصبح في الإمكان تعيين أسماء بديلة أو استيراد أسماء الدوال والثوابت في الإصدار 5.6 وما بعده من PHP. | |||
===يجب أن تهربّ الأسماء الديناميكية لمجالات الأسماء (المعرّفات المحاطة بعلامة اقتباس) رمز الخطّ المائل <code>\</code>=== | |||
من الضروي جدًّا إدراك أنّه بسبب استخدام الرمز <code>\</code> كحرف للتهريب ضمن السلاسل النصية، فإنّه يجب استخدام هذا الرمز مرتين داخل السلاسل النصية لتجنّب حدوث مشاكل غير متوقعة: | |||
المثال 34: مخاطر استخدام أسماء غير منتمية لمجال أسماء داخل سلسلة نصّية محاطة بعلامة اقتباس مزدوجة | |||
لاحظ أنّ الرمز <code>\n</code> يعني سطرًا جديدًا داخل السلاسل النصية المحاطة بعلامة اقتباس مزدوجة.<syntaxhighlight lang="php"> | |||
<?php | |||
$a = "dangerous\name"; | |||
$obj = new $a; | |||
$a = 'not\at\all\dangerous'; | |||
// لا مشكلة هنا على الإطلاق | |||
$obj = new $a; | |||
?> | |||
</syntaxhighlight>أما السلال النصّية المحاطة بعلامة اقتباس مفردة فلا مشكلة في استخدام الرمز <code>\</code> فيها، ومع ذلك ينصح بعدم استخدام هذا الرمز في جميع أنواع السلاسل النصية. | |||
===تؤدي الإشارة إلى الثوابت غير المعرّفة باستخدام رمز الخطّ المائل <code>\</code> إلى حدوث خطأ من نوع fatal=== | |||
ستطلق اللغة أي ثابت غير معرّف وغير مؤهّل مثل <code>FOO</code> ملاحظة تخبرك بأنّ اللغة قد افترضت أن <code>FOO</code> هي قيمة الثابت. في حال لم تعثر اللغة على أي ثابت مؤهّل أو مؤهّل بالكامل ويتضمن الرمز \، فإنّها ستطلق خطأً من نوع fatal. | |||
المثال 35: ثوابت غير معرّفة<syntaxhighlight lang="php"> | |||
<?php | |||
namespace bar; | |||
$a = FOO; // produces notice - undefined constants "FOO" assumed "FOO"; | |||
$a = \FOO; // fatal error, undefined namespace constant FOO | |||
$a = Bar\FOO; // fatal error, undefined namespace constant bar\Bar\FOO | |||
$a = \Bar\FOO; // fatal error, undefined namespace constant Bar\FOO | |||
?> | |||
</syntaxhighlight> | |||
===لا يمكن تجاوز (إعادة تعريف) الثوابت الخاصة <code>NULL</code> و <code>TRUE</code> و <code>FALSE</code> و <code>ZEND_THREAD_SAFE</code> و <code>ZEND_DEBUG_BUILD</code>=== | |||
ستؤدي أي محاولة لتعريف ثابت خاص باللغة ينتمي إلى مجال أسماء معين إلى حدوث خطأ من نوع fatal. | |||
المثال 36: ثوابت غير معرّفة<syntaxhighlight lang="php"> | |||
<?php | |||
namespace bar; | |||
const NULL = 0; // fatal error; | |||
const true = 'stupid'; // fatal error; | |||
// إلخ... | |||
?> | |||
</syntaxhighlight> | |||
== مصادر == | == <span> مصادر</span> == | ||
* [http://php.net/manual/en/language.namespaces.php صفحة Namespaces في توثيق PHP الرسمي.] | * [http://php.net/manual/en/language.namespaces.php صفحة Namespaces في توثيق PHP الرسمي.] | ||
[[تصنيف:PHP|{{SUBPAGENAME}}]] | [[تصنيف:PHP|{{SUBPAGENAME}}]] | ||
[[تصنيف:PHP Namespaces|{{SUBPAGENAME}}]] | [[تصنيف:PHP Namespaces|{{SUBPAGENAME}}]] |
المراجعة الحالية بتاريخ 05:03، 4 أبريل 2018
ما هي مجالات الأسماء؟ التعريف الواسع لمجالات الأسماء هو: طريقة لتغليف العناصر، ويمكن رؤية هذا الأمر كمفهوم مجرد في عدة أماكن. فعلى سبيل المثال، تعمل المجلدات في أنظمة التشغيل المختلفة على تجميع الملفات المرتبطة ببعضها البعض، وهي بمثابة مجال أسماء لتلك الملفات. لنأخذ المثال التالي للتوضيح: يمكن أن يكون الملف foo.txt
موجودًا في كلا المجلدين /home/greg
و /home/other
ولكن لا يمكن لنسختين من هذا الملف أن تكونا في المجلد ذاته، وإضافة لذلك يتطلب الوصول إلى الملف foo.txt
من خارج المجلد /home/greg
إضافة اسم المجلّد إلى اسم الملف باستخدام فاصل المجلدات للحصول على المسار /home/greg/foo.txt
. وهذا المبدأ مشابه لمفهوم مجالات الأسماء في عالم البرمجة.
الإصدار | الوصف |
---|---|
7.0.0 | Added Group use Declarations |
صُمِّمت مجالات الأسماء في لغة PHP لحل مشكلتين تواجهان أصحاب مكتبات وتطبيقات PHP عند كتابة شيفرات تتضمن عناصر قابلة لإعادة الاستخدام مثل الأصناف والدوال:
- التضارب الحاصل بين الشيفرة المكتوبة وبين الأصناف والدوال والثوابت الداخلية الخاصة باللغة أو الخاصة بالطرف الثالث (أصحاب المكتبات والملحقات).
- القدرة على اختصار (أو تقصير) الأسماء الطويلة جدًّا والتي وضعت للتخفيف من المشكلة الأولى وزيادة مقروئية الشيفرة المصدرية.
تقدّم مجالات الأسماء في PHP وسيلة لتجميع الأصناف والواجهات والدوال والثوابت المرتبطة ببعضها البعض. إليك مثالًا عن صيغة مجالات الأسماء في PHP:
المثال 1: صيغة مجالات الأسماء
<?php
namespace my\name;
// راجع صفحة \تعريف مجالات الأسماء
class MyClass {}
function myfunction() {}
const MYCONST = 1;
$a = new MyClass;
$c = new \my\name\MyClass;
// راجع صفحة المجال العام
$a = strlen('hi');
// راجع استخدام مجالات الأسماء: اللجوء إلى الدوال والثوابت العامة
$d = namespace\MYCONST;
// see "namespace operator and __NAMESPACE__
// constant" section
$d = __NAMESPACE__ . '\MYCONST';
echo constant($d);
// راجع فصل "مجالات الأسماء وميزات اللغة الديناميكية"
?>
ملاحظة: أسماء مجالات الأسماء PHP و php والأسماء المركبة منها (مثل PHP\Classes
) هي أسماء محجوزة في اللغة ولا يمكن استخدامها في الشيفرة.
تعريف مجالات الأسماء
صحيح أنّه يمكن لأي شيفرة صالحة أن تكون ضمن مجال الأسماء إلا أنّ أنواع الشيفرة التالي هي الوحيدة التي تتأثر بمجالات الأسماء: الأصناف (وبضمنها الأصناف المجردة [abstract classes] والسمات [traits]) والواجهات (interfaces) والدوال والثوابت.
تعرّف مجالات الأسماء باستخدام الكلمة المفتاحية namespace، ويجب التصريح عن مجال الأسماء في بداية الملف قبل أي شيفرة أخرى، باستثناء الكلمة المفتاحية declare.
المثال 2: التصريح عن مجال أسماء مفرد
<?php
namespace MyProject;
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
?>
تسمح اللغة بالتصريح عن البنية declare
فقط قبل التصريح عن مجال الأسماء وذلك لتعريف الترميز الذي يعتمد ملف الشيفرة المصدرية، ولا تسمح باستخدام أي شيفرة غير تابعة للغة أو حتّى المسافات البيضاء:
المثال 3: التصريح عن مجال أسماء مفرد
<?php
namespace MyProject;
// ستطلق هذه الشيفرة خطأً، إذ يجب أن يكون التصريح عن مجال الاسم في بداية الشيفرة.
?>
بالإضافة إلى ذلك، وعلى العكس من بنى PHP الأخرى، فإنّ اللغة تسمح بتعريف نطاق الاسم نفسه في ملفات متعدّدة، ممّا يسمح بتقسيم محتويات نطاق الاسم عبر الملفات.
تعريف مجالات الأسماء الفرعية
كما هو الحال مع المجلدات والملفات فإنّ بالإمكان تحديد تسلسل هرمي لأسماء مجالات الأسماء؛ لذا يمكن تعريف مجالات أسماء فرعية:
المثال 4: التصريح عن مجال اسم مفرد مع تسلسل هرمي
<?php
namespace MyProject\Sub\Level;
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
?>
ينشئ المثال السابق الثابت MyProject\Sub\Level\CONNECT_OK
، والصنف MyProject\Sub\Level\Connection
والدالة MyProject\Sub\Level\connect
.
تعريف مجالات أسماء متعددة في نفس الملف
يمكن التصريح عن مجالات أسماء متعددة في الملف نفسه، وهناك صيغتان للقيام بذلك:
المثال 5: التصريح عن مجالات أسماء متعددة بصيغة الجمع البسيطة (simple combination syntax)
<?php
namespace MyProject;
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
namespace AnotherProject;
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
?>
لا ينصح باستخدام هذه الصيغة لجمع مجالات الأسماء في ملف واحد، بل ينصح باستخدام صيغة الأقواس البديلة. المثال 6: التصريح عن مجالات أسماء متعددة بواسطة صيغة الأقواس (bracketed syntax)
<?php
namespace MyProject {
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
}
namespace AnotherProject {
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
}
?>
ينصح بشدّة تجنّب دمج نطاقات أسماء متعددة في ملف مفرد، والحالة الشائعة هي دمج شيفرات PHP متعددة في الملف نفسه.
يسمح باستخدام صيغة الأقواس فقط في حال الرغبة في دمج شيفرة عامة ليست موجودة في مجال أسماء مع شيفرة أخرى موجودة ضمن مجال أسماء، ويجب إحاطة الشيفرة العامة بعبارة namespace دون تحديد اسم لهذا المجال:
المثال 7: التصريح عن مجالات أسماء متعددة مع شيفرة غير موجودة ضمن مجال أسماء
<?php
namespace MyProject {
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
}
namespace {
// الشيفرة العامة
session_start();
$a = MyProject\connect();
echo MyProject\Connection::start();
}
?>
لا تسمح اللغة بوجود أي شيفرة خارج أقواس مجال الأسماء باستثناء عبارة declare. المثال 8: التصريح عن مجالات أسماء متعددة وشيفرة غير موجودة في مجال أسماء
<?php
declare(encoding='UTF-8');
namespace MyProject {
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
}
namespace {
// شيفرة عامة
session_start();
$a = MyProject\connect();
echo MyProject\Connection::start();
}
?>
استخدام مجالات الأسماء: الأساسيات
من الضروري قبل الخوض في موضوع استخدام مجالات الأسماء أن تستوعب الطريق التي تتبعها PHP في التعرف على العنصر الذي ينتمي إلى مجال أسماء معين والذي تطلبه الشيفرة الخاصة بك. يمكننا في هذا الصدد أن نقارن بين مجالات الأسماء وملفات النظام. هناك ثلاث طرائق للوصول إلى ملف معيّن ضمن ملفات النظام:
- الاسم النسبي للملف مثل
foo.txt
، والذي يُحلَّل إلى المسارcurrentdirectory/foo.txt
حيثcurrentdirectory
هو المجلد الحالي، فلو كان المجلّد الحالي هو/home/foo
، فإنّ اسم الملف يصبح /home/foo/foo.txt
- المسار النسبي مثل
subdirectory/foo.txt
، والذي يُحلَّل إلىcurrentdirectory/subdirectory/foo.txt
- اسم الملف المطلق مثل
/main/foo.txt
، والذي يُحلّل إلى/main/foo.txt
يمكن تطبيق المبدأ ذاته على العناصر المنتمية إلى مجال أسماء معيّن في PHP، فعلى سبيل المثال، يمكن الإشارة إلى اسم الصنف بثلاثة طرق:
- الاسم غير المؤهّل (Unqualified name)، أو اسم الصنف غير المتضمن لسابقة مثل
$a = new foo();
أو foo::staticmethod();
. إن كان مجال الأسماء الحالي هوcurrentnamespace
، فإنّ اسم الصنف يُحلّل إلىcurrentnamespace\foo
. وإذا كانت الشيفرة عامة وغير منتمية إلى مجال أسماء فإنّ اسم الصنف يُحلّل إلى foo.تُحلّل أسماء الدوال والثوابت غير المؤهّلة إلى دوال وثوابت عامة إن لم تعرّف الدالة أو الثابت غير المنتمي إلى مجال أسماء. راجع استخدام مجالات الأسماء: اللجوء إلى الدوال أو الثوابت العامة للمزيد من المعلومات. - الأسماء المؤهّلة (Qualified names)، أو اسم الصنف مع سابقة مثل
$a = new subnamespace\foo();
أو subnamespace\foo::staticmethod();
. إن كان اسم مجال الأسماء الحالي هوcurrentnamespace
فإنّ اسم الصنف يحلّل إلىcurrentnamespace\subnamespace\foo
وإن كانت الشيفرة عامة لا تنتمي إلى مجال أسماء فإن اسم الصنف يحلّل إلىsubnamespace\foo
. - الاسم المؤهّل بالكامل (Fully qualified name)، أو اسم الصنف المسبوق بعامل السابقة العامة (global prefix operator) مثل:
$a = new\currentnamespace\foo();
أوcurrentnamespace\foo::staticmethod();
. يُحلّل اسم الصنف دائمًا في هذه الحالة إلى الاسم الحرفي المحدّد في الشيفرة كما هوcurrentnamespace\foo
.
إليك مثالًا عن الأنواع الثلاثة في شيفرة حقيقية:
file1.php
<?php
namespace Foo\Bar\subnamespace;
const FOO = 1;
function foo() {}
class foo
{
static function staticmethod() {}
}
?>
file2.php
<?php
namespace Foo\Bar;
include 'file1.php';
const FOO = 2;
function foo() {}
class foo
{
static function staticmethod() {}
}
/* اسم غير مؤهّل */
foo(); // resolves to function Foo\Bar\foo
foo::staticmethod(); // resolves to class Foo\Bar\foo, method staticmethod
echo FOO; // resolves to constant Foo\Bar\FOO
/* اسم مؤهّل */
subnamespace\foo(); // resolves to function Foo\Bar\subnamespace\foo
subnamespace\foo::staticmethod(); // resolves to class Foo\Bar\subnamespace\foo,
// method staticmethod
echo subnamespace\FOO; // resolves to constant Foo\Bar\subnamespace\FOO
/* اسم مؤهّل بالكامل */
\Foo\Bar\foo(); // resolves to function Foo\Bar\foo
\Foo\Bar\foo::staticmethod(); // resolves to class Foo\Bar\foo, method staticmethod
echo \Foo\Bar\FOO; // resolves to constant Foo\Bar\FOO
?>
لاحظ أنّه لغرض الوصول إلى أي صنف أو دالة أو ثابت في النطاق العام global يمكن استخدام الاسم المؤهّل بالكامل مثل \strlen()
أو \Exception
أو \INI_ALL
.
المثال 9: الوصول إلى الأصناف والدوال والثوابت العامة ضمن مجال الأسماء
<?php
namespace Foo;
function strlen() {}
const INI_ALL = 3;
class Exception {}
$a = \strlen('hi'); // calls global function strlen
$b = \INI_ALL; // accesses global constant INI_ALL
$c = new \Exception('error'); // instantiates global class Exception
?>
مجالات الأسماء وخصائص اللغة الديناميكية
تتأثر طريقة استخدام PHP لمجالات الأسماء بطبيعتها الديناميكية كلغة برمجية؛ لهذا لو أردنا تحويل الشيفرة في المثال التالي إلى شيفرة ضمن مجال أسماء:
المثال 10: الوصول الديناميكي إلى العناصر
<?php
class classname
{
function __construct()
{
echo __METHOD__,"\n";
}
}
function funcname()
{
echo __FUNCTION__,"\n";
}
const constname = "global";
$a = 'classname';
$obj = new $a; // prints classname::__construct
$b = 'funcname';
$b(); // prints funcname
echo constant('constname'), "\n"; // prints global
?>
يجب استخدام الاسم المؤهّل بالكامل (اسم الصنف مع سابقة اسم المجال). لاحظ أنّه نظرًا لعدم وجود فرق بين الاسم المؤهّل (qualified) والاسم المؤهّل بالكامل (fully qualified) داخل اسم صنف أو اسم دالة أو اسم ثابت ديناميكي، فلا حاجة لاستخدام الخط المائل. المثال 11: الوصول الديناميكي لعناصر ضمن مجال أسماء
<?php
namespace namespacename;
class classname
{
function __construct()
{
echo __METHOD__,"\n";
}
}
function funcname()
{
echo __FUNCTION__,"\n";
}
const constname = "namespaced";
/* لاحظ أنّه في حال استخدام علامات الاقتباس المزدوجة يجب استخدام
"\\namespacename\\classname" */
$a = '\namespacename\classname';
$obj = new $a; // prints namespacename\classname::__construct
$a = 'namespacename\classname';
$obj = new $a; // also prints namespacename\classname::__construct
$b = 'namespacename\funcname';
$b(); // prints namespacename\funcname
$b = '\namespacename\funcname';
$b(); // also prints namespacename\funcname
echo constant('\namespacename\constname'), "\n"; // prints namespaced
echo constant('namespacename\constname'), "\n"; // also prints namespaced
?>
تأكّد من قراءة الملاحظة حول تهريب أسماء مجالات الأسماء في السلاسل النصّية.
الكلمة المفتاحية namespace و الثابت __NAMESPACE__
تقدّم PHP طريقتين للوصول المجرّد إلى العناصر ضمن مجال الأسماء الحالي، وهما الثابت السحري __NAMESPACE__
والكلمة المفتاحية namespace
.
تكون قيمة الثابت السحري __NMAESPACE__
سلسلة نصية تحتوي اسم مجال الأسماء الحالي، وبصورة عامة تكون هذه السلسلة النصية فارغة في حال كون الشيفرة لا تنتمي إلى أي مجال أسماء.
المثال 12: مثال على الثابت السحري __NAMESPACE__
وشيفرة تنتمي إلى مجال أسماء
<?php
namespace MyProject;
echo '"', __NAMESPACE__, '"'; // outputs "MyProject"
?>
المثال 13: مثال على الثابت السحري __NAMESPACE__
وشيفرة لا تنتمي إلى مجال أسماء
<?php
echo '"', __NAMESPACE__, '"'; // outputs ""
?>
يمكن الاستفادة من الثابت __NAMESPACE__
في بناء الأسماء بطريقة ديناميكية، فعلى سبيل المثال:
المثال 14: استخدام __NAMESPACE__
لبناء الأسماء بصورة ديناميكية
<?php
namespace MyProject;
function get($classname)
{
$a = __NAMESPACE__ . '\\' . $classname;
return new $a;
}
?>
يمكن استخدام الكلمة المفتاحية namespace
لطلب عنصر من مجال الأسماء الحالي أو مجال الأسماء الفرعي، ويمكن اعتبار هذه الكملة المفتاحية مشابهة للعامل self
في الأصناف.
المثال 15: استخدام العامل namespace
داخل مجال أسماء
<?php
namespace MyProject;
use blah\blah as mine; // see "Using namespaces: Aliasing/Importing"
blah\mine(); // calls function MyProject\blah\mine()
namespace\blah\mine(); // calls function MyProject\blah\mine()
namespace\func(); // calls function MyProject\func()
namespace\sub\func(); // calls function MyProject\sub\func()
namespace\cname::method(); // calls static method "method" of class MyProject\cname
$a = new namespace\sub\cname(); // instantiates object of class MyProject\sub\cname
$b = namespace\CONSTANT; // assigns value of constant MyProject\CONSTANT to $b
?>
المثال 16: استخدام العامل namespace
مع شيفرة عامة
<?php
namespace\func(); // calls function func()
namespace\sub\func(); // calls function sub\func()
namespace\cname::method(); // calls static method "method" of class cname
$a = new namespace\sub\cname(); // instantiates object of class sub\cname
$b = namespace\CONSTANT; // assigns value of constant CONSTANT to $b
?>
استخدام مجالات الأسماء: التسمية بأسماء بديلة/الاستيراد
من الميزات المهمة في مجالات الأسماء هي القدرة على الإشارة إلى اسم خارجي مؤهّل بالكامل (external fully qualified name) باستخدام اسم بديل (alias)، والقدرة على استيراد مجالات الأسماء. هذه الميزة مشابهة للقدرة على إنشاء روابط رمزية للملفات (symbolic links) أو المجلّدات في الأنظمة المبنية على يونكس (unix-based filesystems).
تتضمّن جميع إصدارات PHP التي تدعم مجالات الأسماء ثلاثة أنواع من التسمية البديلة والاستيراد: التسمية لبديلة لاسم الصنف، والتسمية البديلة لاسم الواجهة، والتسمية البديلة لاسم مجال الأسماء. يتيح الإصدار 5.6 وما بعده من PHP التسمية البديلة أو استيراد أسماء الدوال والثوابت.
يمكن استخدام العامل use
لإنشاء التسمية البديلة، والمثال التالي يوضّح الأنواع الخمسة للاستيراد:
المثال 17: استيراد/التسمية البديلة باستخدام العامل use
<?php
namespace foo;
use My\Full\Classname as Another;
// هذا مطابق لما يلي
// My\Full\NSname as NSname
use My\Full\NSname;
// استيراد صنف عام
use ArrayObject;
// استيراد دالة في الإصدار 5.6 وما بعده
use function My\Full\functionName;
// إعادة تسمية دالة في الإصدار 5.6 وما بعده
use function My\Full\functionName as func;
// استيراد ثابت (الإصدار 5.6 وما بعده)
use const My\Full\CONSTANT;
$obj = new namespace\Another; // instantiates object of class foo\Another
$obj = new Another; // instantiates object of class My\Full\Classname
NSname\subns\func(); // calls function My\Full\NSname\subns\func
$a = new ArrayObject(array(1)); // instantiates object of class ArrayObject
// without the "use ArrayObject" we would instantiate an object of class foo\ArrayObject
func(); // calls function My\Full\functionName
echo CONSTANT; // echoes the value of My\Full\CONSTANT
?>
لاحظ أنّه لا حاجة (ولا ينصح بذلك أيضًا) لاستخدام الخط المائل مع الأسماء المنتمية إلى نطاق أسماء معيّن (أسماء مؤهّلة بالكامل تتضمن الرمز الفاصل في مجالات الأسماء مثل Foo\Bar
، مقارنة بالأسماء العامة والتي لا تتضمن هذا الرمز مثل FooBar
)؛ إذ يجب أن تكون الأسماء المستوردة مؤهّلة بالكامل، ولن تعالج بالنسبة إلى مجال الأسماء الحالي.
تدعم PHP كذلك اختصارًا يمكن عن طريقه استخدام عبارات use متعدّدة في نفس السطر.
المثال 18: استيراد/التسمية البديلة باستخدام العامل use
مع دمج عدة عبارات في سطر واحد
<?php
use My\Full\Classname as Another, My\Full\NSname;
$obj = new Another; // instantiates object of class My\Full\Classname
NSname\subns\func(); // calls function My\Full\NSname\subns\func
?>
تنفّذ عملية الاستيراد في وقت التصريف؛ لذا فإنّها لا تؤثر على أسماء الأصناف أو الدوال أو الثوابت الديناميكية. المثال 19: الاستيراد والأسماء الديناميكية
<?php
use My\Full\Classname as Another, My\Full\NSname;
$obj = new Another; // instantiates object of class My\Full\Classname
$a = 'Another';
$obj = new $a; // instantiates object of class Another
?>
تؤثّر عملية الاستيراد على الأسماء غير المؤهلة والمؤهّلة فقط، أما الأسماء المؤهّلة بالكامل فتكون مطلقة ولا تتأثر بعملية الاستيراد. المثال 20: الاستيراد والأسماء المؤهّلة بالكامل
<?php
use My\Full\Classname as Another, My\Full\NSname;
$obj = new Another; // instantiates object of class My\Full\Classname
$obj = new \Another; // instantiates object of class Another
$obj = new Another\thing; // instantiates object of class My\Full\Classname\thing
$obj = new \Another\thing; // instantiates object of class Another\thing
?>
قواعد النطاقات في عملية التصدير
يجب التصريح عن الكلمة المفتاحية use في نطاق الملف الخارجي (أي النطاق العام global) أو داخل تصريحات مجالات الأسماء؛ وذلك لأن عملية الاستيراد تتمّ في وقت التصريف وليس في وقت التشغيل؛ لذا لا يمكن تحديدها بنطاق. يعرض المثال التالي طريقة غير صحيحة لاستخدام الكلمة المفتاحية use:
المثال 21: طريقة استيراد غير صحيحة
<?php
namespace Languages;
function toGreenlandic()
{
use Languages\Danish;
// ...
}
?>
ملاحظة: تسري قواعد الاستيراد في كلّ ملف على حدة، وهذا يعني أنّ الملفات المضمّنة لن ترث قواعد الاستيراد الخاصّة بالملف الأب.
تجميع تصريحات use
في الإصدار 7.0 وما بعده من PHP أصبح بالإمكان تجميع الأصناف والدوال والثوابت المستوردة من مجال الأسماء ذاته في عبارة use واحدة.
<?php
// قبل الإصدار السابع
use some\namespace\ClassA;
use some\namespace\ClassB;
use some\namespace\ClassC as C;
use function some\namespace\fn_a;
use function some\namespace\fn_b;
use function some\namespace\fn_c;
use const some\namespace\ConstA;
use const some\namespace\ConstB;
use const some\namespace\ConstC;
// بعد الإصدار السابع
use some\namespace\{ClassA, ClassB, ClassC as C};
use function some\namespace\{fn_a, fn_b, fn_c};
use const some\namespace\{ConstA, ConstB, ConstC};
المجال العام
تضع اللغة جميع الأصناف والدوال في المجال العام في حال عدم تعريف أي مجال أسماء، أي كما كان الحال قبل دعم ميزة مجالات الأسماء في PHP. إن استخدام الرمز \ قبل اسم الصنف أو الدالة يعني أنّ ذلك الاسم مطلوب من المجال العام حتى لو استخدم ضمن مجال أسماء معين.
المثال 22: استخدام المجال العام
<?php
namespace A\B\C;
/* This function is A\B\C\fopen */
function fopen() {
/* ... */
$f = \fopen(...); // call global fopen
return $f;
}
?>
استخدام مجالات الأسماء: اللجوء إلى الدوال/الثوابت العامة
عندما تلاقي اللغة اسمًا غير مؤهّل في اسم صنف أو دالة أو ثابت ما، فإنّها تحلل هذه الأسماء بأولويات مختلفة. تحلّل اللغة أسماء الأصناف إلى اسم مجال الأسماء الحالي، وللوصول إلى الأصناف الداخلية أو غير المنتمية إلى مجال أسماء يجب الإشارة إلى هذه الأصناف باسمها المؤهّل بالكامل كما في المثال التالي:
المثال 23: الوصول إلى الأصناف العامة داخل مجال الأسماء
المتغير $a
في المثال التالي هو كائن للصنف A\B\C\Exception
أما المتغيّر $b
فهو كائن للصنف Exception
، أما المتغيّر $c فسيطلق خطأ من نوع fatal لأنّ الصنف A\B\C\ArrayObject
غير موجود.
<?php
namespace A\B\C;
class Exception extends \Exception {}
$a = new Exception('hi');
$b = new \Exception('hi');
$c = new ArrayObject;
?>
أما بالنسبة للدوال والثوابت فإنّ PHP تلجأ إلى الدوال أو الثوابت العامة في حال عدم وجود الدالة أو الثابت غير المنتميين إلى مجال أسماء. المثال 24: اللجوء إلى الدوال/الثوابت داخل مجال الأسماء
<?php
namespace A\B\C;
const E_ERROR = 45;
function strlen($str)
{
return \strlen($str) - 1;
}
echo E_ERROR, "\n"; // prints "45"
echo INI_ALL, "\n"; // prints "7" - falls back to global INI_ALL
echo strlen('hi'), "\n"; // prints "1"
if (is_array('hi')) { // prints "is not array"
echo "is array\n";
} else {
echo "is not array\n";
}
?>
قواعد تمييز الأسماء
فيما يلي بعض التعريفات المهمّة التي تمهّد لقواعد التمييز هذه:
تعريفات اسم مجال الأسماء
- اسم غير مؤهّل (Unqualified name): هو المعرّف الذي لا يتضمن فاصل مجال الأسماء، مثل
Foo
. - اسم مؤهّل (Qualified name): هو المعرّف الذي يتضمّن فاصل مجال الأسماء، مثل
Foo\Bar
. - اسم مؤهّل بالكامل (Fully qualified name): هو المعرّف الذي يتضمّن فاصل مجال الأسماء والذي يبدأ بهذا الفاصل أيضًا، مثل
\Foo\Bar
. مجال الأسماء\Foo
هو أيضًا اسم مؤهّل بالكامل. - الاسم النسبي (Relative name): هو المعرّف الذي يبدأ بمجال الأسماء، مثل
namespace\Foo\Bar
.
تعالج الأسماء تبعًا لقواعد التمييز التالية:
- تحلل الأسماء المؤهّلة بالكامل إلى الاسم من دون إضافة فاصل مجال الأسماء في البداية. تحلّل
\A\B
مثلًا إلىA\B
. - الأسماء النسبية تحلّل دائمًا إلى الاسم ويستبدل مجال الأسماء بمجال الأسماء الحالي. إن كان الاسم موجودًا في مجال الأسماء العام، فإنّ المقطع
namespace\
يحذف من الاسم. على سبيل المثال يحلّلnamespace\A
داخل مجال الأسماءX\Y
إلىX\Y\A
، ويحلّل نفس الاسم في مجال الأسماء العام إلىA
. - يترجم المقطع الأول من الأسماء المؤهّلة بالكامل حسب جدول استيراد
class/name
الحالي. على سبيل المثال: إن تم استيراد الاسمA\B\C
على أنهC
، فإن الاسمC\D\E
سيترجم إلىA\B\C\D\E
. - في حال عدم تطبيق أي قاعدة استيراد على الأسماء المؤهّلة بالكامل فإنّ مجال الأسماء الحالي يضاف إلى بداية الاسم. فمثلًا، يحلّل الاسم
C\D\E
في مجال الأسماءA\B
إلىA\B\C\D\E
. - يترجم الاسم غير المؤهّل بالاعتماد على جدول الاستيراد الحالي إلى نوع الرمز المقابل. وهذا يعني أن الأسماء الشبيهة بالأصناف ستترجم بالاعتماد على جدول استيراد
class/namespace
، وتترجم الدوال بالاعتماد على جدول استيراد الدالة والثوابت بالاعتماد على جدول استيراد الثابت. فمثلًا بعد استخدامA\B\C
يحلّل التعبيرnew C()
إلى الاسمA\B\C()
. كذلك الأمر بعد استخدام الدالةA\B\fn;
فإن التعبيرfn()
سيحلّل إلى الاسمA\B\fn
. - إن كان الاسم غير المؤهّل يشير إلى رمز شبيه بالصنف وفي حال عدم تطبيق أي قاعدة استيراد، سيضاف إلى اسم المجال الحالي إلى بداية الاسم. فعلى سبيل المثال تحلّل العبارة
new C()
داخل مجال الأسماءA\B
إلى الاسمA\B\C
. - في حال عدم تطبيق أي قاعدة استيراد وكان الاسم غير المؤهل لدالة أو ثابت وكانت الشيفرة خارج المجال الام، فإن الاسم سيحلّل في وقت التشغيل. فلو افترضنا أن الشيفرة ضمن مجال الأسماء
A\B
فإن استدعاء الدالةfoo()
سيحّلل إلى:- سيجري البحث عن دالة من مجال الأسماء الحالي:
A\B\foo()
. - سيجري البحث عن الدالة العامة
foo()
واستدعائها.
- سيجري البحث عن دالة من مجال الأسماء الحالي:
المثال 25: مثال يوضح طريقة تحليل الأسماء
ليكن لدينا ملف PHP الذي يحتوي على ما يلي (قسّمناه إلى أقسام ليسهل شرحه):
<?php
namespace A;
use B\D, C\E as F;
?>
سنحاول أولًا استدعاء الدالة foo
في مجال الأسماء A
، ثم لن يُعثَر عليها وستُستدعى الدالة foo
في المجال العام:
<?php
foo();
?>
استدعاء الدالة foo
المُعرَّفة في المجال العام:
<?php
\foo();
?>
استدعاء الدالة foo
المُعرَّفة في مجال الأسماء A/my
:
<?php
my\foo();
?>
محاولة استدعاء الدالة F
في مجال الأسماء A
، ثم استدعاء الدالة العام F
:
<?php
F();
?>
إنشاء كائن من الصنف B
المُعرَّفة في مجال الأسماء A
، وإن لم يُعثَر عليه فسيحاول المُفسِّر التحميل التلقائي للصنف A/B
:
<?php
new B();
?>
إنشاء كائن من الصنف D
المُعرَّفة في مجال الأسماء B
(ألقِ نطرةً على تعبير import
أعلاه)، وإن لم يُعثَر عليه فسيحاول المُفسِّر التحميل التلقائي للصنف B/D
:
<?php
new D();
?>
إنشاء كائن من الصنف E
المُعرَّف في مجال الأسماء C
(أنظر مليًا إلى تعبير import
)، وإن لم يُعثَر عليه فسيحاول المُفسِّر التحميل التلقائي للصنف C/E
:
<?php
new F();
?>
إنشاء كائن من الصنف B
المُعرَّف في المجال العام، وإن لم يكن موجودًا فسيحاول المُفسِّر التحميل التلقائي للصنف B
:
<?php
new \B();
?>
إنشاء كائن من الصنف D
المُعرَّف في المجال العام، وإن لم يكن موجودًا فسيحاول المُفسِّر التحميل التلقائي للصنف D
:
<?php
new \D();
?>
إنشاء كائن من الصنف F
المُعرَّف في المجال العام، وإن لم يكن موجودًا فسيحاول المُفسِّر التحميل التلقائي للصنف F
:
<?php
new \F();
?>
استدعاء الدالة foo
من مجال الأسماء A/B
:
<?php
B\foo();
?>
استدعاء الدالة foo
التابعة للصنف B
المُعرَّف في مجال الأسماء A
، وإذا لم الصنف A/B
موجودًا فسيحاول المُفسِّر التحميل التلقائي للصنف A/B
:
<?php
B::foo();
?>
استدعاء الدالة foo
التابعة للصنف D
المُعرَّف في مجال الأسماء B
، وإذا لم الصنف B/D
موجودًا فسيحاول المُفسِّر التحميل التلقائي للصنف B/D
:
<?php
D::foo();
?>
استدعاء الدالة foo
من مجال الأسماء B
:
<?php
\B\foo();
?>
استدعاء الدالة foo
من الصنف B
المُعرَّف في المجال العام، وإن لم يكن الصنف B
موجودًا فسيحاول المُفسِّر التحميل التلقائي للصنف B
:
<?php
\B::foo();
?>
استدعاء الدالة foo
التابعة للصنف B
من مجال الأسماء A/A
، وإذا لم يكن الصنف A/A/B
موجودًا فسيحاول المُفسِّر التحميل التلقائي للصنف A/A/B
:
<?php
A\B::foo();
?>
استدعاء الدالة foo
التابعة للصنف B
من مجال الأسماء A
، وإذا لم يكن الصنف A/B
موجودًا فسيحاول المُفسِّر التحميل التلقائي للصنف A/B
:
<?php
\A\B::foo();
?>
الأسئلة المتداولة: أمور يجب عليك معرفتها حول مجالات الأسماء
تقسم هذه الأسئلة المتداولة إلى قسمين: الأسئلة الشائعة، وبعض الاستخدامات التي من المفيد استيعابها بشكل كامل.
أنا لا أستخدم مجالات الأسماء هل علي الاهتمام بهذا؟
لا. لن تؤثّر مجالات الأسماء على شيفرتك الحالية، أو شيفرة ستكتبها في المستقبل ولا تتضمن مجالات الأسماء. يمكنك كتابة الشيفرة التالية إن كنت ترغب بذلك:
المثال 26: الوصول إلى الأصناف العامة خارج مجال الأسماء
<?php
$a = new \stdClass;
?>
وهذا مكافئ لما يلي: المثال 27: الوصول إلى الأصناف العامة خارج مجال الأسماء
<?php
$a = new stdClass;
?>
كيف أستخدم الأصناف الداخلية أو العامة في مجال الأسماء؟
المثال 28: الوصول إلى الأصناف الداخلية في مجالات الأسماء
<?php
namespace foo;
$a = new \stdClass;
function test(\ArrayObject $typehintexample = null) {}
$a = \DirectoryIterator::CURRENT_AS_FILEINFO;
// توسيع صنف داخلي أو عام
class MyException extends \Exception {}
?>
كيف أستخدم الأصناف أو الدوال أو الثوابت التابعة لمجال أسماء معين داخل ذلك المجال؟
المثال 29: الوصول إلى الأصناف أو الدوال أو الثوابت الداخلية في مجالات الأسماء
<?php
namespace foo;
class MyClass {}
// استخدام صنف من مجال الأسماء الحالي كإشارة إلى النوع
function test(MyClass $typehintexample = null) {}
// طريقة أخرى لاستخدام الصنف من مجال الأسماء الحالي كإشارة إلى النوع
function test(\foo\MyClass $typehintexample = null) {}
// توسيع الصنف من مجال الأسماء الحالي
class Extended extends MyClass {}
// الوصول إلى دالة عامة
$a = \globalfunc();
// الوصول إلى ثابت عام
$b = \INI_ALL;
?>
كيف سيُحلّل اسم مثل \my\name
أو \name
؟
تحلّل الأسماء التي تبدأ بالرمز \
دائمًا إلى الهيئة ذاتها، لذا فإنّ الاسم \my\name
سيحلّل إلى my\name
والاسم \Exception
سيحلّل إلى Exception
.
المثال 30: الأسماء المؤهّلة بالكامل
<?php
namespace foo;
$a = new \my\name(); // instantiates "my\name" class
echo \strlen('hi'); // calls function "strlen"
$a = \INI_ALL; // $a is set to the value of constant "INI_ALL"
?>
كيف سيحلّل اسم مثل my\name
؟
تحلّل الأسماء التي تحتوي على الرمز \
ولكنّها لا تبدأ به بطريقتين مختلفتين:
إن كانت هناك عبارة import
تضع اسمًا بديلًا لـ my
فإنّ الاسم البديل سيطبّق أيضًا على my
في my\name
.
في حال عدم وجود اسم بديل، يصبح اسم مجال الأسماء الحالي هو my\name
.
المثال 31: الأسماء المؤهّلة
<?php
namespace foo;
use blah\blah as foo;
$a = new my\name(); // instantiates "foo\my\name" class
foo\bar::name(); // calls static method "name" in class "blah\blah\bar"
my\bar(); // calls function "foo\my\bar"
$a = my\BAR; // sets $a to the value of constant "foo\my\BAR"
?>
كيف سيحلّل اسم صنف غير مؤهّل مثل name
؟
يمكن للأسماء التي لا تحتوي على الرمز \
مثل name
أن تحلّل بطريقتين مختلفتين:
في حال وجود عبارة import
تضع اسمًا بديلًا للاسم name
فيستخدم الاسم البديل، وإلا فإنّ اسم مجال الأسماء الحالي يصبح name
.
المثال 23: أسماء الأصناف غير المؤهّلة
<?php
namespace foo;
use blah\blah as foo;
$a = new name(); // instantiates "foo\name" class
foo::name(); // calls static method "name" in class "blah\blah"
?>
كيف سيحلّل اسم دالة أو ثابت غير مؤهّل مثل name
؟
تحلّل أسماء الدوال والثوابت التي لا تحتوي على الرمز \
بطريقتين مختلفتين:
الأولى: يصبح اسم مجال الأسماء الحالي name
.
الثانية: إن كان اسم الثابت أو الدالة غير موجود في مجال الأسماء الحالي، تلجأ اللغة إلى استخدام اسم عام للدالة أو الثابت في حال توفره.
المثال 33: أسماء دوال وثوابت غير مؤهّلة
<?php
namespace foo;
use blah\blah as foo;
const FOO = 1;
function my() {}
function foo() {}
function sort(&$a)
{
\sort($a); // calls the global function "sort"
$a = array_flip($a);
return $a;
}
my(); // calls "foo\my"
$a = strlen('hi'); // calls global function "strlen" because "foo\strlen" does not exist
$arr = array(1,3,2);
$b = sort($arr); // calls function "foo\sort"
$c = foo(); // calls function "foo\foo" - import is not applied
$a = FOO; // sets $a to value of constant "foo\FOO" - import is not applied
$b = INI_ALL; // sets $b to value of global constant "INI_ALL"
?>
لا يمكن للأسماء المستوردة أن تتضارب مع الأصناف المعرّفة في نفس الملف
لا توجد أي مشكلة في الشيفرة التالية:
file1.php
<?php
namespace my\stuff;
class MyClass {}
?>
another.php
<?php
namespace another;
class thing {}
?>
file2.php
<?php
namespace my\stuff;
include 'file1.php';
include 'another.php';
use another\thing as MyClass;
$a = new MyClass; // instantiates class "thing" from namespace another
?>
لا يوجد تضارب في الأسماء مع أنّ الصنف MyClass
موجود ضمن مجال الأسماء my\stuff
؛ وذلك لأنّ الصنف MyClass
معرّف في ملف منفصل. ولكن المثال التالي سيتسبّب في حدوث خطأ من نوع fatal ناجم عن تضارب في الأسماء؛ وذلك لأنّ الصنف MyClass
قد عُرِّف في الملف نفسه مع عبارة use
.
<?php
namespace my\stuff;
use another\thing as MyClass;
class MyClass {} // fatal error: MyClass conflicts with import statement
$a = new MyClass;
?>
لا يسمح بتداخل مجالات الأسماء
لا تسمح PHP بتداخل مجالات الأسماء:
<?php
namespace my\stuff {
namespace nested {
class foo {}
}
}
?>
ولكن يمكن محاكاة عملية تداخل مجالات الأسماء بسهولة:
<?php
namespace my\stuff\nested {
class foo {}
}
?>
قبل الإصدار 5.6 من PHP لا يمكن استيراد الدوال أو الثوابت باستخدام العبارة use
قبل الإصدار 5.6 من اللغة كانت مجالات الأسماء وأسماء الأصناف هي العناصر الوحيدة التي تتأثر بعبارة use
. ولغرض تقصير اسم ثابت أو دالة طويل يجب استيراد مجال الأسماء الذي يحتويها.
<?php
namespace mine;
use ultra\long\ns\name;
$a = name\CONSTANT;
name\func();
?>
أصبح في الإمكان تعيين أسماء بديلة أو استيراد أسماء الدوال والثوابت في الإصدار 5.6 وما بعده من PHP.
يجب أن تهربّ الأسماء الديناميكية لمجالات الأسماء (المعرّفات المحاطة بعلامة اقتباس) رمز الخطّ المائل \
من الضروي جدًّا إدراك أنّه بسبب استخدام الرمز \
كحرف للتهريب ضمن السلاسل النصية، فإنّه يجب استخدام هذا الرمز مرتين داخل السلاسل النصية لتجنّب حدوث مشاكل غير متوقعة:
المثال 34: مخاطر استخدام أسماء غير منتمية لمجال أسماء داخل سلسلة نصّية محاطة بعلامة اقتباس مزدوجة
لاحظ أنّ الرمز \n
يعني سطرًا جديدًا داخل السلاسل النصية المحاطة بعلامة اقتباس مزدوجة.
<?php
$a = "dangerous\name";
$obj = new $a;
$a = 'not\at\all\dangerous';
// لا مشكلة هنا على الإطلاق
$obj = new $a;
?>
أما السلال النصّية المحاطة بعلامة اقتباس مفردة فلا مشكلة في استخدام الرمز \
فيها، ومع ذلك ينصح بعدم استخدام هذا الرمز في جميع أنواع السلاسل النصية.
تؤدي الإشارة إلى الثوابت غير المعرّفة باستخدام رمز الخطّ المائل \
إلى حدوث خطأ من نوع fatal
ستطلق اللغة أي ثابت غير معرّف وغير مؤهّل مثل FOO
ملاحظة تخبرك بأنّ اللغة قد افترضت أن FOO
هي قيمة الثابت. في حال لم تعثر اللغة على أي ثابت مؤهّل أو مؤهّل بالكامل ويتضمن الرمز \، فإنّها ستطلق خطأً من نوع fatal.
المثال 35: ثوابت غير معرّفة
<?php
namespace bar;
$a = FOO; // produces notice - undefined constants "FOO" assumed "FOO";
$a = \FOO; // fatal error, undefined namespace constant FOO
$a = Bar\FOO; // fatal error, undefined namespace constant bar\Bar\FOO
$a = \Bar\FOO; // fatal error, undefined namespace constant Bar\FOO
?>
لا يمكن تجاوز (إعادة تعريف) الثوابت الخاصة NULL
و TRUE
و FALSE
و ZEND_THREAD_SAFE
و ZEND_DEBUG_BUILD
ستؤدي أي محاولة لتعريف ثابت خاص باللغة ينتمي إلى مجال أسماء معين إلى حدوث خطأ من نوع fatal.
المثال 36: ثوابت غير معرّفة
<?php
namespace bar;
const NULL = 0; // fatal error;
const true = 'stupid'; // fatal error;
// إلخ...
?>