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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 6736|回复: 0

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

[复制链接]
发表于 2020-7-1 23:37:46 | 显示全部楼层 |阅读模式
以下皆为本人自我理解内容,如有失误之处,请多多包涵。

* u2 U- O+ k7 l1 \) N' W
文章大纲:
使用namespace的目的
namespace的使用方法
使用use的目的
use的使用方法
4 R/ w5 {6 d8 f4 R
7 G/ t6 ]( }) Z
使用namespace的目的:
团队合作项目时,避免与团队其它成员新建的类发生冲突;个人负责项目时,避免前后新建的类发生冲突;

$ h2 J5 N2 V+ q5 r) n
据个人理解,用到所需要的类时,需要先require或include引入,所以会发生类重定义的错误的前提是:两个相同命名的类都有被引入。目前有些php框架会自动加载(即include)所有新建的model类,所以为了避免你新建的model类和项目框架原生的核心类发生重名冲突,采用了namespace。(想了想,与团队成员新建的类产生冲突应该通过沟通避免,即使事发后也应该重新调整类名即时维护,避免后期造成因为对类的理解混淆而带来维护上的复杂度提高)
: Z- C$ Y+ U5 R  p! T5 b1 }
结合使用方法来进一步理解它的使用目的吧。

% Y. Z2 E: v2 ]( z% r8 R( b# q. v5 F/ C7 [9 L& R
namespace的使用方法:
为了进行测试,我将创建3个文件:1.php和name.php(此文件用来执行测试),后面将不再说明,请自行注意代码的变化。
1.namespace后命名的定义不区分大小写
  1. namespace one;
    4 }4 _  |3 R$ G0 Y" W* c6 W
  2. namespace One;
    / b- S- x, k& G5 v4 N& o
  3. namespace ONE;
复制代码

% l) u. |+ Y7 i1 `  N
如上写法都可以,选择一种作为自己的规范即可。(后面代码我采用第一种进行测试哈)
1 \  c! T1 ^* D* M
2. 没有定义命名空间,就理解为使用顶级命名空间。new类时,可以在类前加上反斜杠\,也可以不加。
  1. //1.php   
    % s* V1 g; d. E( A- n% D& i
  2. class Person{: g6 j5 u1 x1 b+ Y) q
  3.     function __construct(){+ G4 T" ]6 G/ G; h+ y8 K* d9 X
  4.             echo 'I am one!';
    # c# u3 z' i' q4 @- u
  5.         }7 [. K' Y$ {$ f' U& a
  6. }
复制代码
  1. //name.php
    . S5 ]( k( b$ ~) m& m6 w
  2. require_once './1.php';1 P  Z" q# t# P# Y% z2 `* E
  3. ; O# J/ x4 f% z# B# ~
  4. new Person();     //输出 I am one!;
    * M. B& e, E, Z6 t, p: g- p5 H  q( `3 ^
  5. new \Person(); //输出 I am one!;
复制代码
0 P* q9 C7 v, A% j" y% G
3. new类时,带上命名空间时,之间一定用反斜杠字符,而不是顺斜杠。
记忆方法:按找%中斜杠的顺序理解为顺斜杠。(有时说反斜杠,自己都不知道是哪种方向,以前按自左向右上升方向这种方向记忆,现在感觉这个太不靠谱了)
  1. //name.php
    + w3 d5 E# ?& `% v
  2. require_once './1.php';" y6 `. F3 u3 L# j+ ?/ A
  3. new /Person();  // 代码报错:Parse error: syntax error, unexpected '/'
复制代码
8 w2 I, ]$ g* H* r) X1 O; t
4.类在指定命名空间下, new类时,一定要带上指定的命名空间。
没有带上指定的命名空间,按照第2点,php就会从顶级命名空间里找这个类。切记:这里不能按照顶级命名空间包含一切其它的命名空间来理解。而应该将顶级命名空间完完全全与其他命名空间区分开。
  1. //1.php   ' x$ W7 B8 V4 [2 p, l
  2. namespace one;/ R& j+ U7 b, u' Z/ @5 |
  3. class Person{3 Z4 v/ U" J" i- B, X
  4.     function __construct(){
    , \" H8 A( `( u$ U& l
  5.             echo 'I am one!';' I$ m+ q& b" b$ {
  6.         }
    " a! w) [* v  ?" J
  7. }
