2024 年日本 PHP 研討會

使用命名空間:基本知識

(PHP 5 >= 5.3.0, PHP 7, PHP 8)

在討論命名空間的使用之前,重要的是要了解 PHP 如何知道您的程式碼正在請求哪個命名空間元素。可以將 PHP 命名空間和檔案系統做一個簡單的類比。有三種方法可以存取檔案系統中的檔案

  1. 相對檔名,例如 foo.txt。這會解析為 currentdirectory/foo.txt,其中 currentdirectory 是目前所在的目錄。因此,如果目前目錄是 /home/foo,則名稱會解析為 /home/foo/foo.txt
  2. 相對路徑名稱,例如 subdirectory/foo.txt。這會解析為 currentdirectory/subdirectory/foo.txt
  3. 絕對路徑名稱,例如 /main/foo.txt。這會解析為 /main/foo.txt
同樣的原則也適用於 PHP 中的命名空間元素。例如,類別名稱可以用三種方式來引用:
  1. 非限定名稱,或未加前綴的類別名稱,例如 $a = new foo();foo::staticmethod();。如果目前的命名空間是 currentnamespace,則會解析為 currentnamespace\foo。如果程式碼是全域的、非命名空間的程式碼,則會解析為 foo 一個需要注意的地方:如果命名空間中的函式或常數未定義,則函式和常數的非限定名稱將會解析為全域函式和常數。詳情請見 使用命名空間:退回至全域函式/常數
  2. 限定名稱,或加有前綴的類別名稱,例如 $a = new subnamespace\foo();subnamespace\foo::staticmethod();。如果目前的命名空間是 currentnamespace,則會解析為 currentnamespace\subnamespace\foo。如果程式碼是全域的、非命名空間的程式碼,則會解析為 subnamespace\foo
  3. 完全限定名稱,或加有全域前綴運算子的前綴名稱,例如 $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(); // 解析為函式 Foo\Bar\foo
foo::staticmethod(); // 解析為類別 Foo\Bar\foo,方法 staticmethod
echo FOO; // 解析為常數 Foo\Bar\FOO

/* 限定名稱 */
subnamespace\foo(); // 解析為函式 Foo\Bar\subnamespace\foo
subnamespace\foo::staticmethod(); // 解析為類別 Foo\Bar\subnamespace\foo,
// 方法 staticmethod
echo subnamespace\FOO; // 解析為常數 Foo\Bar\subnamespace\FOO

/* 完全限定名稱 */
\Foo\Bar\foo(); // 解析為函式 Foo\Bar\foo
\Foo\Bar\foo::staticmethod(); // 解析為類別 Foo\Bar\foo,方法 staticmethod
echo \Foo\Bar\FOO; // 解析為常數 Foo\Bar\FOO
?>

請注意,要存取任何全域類別、函式或常數,可以使用完全限定名稱,例如 \strlen()\Exception 或 \INI_ALL

範例 #1 從命名空間內部存取全域類別、函式和常數

<?php
namespace Foo;

function
strlen() {}
const
INI_ALL = 3;
class
Exception {}

$a = \strlen('hi'); // 呼叫全域函式 strlen
$b = \INI_ALL; // 存取全域常數 INI_ALL
$c = new \Exception('error'); // 初始化全域類別 Exception
?>

新增註解

使用者貢獻的註解 5 則註解

richard at richard-sumilang dot com
16 年前
在命名空間中繼承類別的語法仍然相同。

我們將這個檔案命名為 Object.php

<?php

namespace com\rsumilang\common;

class
Object{
// ... 程式碼 ...
}

?>

現在我們建立一個名為 String 的類別,它繼承自 String.php 中的 Object

<?php

class String extends com\rsumilang\common\Object{
// ... 程式碼 ...
}

?>

如果您的 String 類別與 Object 定義在相同的命名空間中,則不必指定完整的命名空間路徑

<?php

namespace com\rsumilang\common;

class
String extends Object
{
// ... 程式碼 ...
}

?>

最後,您也可以為命名空間名稱設定別名,以便在您的類別位於不同的命名空間中時,使用較短的名稱來繼承類別

<?php

namespace com\rsumilang\util;
use
com\rsumlang\common as Common;

class
String extends Common\Object
{
// ... 程式碼 ...
}

?>

- Richard Sumilang
匿名
10 年前
<?php

命名空間 Foo;

try {
// 這裡會發生可怕的事情
// 會拋出一個來自 SPL 的新例外
}
catch (
Exception as $ex) {
// 我們永遠不會到達這裡
// 因為我們捕捉的是 Foo\Exception
}
?>

請使用完整的命名空間名稱來捕捉例外

<?php

命名空間 Foo;

try {
// 這裡會發生可怕的事情
// 會拋出一個來自 SPL 的新例外
}
catch (
\Exception as $ex) {
// 現在我們終於可以到達這裡了
}
?>
Lukas Z
12 年前
命名空間內的變數不會覆蓋其他命名空間的變數,因為變數不受命名空間影響,而是全域的。
「雖然任何有效的 PHP 程式碼都可以包含在命名空間內,但只有四種類型的程式碼會受到命名空間的影響:類別、介面、函式和常數。」

來源:「定義命名空間」
https://php.dev.org.tw/manual/en/language.namespaces.definition.php
tom at tomwardrop dot com
12 年前
檔案系統的類比似乎只到此為止。缺少一個非常有用的功能,那就是在命名空間鏈中向上相對導航,例如:

<?php
命名空間 MyProject {
class
Person {}
}

命名空間
MyProject\People {
class
Adult extends ..\Person {}
}
?>

那樣會非常好,尤其是在命名空間非常深的情況下。它可以省去您為了參考上一層的資源而必須輸入完整的命名空間。
philip dot preisser at arcor dot de
13 年前
使用變數可能會覆蓋其他命名空間中相同的變數

<?php // php5 - package-version : 5.3.5-1ubuntu7.2

命名空間
main
{}

命名空間
main\sub1
{
$data = 1;
}

命名空間
main\sub2
{
echo
$data;// 1
$data = 2;
}

命名空間
main\sub1
{
echo
$data;// 2
$data = 1;
}

命名空間
{
echo
$data;// 1
}

?>
To Top