您尚未登录,请登录后浏览更多内容! 登录 | 立即注册

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 15992|回复: 0
打印 上一主题 下一主题

[php学习资料] PHP命令空间namespace及use的用法实践总结

[复制链接]
跳转到指定楼层
楼主
发表于 2020-7-1 23:37:46 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
以下皆为本人自我理解内容,如有失误之处,请多多包涵。

' R6 [, N" _4 ]. o! _
文章大纲:
使用namespace的目的
namespace的使用方法
使用use的目的
use的使用方法

3 T! W- i- W- s) ~& y4 P; d# r) R8 v' k  g
使用namespace的目的:
团队合作项目时,避免与团队其它成员新建的类发生冲突;个人负责项目时,避免前后新建的类发生冲突;

" [5 i3 K9 @5 v3 I  e$ A7 }# K4 b/ S
据个人理解,用到所需要的类时,需要先require或include引入,所以会发生类重定义的错误的前提是:两个相同命名的类都有被引入。目前有些php框架会自动加载(即include)所有新建的model类,所以为了避免你新建的model类和项目框架原生的核心类发生重名冲突,采用了namespace。(想了想,与团队成员新建的类产生冲突应该通过沟通避免,即使事发后也应该重新调整类名即时维护,避免后期造成因为对类的理解混淆而带来维护上的复杂度提高)
, L; f5 C+ q3 r( D: L* p$ G
结合使用方法来进一步理解它的使用目的吧。

8 R2 }3 z- d5 r# ?# q
: w+ s# l9 d# i3 Y3 Znamespace的使用方法:
为了进行测试,我将创建3个文件:1.php和name.php(此文件用来执行测试),后面将不再说明,请自行注意代码的变化。
1.namespace后命名的定义不区分大小写
  1. namespace one;
    7 \8 Q7 O  n" r0 n
  2. namespace One;
    ) B8 F5 f; @% Y6 |
  3. namespace ONE;