复制代码
  1. //name.php
    ' Y) _" ]! Q* b2 W
  2. require_once './1.php';
    1 @9 @$ I7 i# Q% V
  3. new \one\Person(); //输出 I am one!;
    % b) s! y6 F+ s
  4. new \Person(); //代码报错:Fatal error: Class 'Person' not found
复制代码

% ~5 j$ j% W, m+ q( V2 n% I
可以举个这个通俗例子来理解:带上指定命名空间代表某人的苹果(在他手里),顶级命名空间代表苹果箱里的苹果(在箱子里)。现在要找某人的苹果,就将某人的命名空间带上,否则就会从箱子里找某人的苹果,结果当然是找不到。

' D7 a1 K( Q: P! T& k5.命名空间声明后的代码便属于这个命名空间,即使有include或require也不影响(重点是对后半句的理解,具体看代码)。! y5 h" _8 ]" ~9 _9 C4 z: f, c6 C% c
  1. //1.php   $ ?- ~8 o' [8 W6 N% p8 n
  2. namespace one;
    6 ]: _2 y0 R) b- t; y$ w9 x# w  ?
  3. class Person{" |5 g2 j" F6 @0 a5 S7 D
  4.     function __construct(){6 t, F5 J* Y( r+ m
  5.             echo 'I am one!';
      i$ x, u) T" a) X
  6.         }9 i9 ?9 r8 [1 h# e! o
  7. }
复制代码
  1. //name.php* m7 e& S% K1 k0 B2 F* e+ R% y
  2. namespace test;
    8 S0 d1 Z* O5 e; b8 n2 p
  3. require './1.php';
    5 t5 T6 }  U' u. ]0 y
  4. new \one\Person(); //输出 I am one!;. @- n$ G: h9 q; B* p" u" @
  5. new Person();      //这里结果会是什么呢,猜猜看
    + N* B  X3 e2 }/ k6 Z
  6. 最后一行结果报错:
    9 R4 c2 k. d+ S8 y1 M
  7. Fatal error:  Class 'test\Person' not found
复制代码

2 @: N0 _$ j' D6 Z9 x8 A. {
0 v4 e- q2 L9 W" T
首先,这里与第2点比较一下:
第2点,我说,没有命名空间时,new类时,有没有反斜杠意义一样。
在这里,有了命名空间,有和没有反斜杠的意义就不一样了。
最后一行换成
  1. new \Person();
复制代码

5 n$ K  L! z$ }# m4 W
结果报错:
  1. Fatal error:  Class 'Person' not found
复制代码

