文章目錄
- 環境
- Java的package
- package關鍵字
- 包結構和目錄結構
- 訪問權限
- import關鍵字
- 總結
- PHP的namespace
- namespace關鍵字
- 在同一個文件里使用資源
- 限定,完全限定,非限定
- 限定
- 完全限定
- 非限定
- use關鍵字
- use VS 直接指定資源
- 在不同的文件里使用
- 總結
環境
- Windows 11 專業版
- PHP 8.2.12
Java的package
在學習PHP的namespace之前,先來復習一下Java的package。
package關鍵字
Java使用 package
關鍵字來聲明包,支持多級結構,各級之間以 .
分隔。
一般全部使用小寫字母,使用倒序,比如: com.mycompany.myproject.mypackage
。
例如:
MyClass1.java
:
package mypkg1.mysubpkg1; // 聲明packagepublic class MyClass1() {
......
}
MyClass2.java
:
package mypkg2.mysubpkg1; // 聲明packageimport mypkg1.mysubpkg1.MyClass1; // 引入MyClass1public class MyClass2() {public static void main(String[] args) {var obj = new MyClass1();......}
......
}
包結構和目錄結構
在Java里,包結構和實際文件的目錄結構必須保持一致,如果不一致則編譯報錯。
比如包名是 com.mycompany.myproject.mypackage
,則實際目錄結構必須是 com/mycompany/myproject/mypackage
。其中 com
目錄是在Java源代碼的根目錄下。
此外,如果Java文件包含了public類(一個Java文件里最多只能有一個public類),則文件名必須與該類的命名一致,參見上面的例子。
訪問權限
Java的包會影響訪問權限。
我們知道,Java的訪問修飾符如下:
public
:在任何地方都可見protected
:只在同一個包,以及子類中可見- 缺省(包訪問權限):只在同一個包中可見
private
:只在本類內部可見
注意:一個Java文件里可以定義多個類,它們也是在同一個包里的(但一個Java文件里最多只能有一個public類)。
訪問修飾符 | 同一個類 | 同一個包 | 不同包的子類 | 不同包的非子類 |
---|---|---|---|---|
public | Y | Y | Y | Y |
protected | Y | Y | Y | N |
缺省 | Y | Y | N | N |
private | Y | N | N | N |
import關鍵字
Java通過 import
關鍵字來引入包資源。由于包結構和實際文件目錄結構一致,所以 import
既指定了包結構,也指定了目錄結構(這和PHP是不同的)。
在import語句中,可以指定一個資源,也可以使用通配符 *
,比如:
import java.util.List
impport java.util.*
使用 import
來引入資源后,接下來就可以直接使用資源,而不需要指定資源的全限定名了,比如:
import java.util.ArrayList;
......ArrayList<String> list = new ArrayList<>();
注意:如果不通過 import
來引入資源,也可以使用資源,只不過每個用到資源的地方,都需要指定全限定名,比如:
java.util.ArrayList<String> list = new java.util.ArrayList<>();
總結
- 使用
package
關鍵字來聲明包,各級之間以.
分隔 - 包結構和實際文件目錄結構必須一致
- 包可以影響訪問權限
- 通過
import
關鍵字來引入包資源,簡化使用
PHP的namespace
namespace關鍵字
PHP通過 namespace
關鍵字來定義命名空間,對于多級命名空間,不同層級之間用 \
分隔,比如:
namespace MyProject\Controllers;class MyClass1 {......
}
注:遵循 PSR-4 標準,使用首字母大寫(PascalCase)。
注意:namespace
后面不用加引號,但是 require
和 include
后面需要加引號,比如:
namespace MyProject\Controllers;require 'test0602_1.php';
......
實際上,PHP的namespace有兩種寫法,上面的寫法叫做非括號語法,還有一種寫法叫做括號語法,如下:
namespace MyProject1 {......
}
這兩種寫法,在同一個文件中不能混用。
推薦還是使用非括號語法,而且一個文件只用一個namespace。
括號語法的一個不同之處在于,可以顯式聲明一個全局命名空間,比如:
namespace {......
}
不加命名空間名字,就是全局命名空間。
在同一個文件里使用資源
首先,在同一個文件里,可以有多個namespace(這一點和Java不一樣),比如:
namespace MyProject1\Namespace1;......namespace MyProject2\Namespace2;......
或者:
namespace MyProject1\Namespace1 {......
}namespace MyProject2\Namespace2 {......
}
限定,完全限定,非限定
在使用另一個命名空間的資源時,可用下面三種方式:
- 限定:有點類似于“相對路徑”,但貌似只能向下,不能向上(即找其父命名空間)
- 完全限定:有點類似于“絕對路徑”,安全可靠
- 非限定:不指定namespace信息(使用當前命名空間的資源,或者全局資源,或者資源的別名)
限定
namespace MyProject1\Namespace1;
const PI = 3.14;namespace MyProject1;
echo Namespace1\PI;
本例中,在 MyProject1
下,要使用 MyProject1\Namespace1
下的資源,可以直接從當前命名空間開始計算,因此只需指定 Namespace1
即可(開頭不加 \
)。
完全限定
namespace MyProject1\Namespace1;
const PI = 3.14;namespace MyProject2\Namespace2;
echo \MyProject1\Namespace1\PI;
不管在哪里,要使用 MyProject1\Namespace1
下的資源,都可以從根命名空間開始計算,也就是以 \
開頭,指定全路徑 \MyProject1\Namespace1
。
非限定
namespace {const E = 2.72;
}namespace MyProject1 {echo E;// echo \E;
}
本例中,因為要使用的是全局命名空間的資源,所以無需指定namespace。
當然,如果前面加上 \
,顯式指定全局資源,也是OK的。
事實上,如果使用全局資源,加上 \
會更安全一些,這是因為如果不加 \
,會先查找當前命名空間,然后才是全局命名空間。
namespace MyProject1\Namespace1;
const M_PI = 3.14;
echo M_PI . PHP_EOL;
echo \M_PI . PHP_EOL;
輸出結果如下:
3.14
3.1415926535898
可見 M_PI
和 \M_PI
是不同的,前者是當前命名空間的常量,后者是全局常量。
如果注釋掉第二行代碼,則 M_PI
和 \M_PI
一樣,都是指向全局常量。
use關鍵字
使用其它命名空間的資源時,每次都要指定命名空間結構,太麻煩了。為了方便,可使用 use
關鍵字來簡化操作。
use
關鍵字有以下幾種使用方法:
- 指定命名空間
- 指定資源
- 指定命名空間,并給命名空間起個別名
- 指定資源,并給資源起個別名
namespace MyProject1\Namespace1;
const PI = 3.14;namespace MyProject2\Namespace2;
use \MyProject1\Namespace1; // 指定命名空間
echo Namespace1\PI . PHP_EOL;namespace MyProject3\Namespace3;
use const \MyProject1\Namespace1\PI; // 指定資源
echo PI . PHP_EOL;namespace MyProject4\Namespace4;
use \MyProject1\Namespace1 as MyNamespace; // 指定命名空間,并給命名空間起個別名
echo MyNamespace\PI . PHP_EOL;namespace MyProject5\Namespace5;
use const \MyProject1\Namespace1\PI as MyPI; // 指定資源,并給資源起個別名
echo MyPI . PHP_EOL;
注意和Java的區別:Java的 import
指定的是資源(具體來說是類),比如 import java.util.*
或者 import java.util.ArrayList
。而PHP的 use
既可以指定命名空間,也可以指定資源。
PHP在use命名空間時,如果沒有起別名,則接下來使用命名空間的最后一部分(如上例中的 Namespace1
)來簡化命名空間全稱,如果有別名,則使用別名來簡化命名空間全稱。
同理,PHP在use資源時,如果沒有起別名,則接下來使用資源名(如上例中的 PI
)來簡化其全限定名,如果有別名,則使用別名來簡化其全限定名。
此外要注意,PHP在use資源時,如果是常量,則需顯式指定 const
(見上例)。類似的,如果是use一個方法,則需顯式指定 function
。
起別名的一個重要意義在于,如果引入多個相同非限定名的命名空間或者是引入同名資源,則需要通過別名來避免沖突。比如:
namespace MyProject1\Controller;
const E = 2.71;namespace MyProject2\Controller;
const E = 2.71828;namespace MyProject1\Namespace1;
const PI = 3.14;namespace MyProject2\Namespace2;
const PI = 3.14159;namespace MyProject3\Namespace3;
use \MyProject1\Controller as Controller1; // Controller有歧義,需用別名避免沖突
echo Controller1\E . PHP_EOL;use \MyProject2\Controller as Controller2; // Controller有歧義,需用別名避免沖突
echo Controller2\E . PHP_EOL;use const \MyProject1\Namespace1\PI as PI1; // PI有歧義,需用別名避免沖突
echo PI1 . PHP_EOL;use const \MyProject2\Namespace2\PI as PI2; // PI有歧義,需用別名避免沖突
echo PI2 . PHP_EOL;
use VS 直接指定資源
前面提到,直接指定資源限定名時:
- 以
\
開頭:完全限定,從根命名空間開始計算 - 不以
\
開頭,非完全限定,從當前命名空間開始計算
在使用 use
關鍵字指定命名空間或資源時,無論是否以 \
開頭,都是完全限定的。也就是說,一定是從根命名空間開始計算的。
namespace MyProject1\Namespace1;
const PI = 3.14;namespace MyProject1;
echo Namespace1\PI . PHP_EOL; // 直接指定,不以 \ 開頭,非完全限定,從當前命名空間開始計算echo \MyProject1\Namespace1\PI . PHP_EOL; // 直接指定,以 \ 開頭,完全限定,從根命名空間開始計算use const MyProject1\Namespace1\PI as MyPI1; // 使用use, 不以 \ 開頭,完全限定,從根命名空間開始計算
echo MyPI1 . PHP_EOL;use const \MyProject1\Namespace1\PI as MyPI2; // 使用use, 以 \ 開頭,完全限定,從根命名空間開始計算
echo MyPI2 . PHP_EOL;
注:這種行為可能與PHP版本有關,我使用的PHP 8,也許舊版本不是這樣的,我沒有深究。
在不同的文件里使用
資源和使用者如果在不同的文件里,則使用者需要先引入資源所在的文件。在PHP里,是使用 include
或者 require
關鍵字來引入文件,具體參見我另一篇文檔( https://blog.csdn.net/duke_ding2/article/details/147690887
)。
但是,由于PHP的命名空間和實際目錄結構是相互獨立的,因此,引入文件后,仍需通過命名空間來指定資源。
test0602_1.php
:
namespace MyProject1\Namespace1;const PI = 3.14;
test0602_2.php
:
namespace MyProject2\Namespace2;require 'test0602_1.php';echo \MyProject1\Namespace1\PI;
同樣,也可使用 use
關鍵字來簡化操作。
把 test0602_2.php
改寫如下:
namespace MyProject2\Namespace2;require 'test0602_1.php';use const \MyProject1\Namespace1\PI;echo PI;
注意和Java對比:
- Java只需
import
(既指定目錄結構也指定包結構),PHP需要require
和use
(前者指定目錄結構,后者指定命名空間結構) - Java不用
import
也行,只需指定資源全稱。PHP可以不用use
,只需指定資源或命名空間全稱,但是require
是避免不了的(除非通過自動加載機制隱式加載),因為文件路徑和資源全稱是相互獨立的
總結
- 使用
namespace
關鍵字來聲明命名空間,各級之間以\
分隔 - 有“括號語法”和“非括號語法”兩種寫法,一般使用非括號語法,且一個文件只用一個namespace
- 使用者可以通過“限定”、“完全限定”、“非限定”的方式來指定使用的命名空間
- 命名空間結構和實際文件目錄結構可以不一致,但推薦保持一致
- 通過
use
關鍵字來引入命名空間或者資源,簡化使用 - 使用
use
指定的命名空間或資源,不管是否以\
開頭,實際都是從根命名空間開始計算的(至少PHP8是這樣)