复制代码
$ ]  z8 d( t# d
如上写法都可以,选择一种作为自己的规范即可。(后面代码我采用第一种进行测试哈)
! C' W1 \  w3 c1 P
2. 没有定义命名空间,就理解为使用顶级命名空间。new类时,可以在类前加上反斜杠\,也可以不加。
  1. //1.php   
    . b. y' P( y$ ~
  2. class Person{
    , X: S$ ^7 `8 y
  3.     function __construct(){
    : c% M9 u$ f1 x* J$ F& V- j" v
  4.             echo 'I am one!';4 i. C* u4 R* e
  5.         }7 s! J& p; _: A# e; [
  6. }
复制代码
  1. //name.php
    7 \# C+ [6 @7 U: i0 }% |
  2. require_once './1.php';% Z8 ~- K' A" a* m+ v4 T

  3. 4 M  t7 ^) r2 L' S& x2 a0 }9 Q; k; s
  4. new Person();     //输出 I am one!;
    4 i* S7 g" A1 y
  5. new \Person(); //输出 I am one!;
复制代码

% c+ }$ u- T/ I6 \2 W3 Z0 A3. new类时,带上命名空间时,之间一定用反斜杠字符,而不是顺斜杠。
记忆方法:按找%中斜杠的顺序理解为顺斜杠。(有时说反斜杠,自己都不知道是哪种方向,以前按自左向右上升方向这种方向记忆,现在感觉这个太不靠谱了)
  1. //name.php
    / h9 M7 ]2 D% n! T* d* H
  2. require_once './1.php';
    ( w! Y* g0 R* r. Z# l" \
  3. new /Person();  // 代码报错:Parse error: syntax error, unexpected '/'
复制代码
2 P+ _% r9 k  P8 q0 V
4.类在指定命名空间下, new类时,一定要带上指定的命名空间。
没有带上指定的命名空间,按照第2点,php就会从顶级命名空间里找这个类。切记:这里不能按照顶级命名空间包含一切其它的命名空间来理解。而应该将顶级命名空间完完全全与其他命名空间区分开。
  1. //1.php   
    5 b# b2 g% Q4 K) K# ]
  2. namespace one;4 c  W. b1 u* U6 E& f. e& v
  3. class Person{
    ( I, e8 Y8 [1 R& Y+ }/ ?# d" I
  4.     function __construct(){
    8 {6 W4 a9 S5 u# |1 E# B; k$ S, G+ R
  5.             echo 'I am one!';
    ! t1 \; \5 M5 m! D6 F5 J
  6.         }8 H5 D# h+ H) K" l8 L" ^/ S
  7. }
复制代码
  1. //name.php
      P$ N1 U- }9 I; z2 F' g0 c) {
  2. require_once './1.php';
    + X- M9 ~. l0 Q) ^4 U
  3. new \one\Person(); //输出 I am one!;
    4 ~: i8 g& P9 f/ W, ^- H2 b: N
  4. new \Person(); //代码报错:Fatal error: Class 'Person' not found
复制代码

* \4 `1 R* M: e7 S: y
可以举个这个通俗例子来理解:带上指定命名空间代表某人的苹果(在他手里),顶级命名空间代表苹果箱里的苹果(在箱子里)。现在要找某人的苹果,就将某人的命名空间带上,否则就会从箱子里找某人的苹果,结果当然是找不到。
! C9 i& y: z, y$ c/ N! S) a
5.命名空间声明后的代码便属于这个命名空间,即使有include或require也不影响(重点是对后半句的理解,具体看代码)。( o5 f: }% F2 p3 w3 ~6 x- R) c: Q
  1. //1.php   5 \( H" s* A# ~3 k* G
  2. namespace one;% p- j6 s$ Q. o. |3 [1 {( M! o
  3. class Person{9 v% M; P. X4 x
  4.     function __construct(){/ ^; h/ A8 T3 ?/ e- S. S6 N
  5.             echo 'I am one!';) `" U6 ^4 Z2 x
  6.         }; w0 T' A! [$ ~7 _1 J  N- q
  7. }
复制代码
  1. //name.php
    8 q' W: D2 v; i5 D, @
  2. namespace test;$ t- f4 q' A( n1 e5 D% ^' V7 ~0 G0 \1 @
  3. require './1.php';
    6 s! y1 U0 ^3 v) `3 d+ f) |
  4. new \one\Person(); //输出 I am one!;
    % t: e1 ?3 i$ r) g' \1 o* p/ z
  5. new Person();      //这里结果会是什么呢,猜猜看
      X; _  J7 V( c) ?; ]% n' g# Y% y
  6. 最后一行结果报错:+ d. `0 ?+ z9 L+ ], v/ `
  7. Fatal error:  Class 'test\Person' not found
复制代码

: i* A" R0 u0 ?' D2 d9 z
" P# v8 |) n% ~$ ^. w) a
首先,这里与第2点比较一下:
第2点,我说,没有命名空间时,new类时,有没有反斜杠意义一样。
在这里,有了命名空间,有和没有反斜杠的意义就不一样了。
最后一行换成
  1. new \Person();
复制代码
- k" z# C  @; Q5 v; A$ Q
结果报错:
  1. Fatal error:  Class 'Person' not found
复制代码

7 l/ i: V. K! Y; E7 e3 w+ Y2 f) m3 d
接着,就说说当前这点。
我们可以发现,最后一行代码对应的命名空间为test,并没有受到require文件里的命名空间的影响。
进一步加强验证,我修改了name.php文件如下:
  1. //name.php6 z2 K& M8 F& u8 I4 @- z
  2. namespace test;" F! t3 c/ Z' t
  3. require './1.php';
    3 e; F& ~+ ?6 Q( ^0 D: ^
  4. 6 p4 N; b) S" P
  5. class Person{
    ; Z* Y  \5 {2 D: m* B" u
  6.     function __construct(){2 E/ K, c. y4 X9 S/ J
  7.             echo 'I am test!';* v) i4 C0 ~* X" y4 _9 d
  8.         }
    % _! t' `) L7 `9 Y* [3 `4 _
  9. }( X! Y5 H* ]8 Y6 S6 c
  10. * {5 C6 c( d+ D; }
  11. new \one\Person(); //输出 I am one!;
    % W  t2 ?# D; K$ a9 @
  12. new Person();    //这里结果会是什么,自己猜猜看
复制代码
4 _) K4 x% R3 I7 }1 `/ P5 O& I
最后,这个例子刷新了我对require的认识了。
按照我以前对require的理解:PHP 程序在执行前,就会先读入 require 所指定引入的文件,使它变成 PHP 程序网页的一部分。所以我常常就简单的理解为替换,只不过把抽离出来的代码再放回原处而已。然后我试了将1.php文件内容放到name.php里:
  1. //name.php! |5 O. E% k0 C; h+ M& a1 M
  2. namespace test;
    6 U5 G( H! q, O% Z/ _4 T3 z% s
  3. namespace one;/ T- y9 S, p9 V7 o# ^  t% y. `
  4. class Person{
    # V3 D! L8 W! r; I
  5.     function __construct(){( Y6 ?* Y4 d. U2 V' l6 i  b
  6.             echo 'I am one!';4 f; u' e$ @3 o- b! f) t8 P
  7.         }# L) T: M  ?6 y! h
  8. }
    : G' Z0 u+ i5 |3 e8 k
  9. 1 v; {6 n. |3 |; c5 d
  10. class Person{
    $ u3 E' n. w+ o. g; k
  11.     function __construct(){
    , a) t9 J% U4 c% p9 ?
  12.             echo 'I am test!';
    # g4 j; q% G: N- `2 n. ~
  13.         }
    6 l8 r7 h4 A: Y1 I/ K- }1 D
  14. }