% p. M+ ]$ T# b3 H( p& t
接着,就说说当前这点。
我们可以发现,最后一行代码对应的命名空间为test,并没有受到require文件里的命名空间的影响。
进一步加强验证,我修改了name.php文件如下:
  1. //name.php7 s. s' ]/ Z5 ]6 @
  2. namespace test;
    ' R" P1 {6 B1 P
  3. require './1.php'; $ z5 Z; ^- `0 q- C& ]
  4. % z+ h* G- o' l; p$ P
  5. class Person{
    ; w7 F) a$ ?- q& X: `
  6.     function __construct(){
    : o  N( Q; w: W4 |5 M+ c9 ?5 s
  7.             echo 'I am test!';
    . h4 p; C+ e7 b% u9 _( S, U
  8.         }
    / G# G2 K+ q0 l& [$ _4 T, N
  9. }% u$ q0 n* p/ {2 s! N) S

  10. & F& F" M  i: r6 p. c
  11. new \one\Person(); //输出 I am one!;5 p* G: B$ B5 _; L3 U3 u
  12. new Person();    //这里结果会是什么,自己猜猜看
复制代码
# z3 {$ w1 v$ a8 Y; a9 U
最后,这个例子刷新了我对require的认识了。
按照我以前对require的理解:PHP 程序在执行前,就会先读入 require 所指定引入的文件,使它变成 PHP 程序网页的一部分。所以我常常就简单的理解为替换,只不过把抽离出来的代码再放回原处而已。然后我试了将1.php文件内容放到name.php里:
  1. //name.php; e/ V% i' k8 q
  2. namespace test;
    9 H0 K  [, w- l! J8 U0 _' a8 j
  3. namespace one;+ ~8 i% t, B$ D
  4. class Person{+ r$ p  _; }' q, R2 q
  5.     function __construct(){& A5 h' J* m. x& o, _' ~. R" O$ n
  6.             echo 'I am one!';
    * {7 T0 S' K9 E/ n
  7.         }
    2 u3 _" \3 A9 T' N7 C9 |7 t( ~
  8. }& `/ X8 k3 _/ }7 F1 Y9 z% D) w

  9. 1 o. o6 K3 B' j8 a  d
  10. class Person{
    + a5 K9 F( @& H" M# M" R$ ^. n
  11.     function __construct(){0 e6 d, ^# [4 V  S4 Y4 t
  12.             echo 'I am test!';
    ) [9 e6 t/ e+ `+ P% Q
  13.         }% @. K2 k7 p& S% W  O" y6 k, G1 a
  14. }
复制代码

* V- q# y( X3 U7 M4 ?+ d/ t# p3 O( v) D
无需new类,该文件就会报错:
  1. Fatal error:  Cannot redeclare class one\Person
复制代码
+ v) ]( `& z, x9 C, e% V# g) t8 T
看来简单的把require理解为替换,在这里行不通。

, S7 i& H3 }2 B0 g$ H6 v6.namespace里不包含类名称,即使存在与类名称同名的部分,那也不代表类。new类时,还是得将这部分带上。& {6 m% i4 r8 G2 o  u
  1. //name.php* G  M1 b8 m4 A& B1 {- S( r% x2 ]0 k: q
  2. 6 t* J  m: z# y# o6 C
  3. namespace test\person;
    0 @# Q1 l9 K; t2 c2 R
  4. 9 ?! X" y8 S7 L$ i2 i/ {
  5. class Person{
    ' u: l( h7 b& r
  6.     function __construct(){2 ~! `. S& ~1 v2 X
  7.             echo 'I am test!';8 q! F0 p/ R) Z6 o: R( Q7 n6 V+ F4 \
  8.         }8 d9 F& v5 k; p* _7 k$ x) r
  9. }  ?; b1 b: K5 B& z* J/ c
  10. new \test\person\Person();  //命名空间里person无法代表类名
复制代码

4 A+ ]3 ?9 ~9 A8 I8 w) ^; e
不过这样纯粹是画蛇添足,直接干脆点,namespace里不要带类名称就好。

# P+ H( `6 j9 ^/ O0 \: R  `, S7.一个php文件中可以存在多个命名空间,第一个命名空间前不能有任何代码。
只说第一个命名空间前不能有任何代码,之后的命名空间之前可以有代码。这个自行测试即可。
  1. //name.php
    # O9 F* D$ R. K
  2. ; D" q9 z* p9 n- ]8 G
  3. namespace test;
    $ R7 b9 w0 H/ T# L9 j! B! u) ~+ z* V" b
  4. echo 'zhai14';- X! {- T9 H+ X4 S0 s- {
  5. namespace zhai;! u9 N- ^) [0 x6 p6 J
  6. require './1.php';
复制代码
4 ~4 n$ C0 I4 m' q# v& N
php命名空间namespace告一段落了,接下来说说use的用途。
使用use的目的:
在命名空间字符串过长时,使用use可以相应的缩短命名空间。
3 r) l! z/ F! ~, H0 \
use的使用方法:1.new类时,最前面无需用反斜杠。此外,use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。
  H3 h& p6 p6 u8 K0 m) W
  1. //name.php
    8 i; l3 l" w! y8 V6 a# E
  2. $ N$ _" X3 C5 W# D/ p! ?/ h  h
  3. namespace animal\dog;
    4 n. r9 D  u$ b# t8 h( L6 T

  4. . m+ z+ a' C5 o% c5 i; ^) [/ O
  5. class Life{9 {; m: c! f' }" f
  6.     function __construct(){* |+ E+ p" L6 I, i. ^8 n( I
  7.             echo 'dog life!';- b1 B* o) [) t+ I, j* A# B
  8.         }
    $ K3 a: C1 V+ p$ S
  9. }
    2 }/ j0 l, n: [) U
  10. " E' [* T  \" a6 U6 j' Q. J3 a
  11. namespace animal\cat;, v/ f1 |( ~) b+ N

  12. ) a% ^# t5 t" @7 u( F' F; a
  13. class Life{6 H9 v7 n% R4 {7 f  x
  14.     function __construct(){$ ?; ^* ^+ c4 n
  15.             echo 'cat life!';* }- ]& a  H& Z5 s. V
  16.         }% u! w' I) p3 s! ~- K6 j
  17. }
    . k5 E& t* j6 y$ [+ n2 ~2 W

  18. / z3 b0 ^  f0 @6 u8 ~
  19. new Life();  //按照代码执行顺序,这里默认animal\cat这个命名空间: M  ~4 ^/ W) F
  20. new \animal\dog\Life();  //A$ s3 _( I3 ^8 J/ P
  21. 1 V% |# j' P& M" ]$ i- W1 p7 I
  22. use animal\dog;  //a
    + G. d$ {, v5 E
  23. new dog\Life();  //B% C6 T, v" [5 R7 F

  24. % @3 f( T* g; s. D) v
  25. use animal\dog as d;  //b
    8 U8 m8 N% ]8 n$ ?+ [& {
  26. new d\Life();
复制代码
$ ?/ [7 P4 R! P
通过A、B行代码比较,需要注意:
使用use后,new类时,最前面没有反斜杠。
没使用use时,命名空间最前面有反斜杠
; j5 J' |2 b1 T6 ]% }+ r
通过a、b行代码比较,可以理解:
use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。如上的:
  1. use animal\dog;
复制代码
: f, K( ~1 o7 {0 d3 W; S
相当于
  1. use animal\dog as dog;
复制代码

: C* |0 D% }4 c1 ]2.namespace后面不建议加类名,但use后可以。6 r" S3 j" S- G+ M; |
  1. //name.php
    & h( K5 R) t0 i; |
  2. % l+ l) l" @+ M' W$ D  i! T6 t
  3. namespace animal\dog;6 i( _; o; ?7 D' y" S1 ]

  4. 6 w& v8 X6 Z4 A- _! B4 X
  5. class Life{. n' b$ o) A3 j6 L/ b9 D
  6.     function __construct(){# u% ?0 o2 P$ A
  7.             echo 'dog life!';
      |  i" i! Y$ w& ?+ t
  8.         }; Q0 x; k& V/ J: F
  9. }8 B4 X/ W( |( p' m4 |6 c  O' t
  10. 8 d3 ~3 L2 i! z; _8 N( y
  11. namespace animal\cat;( K. |3 m# n1 X: k( V

  12. + X* q! h0 G! u. J# I
  13. class Life{( d( ]- {. @3 l; ?0 X2 z% q  ?) S6 U
  14.     function __construct(){" u, p" N1 H" j
  15.             echo 'cat life!';1 q0 t4 b; R. O! L' H) M' S
  16.         }* j* `# ]5 P0 N# K' n
  17. }( U, Z  B2 \( d+ C" d& `, [. J

  18. $ {( Y% O& Y0 w9 S8 W
  19. use animal\dog\Life as dog;  ( A0 B% {+ `& V2 X! T. I) w
  20. new dog();
复制代码

) ?( p0 ]" {% X) s9 [
如上所示,use后加上类名后,就相当于把类改了个名称:由Life改为dog了。
上面不用as dog就会报错:
  1. Fatal error:  Cannot use animal\dog\Life as Life because the name is already in use
复制代码
, Y3 E  B  B: V
因为cat下也有个一样名称的Life类。
可以理解为,使用use后,这个昵称对应的类只能归当前命名空间占有,其它命名空间下不允许存在该类。
  1. //name.php+ S# ?* V) J+ q  Z
  2. , X. \- o$ P  e1 e$ g
  3. namespace animal\dog;% q( A( i3 P7 y$ e4 g

  4. ; y9 P, r6 h2 x6 l% ?
  5. class Life{
    4 u; u! k$ Y' g3 d
  6.     function __construct(){% Z& w$ c8 i0 [: M, T8 o5 R
  7.             echo 'dog life!';
    ) _4 ?# B1 S8 X, W
  8.         }2 I- a1 H; U/ i! Y  x& g% I( s' d
  9. }0 `3 g# r/ H& @7 e6 a6 {! b: S. _
  10. class Dog{" e7 f2 H6 k) c5 i; z$ S
  11.     function __construct(){
    $ C" |/ E6 J- b6 h
  12.             echo 'dog in dog!';  v! O- A2 s- \' n" @* W
  13.         }2 w- V0 w  u/ {1 u$ c
  14. }4 q* b- X' Q  R- g9 R

  15. 8 m0 p- f2 K; n9 J9 @
  16. namespace animal\cat;! Q7 ]$ j6 N6 Z5 M8 @# Y8 ]

  17. 5 r  u: M! V: h7 L
  18. // class Dog{1 S7 z, }! `: V" `' N8 o; }$ E3 w, [4 f
  19. //     function __construct(){4 C- w9 d$ U1 F( I0 H1 }
  20. //             echo 'dog in cat!';3 H* U& @, T! Z
  21. //         }
    ; o, ^8 P. {+ s: K
  22. // }7 h8 L, L1 T: t8 L
  23. class Life{
    8 S3 x4 e3 e( O4 |
  24.     function __construct(){
    ; P' H- b  s# t* z
  25.             echo 'cat life!';. L; i) K( F) _& v3 r$ T
  26.         }+ |$ b. w) D: m. j2 n
  27. }
    5 ?  f6 t$ _8 ^; J  X2 j
  28. 1 e( L* ]/ _3 M2 h" {$ z: H" {( d
  29. use animal\dog;  6 i$ H! k) o8 d; {6 J8 j8 V
  30. new dog\Dog();
复制代码
: W% y/ w3 J6 k5 H  H1 I- V! A
如上,使用了
  1. use animal\dog;
复制代码

/ v5 ]) ^  G* b* h& D- q1 L
cat
通过上面代码,我想使用use的目的效果(缩短命名空间名称)就很明显了。
9 L7 I% u9 f8 V* ?9 W. }9 T* L# m
简单总结一下:
namespace就是划分领域的作用,代表这些东西是属于某个命名空间下的。
use就是起小名的作用,不论写起来还是说起来都可以省不少事儿。
9 U% A9 m( j# E) O4 J1 a

$ p3 d2 Q# e$ a
5 x0 q3 C# l! x" N2 \& V0 Z* \! w5 N0 h) h) q

6 g3 s/ J0 A9 y+ M" q6 _
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2023-6-10 05:57 , Processed in 0.132988 second(s), 22 queries .

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