复制代码

, P; p! N" C: m$ L* v0 f
无需new类,该文件就会报错:
  1. Fatal error:  Cannot redeclare class one\Person
复制代码

9 K# h+ H4 t( [  _
看来简单的把require理解为替换,在这里行不通。

" w- i1 |' U0 @7 m" _6.namespace里不包含类名称,即使存在与类名称同名的部分,那也不代表类。new类时,还是得将这部分带上。
0 K5 `" @: O, r9 n( d( [; C
  1. //name.php
    7 k1 D% F0 c, p! y3 C: I  i' p+ A

  2. & Z' D4 D" h2 @% V
  3. namespace test\person;
    0 f7 n0 _9 m. U9 w8 ]8 ^( o

  4. . Q3 g) o3 O) o: N9 i
  5. class Person{/ w! s8 K9 N' @- I; q' K* \4 ^% U* S/ N" n
  6.     function __construct(){& b6 r9 f  d. s' C( T' i  b
  7.             echo 'I am test!';
    4 X' ~3 X/ h1 F: e) [. g
  8.         }
    . w& P& p# Q! W: i, @
  9. }4 t) c. Y/ |% [( C8 [
  10. new \test\person\Person();  //命名空间里person无法代表类名
复制代码

: t1 n8 B" }+ ?: S' U
不过这样纯粹是画蛇添足,直接干脆点,namespace里不要带类名称就好。
) W, z- X; |, B
7.一个php文件中可以存在多个命名空间,第一个命名空间前不能有任何代码。
只说第一个命名空间前不能有任何代码,之后的命名空间之前可以有代码。这个自行测试即可。
  1. //name.php
    + p' |- U3 u/ |) R  T: m+ {

  2. . D9 ]2 C& C6 ?9 p, @
  3. namespace test;
    7 Z7 M+ [1 w0 L. }" V
  4. echo 'zhai14';: m/ l! }0 x; r, U' F
  5. namespace zhai;. B) G& Z- C: |0 T8 q& r
  6. require './1.php';
复制代码

- A/ J- f4 I+ j1 r
php命名空间namespace告一段落了,接下来说说use的用途。
使用use的目的:
在命名空间字符串过长时,使用use可以相应的缩短命名空间。

( x9 A1 \* t. o1 p2 y) @2 b0 ?use的使用方法:1.new类时,最前面无需用反斜杠。此外,use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。' c) s7 w" _% d+ P, e
  1. //name.php" M. d* m7 j. K( R" a8 @4 Q; d
  2. , q4 _3 Z2 n3 w/ k' [4 t
  3. namespace animal\dog;
    1 |9 Q/ S( ~# Y# \; b* o9 b3 @
  4. & Q5 \2 f# K0 r+ o  A" K5 T& V/ Q
  5. class Life{
    . Y- Z3 P* ]! t' |) S! ~5 p+ \
  6.     function __construct(){
    . u  d2 Z; m. L: u
  7.             echo 'dog life!';
    3 w, d% n( X8 W8 }1 h
  8.         }- x) z) w# G* n; j
  9. }
    2 P" z9 I. b3 ?4 @, a

  10. : g% H) j  R( w1 j! J: {
  11. namespace animal\cat;
    $ `" b8 E) ~5 B2 Q* s
  12. 8 ~3 j8 R6 [$ c( T
  13. class Life{
    ( F) e8 e+ E9 y1 _3 ^+ e/ b! |- ]
  14.     function __construct(){4 ]# F  r/ e# j0 Z/ m5 v% O5 ?/ g
  15.             echo 'cat life!';0 ~4 b+ a4 `8 ?) ?! F0 ~8 ?
  16.         }7 C0 \* T" R. u
  17. }
    - F- B% N2 j4 D4 U

  18. 3 z$ Z- W( |& g, g4 ~. [
  19. new Life();  //按照代码执行顺序,这里默认animal\cat这个命名空间7 E. b3 B- v8 J6 Y& s# A3 m2 m" s
  20. new \animal\dog\Life();  //A
    & s8 i* g5 {5 m1 t4 {
  21. 1 M. d5 x- o  T+ j2 Q5 Z! D) }. f
  22. use animal\dog;  //a
    1 {9 k3 s# ~5 f( O
  23. new dog\Life();  //B" F# s1 f9 i4 L& p4 l
  24. 7 x' G( j- N: e" }
  25. use animal\dog as d;  //b
    5 T) U4 Q' O; Z5 J2 J4 ~' ]0 d) K3 @
  26. new d\Life();
复制代码
3 G* ?; _( A6 @7 ]' e
通过A、B行代码比较,需要注意:
使用use后,new类时,最前面没有反斜杠。
没使用use时,命名空间最前面有反斜杠
, x5 W; \$ N. Q: Y
通过a、b行代码比较,可以理解:
use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。如上的:
  1. use animal\dog;
复制代码

2 W/ t7 l# }4 |" k# _
相当于
  1. use animal\dog as dog;
复制代码
" l7 Q  `" {5 Q9 k% E; g
2.namespace后面不建议加类名,但use后可以。
! z1 }9 S5 o& k1 Z3 `6 m
  1. //name.php" D9 h, \  U) u8 t

  2. 3 h) L, e1 F5 @/ }) n, ]
  3. namespace animal\dog;
    % T: X) e0 i& |8 m
  4. 8 {6 x1 Y+ R7 M; q, e6 V! W% u
  5. class Life{, l8 X) W7 G/ u4 ~# F3 ?0 w' J
  6.     function __construct(){
    * P8 [1 n. F5 V4 S! A8 z; z
  7.             echo 'dog life!';/ y8 B  W, l' r$ v/ P7 d2 B/ N
  8.         }9 F' O: l$ m" P) O5 Q7 N, `+ l
  9. }
    ' v/ F: A3 l5 u% R

  10. 8 A5 P/ D  v' s, p
  11. namespace animal\cat;: O7 ~1 C' Y6 v; W) |6 m6 N

  12. $ ]% r& q! `6 P; _( Y
  13. class Life{3 J) K+ p1 ?" B* i6 V7 b
  14.     function __construct(){
    7 t2 L9 m) X$ B: G* c/ }
  15.             echo 'cat life!';) r' K0 o* k. w
  16.         }  a5 W. w( \* T8 g% X
  17. }
    * l6 E, W) W8 H0 o0 N& ]* I
  18. # e! M7 \) ~3 T3 H( @# O& u
  19. use animal\dog\Life as dog;  
    $ O- C3 J. N" e! z
  20. new dog();
复制代码

4 w1 n$ J! {- h8 `& j/ c
如上所示,use后加上类名后,就相当于把类改了个名称:由Life改为dog了。
上面不用as dog就会报错:
  1. Fatal error:  Cannot use animal\dog\Life as Life because the name is already in use
复制代码

5 K; D! O/ H8 t3 A
因为cat下也有个一样名称的Life类。
可以理解为,使用use后,这个昵称对应的类只能归当前命名空间占有,其它命名空间下不允许存在该类。
  1. //name.php
    ! ?  R. c7 p/ o6 u2 |' L

  2. 2 X, O( L- j! m/ U1 N
  3. namespace animal\dog;
    2 d) b! \+ F1 Y9 u' d$ e3 l
  4. 7 ^$ `: z3 x: s% N2 A7 x
  5. class Life{
    7 W8 A# b8 i! t5 T
  6.     function __construct(){
    % H4 ]" v# q0 l3 X7 A2 ]
  7.             echo 'dog life!';, i( P' f6 T0 H- W. t! ~
  8.         }% Y& X- n( U$ a# d' h0 @3 u6 i
  9. }
    5 [# l1 v, i+ R: q+ i- i3 l
  10. class Dog{: m1 e# U3 o( T2 c7 `8 q7 d" ^- r. T
  11.     function __construct(){
    # g7 y, b' E; v( j
  12.             echo 'dog in dog!';* _) h" o# K. ?1 Q- ]$ X9 J0 \
  13.         }' ?+ R, Y) _3 z! c9 l3 }% z$ {3 c! s
  14. }7 H8 l: C; z) l) o0 `
  15. # ]$ H/ O' [) S
  16. namespace animal\cat;6 n) O7 T& J' T  L
  17. ; @% J$ c& _' J/ ^  G. u: K
  18. // class Dog{
    9 Q6 z: c8 m* v. P5 r
  19. //     function __construct(){
    9 f  A5 d3 e! i8 m7 n$ k& V
  20. //             echo 'dog in cat!';
    + s  y* I/ T2 o* X/ s; B2 F
  21. //         }
    / W: y. m6 X/ @- L. G2 P4 k' l& `
  22. // }, C2 v/ b) H' \
  23. class Life{* K6 @. i, P& }+ C5 M6 ]7 D& i4 q
  24.     function __construct(){
    $ Y& K, @1 B' @; x) [" H8 F
  25.             echo 'cat life!';
    % k! i* u9 A( y1 Y7 n
  26.         }6 d* S; i( x$ D! m3 f1 V
  27. }
    $ [5 a' |: Q8 r0 P! J+ o

  28. - T, T2 f6 B6 m
  29. use animal\dog;  . D+ @# m( I% M
  30. new dog\Dog();
复制代码

; F' ?/ U7 Y: t+ ?6 z
如上,使用了
  1. use animal\dog;
复制代码
# R9 l9 O0 ~5 A! \8 H$ C0 X8 W# D, o
cat
通过上面代码,我想使用use的目的效果(缩短命名空间名称)就很明显了。
4 S7 G" U6 h1 M
简单总结一下:
namespace就是划分领域的作用,代表这些东西是属于某个命名空间下的。
use就是起小名的作用,不论写起来还是说起来都可以省不少事儿。

" f! d+ S# y2 u
+ @4 O- ^; L" q
8 C/ t8 v6 }9 G8 e6 y: H( D9 c
" F2 s+ K: [, A) \, G/ y- M8 n
5 a5 K3 x/ ~' p3 B6 K
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-6-20 00:00 , Processed in 0.054471 second(s), 20 queries .

Copyright © 2001-2026 Powered by cncml! X3.2. Theme By cncml!