cncml手绘网

标题: PHP命令空间namespace及use的用法实践总结 [打印本页]

作者: admin    时间: 2020-7-1 23:37
标题: PHP命令空间namespace及use的用法实践总结
以下皆为本人自我理解内容,如有失误之处,请多多包涵。
$ g, T1 K* P7 P' F; |
文章大纲:
使用namespace的目的
namespace的使用方法
使用use的目的
use的使用方法
, G. Z' A4 B( f
8 `9 @' P* o/ w; s
使用namespace的目的:
团队合作项目时,避免与团队其它成员新建的类发生冲突;个人负责项目时,避免前后新建的类发生冲突;
. _/ ?! |5 P- v& h9 @
据个人理解,用到所需要的类时,需要先require或include引入,所以会发生类重定义的错误的前提是:两个相同命名的类都有被引入。目前有些php框架会自动加载(即include)所有新建的model类,所以为了避免你新建的model类和项目框架原生的核心类发生重名冲突,采用了namespace。(想了想,与团队成员新建的类产生冲突应该通过沟通避免,即使事发后也应该重新调整类名即时维护,避免后期造成因为对类的理解混淆而带来维护上的复杂度提高)

/ H3 f3 p2 n4 S  |3 {, P结合使用方法来进一步理解它的使用目的吧。

' R7 t0 h, q% z8 B3 C( D3 v) z5 Z5 s) o$ Q5 `
namespace的使用方法:
为了进行测试,我将创建3个文件:1.php和name.php(此文件用来执行测试),后面将不再说明,请自行注意代码的变化。
1.namespace后命名的定义不区分大小写
  1. namespace one;5 Y1 t' z: {( \( T0 u3 u
  2. namespace One;) F- c: O& ^( r9 ?# L% O! L$ R
  3. namespace ONE;
复制代码
( R2 x7 Y7 T% P& q$ h' j
如上写法都可以,选择一种作为自己的规范即可。(后面代码我采用第一种进行测试哈)
. T% c4 k! q1 Y+ }* ]
2. 没有定义命名空间,就理解为使用顶级命名空间。new类时,可以在类前加上反斜杠\,也可以不加。
  1. //1.php   
    % a; K, [1 V! I- j. w% E2 W# \
  2. class Person{
    / h, k) `+ t  H4 Y
  3.     function __construct(){' ^( R- p' B9 M# {
  4.             echo 'I am one!';$ O& Q7 o; _7 i; `: B, ~" w
  5.         }
    ! c# h! |. e7 Z9 H) w/ A  R
  6. }
复制代码
  1. //name.php
    5 y' S/ p5 E, c, Z; e
  2. require_once './1.php';( N% Z8 b- p/ y. W
  3. 3 S) @: Q: k+ R# m, k( k) h6 V
  4. new Person();     //输出 I am one!;
    $ V3 r  s) ]3 E& y3 X1 ~$ b$ ^
  5. new \Person(); //输出 I am one!;
复制代码

7 {8 W+ v. d1 @$ v3 a3. new类时,带上命名空间时,之间一定用反斜杠字符,而不是顺斜杠。
记忆方法:按找%中斜杠的顺序理解为顺斜杠。(有时说反斜杠,自己都不知道是哪种方向,以前按自左向右上升方向这种方向记忆,现在感觉这个太不靠谱了)
  1. //name.php; _9 @, b) I+ K3 y
  2. require_once './1.php';
    ( e! g* n/ Z% I0 c( z0 E
  3. new /Person();  // 代码报错:Parse error: syntax error, unexpected '/'
复制代码
) I& H, t  d& H
4.类在指定命名空间下, new类时,一定要带上指定的命名空间。
没有带上指定的命名空间,按照第2点,php就会从顶级命名空间里找这个类。切记:这里不能按照顶级命名空间包含一切其它的命名空间来理解。而应该将顶级命名空间完完全全与其他命名空间区分开。
  1. //1.php   5 w6 ~1 w& ]2 H! L
  2. namespace one;
    & t! t) B& d, q; P2 {" A  b0 R
  3. class Person{$ m# Q( Y7 ^! u6 X. \* ?
  4.     function __construct(){
    " h9 L# R% k, \  n6 V2 Z
  5.             echo 'I am one!';
    5 x5 u; K: J, l5 w9 a+ P. J
  6.         }' {: b1 L9 j8 n; A" K6 e: X
  7. }
复制代码
  1. //name.php& C1 Q6 G0 r( Y
  2. require_once './1.php';/ b9 L9 o' V8 _: M9 ?! H6 }
  3. new \one\Person(); //输出 I am one!;
    : u4 U+ c$ X" M) O9 ^3 ^2 c( u/ T
  4. new \Person(); //代码报错:Fatal error: Class 'Person' not found
复制代码

' d4 P! P& r- D% K; t' J7 f/ ?  u
可以举个这个通俗例子来理解:带上指定命名空间代表某人的苹果(在他手里),顶级命名空间代表苹果箱里的苹果(在箱子里)。现在要找某人的苹果,就将某人的命名空间带上,否则就会从箱子里找某人的苹果,结果当然是找不到。

/ z% i& b( M5 c* n# d5.命名空间声明后的代码便属于这个命名空间,即使有include或require也不影响(重点是对后半句的理解,具体看代码)。1 }  [* Y( `. q! h0 N! B
  1. //1.php   
    8 ]* z: E0 O. \7 c3 `
  2. namespace one;
    4 w& L9 z, U7 q
  3. class Person{3 S1 r8 w' ]  @/ T% a# j3 D
  4.     function __construct(){4 o2 L/ _6 f, C. R# {" `
  5.             echo 'I am one!';% w- q* w! ?  u; i- g9 x5 t
  6.         }
    . k. l" T" `, U+ Z% X- }/ O
  7. }
复制代码
  1. //name.php
    $ g& }0 q+ Y7 ^% \( q& s. O2 H' c$ ~
  2. namespace test;
    - G" Z$ Z% J& U' z
  3. require './1.php'; 1 `' I$ O$ G( K9 B$ @
  4. new \one\Person(); //输出 I am one!;6 b- m7 n+ z- X4 z& j+ o' t3 \# D& W
  5. new Person();      //这里结果会是什么呢,猜猜看. R8 l  p/ I7 R' m7 `% A$ V2 o- Y% P4 I
  6. 最后一行结果报错:
    ( h# ~- G4 y# d! G' P2 @
  7. Fatal error:  Class 'test\Person' not found
复制代码

* b* l9 K/ ]# [, X9 j3 D
8 Y' o1 K' k% G8 A: P" ^
首先,这里与第2点比较一下:
第2点,我说,没有命名空间时,new类时,有没有反斜杠意义一样。
在这里,有了命名空间,有和没有反斜杠的意义就不一样了。
最后一行换成
  1. new \Person();
复制代码
1 ?: X8 f, @6 ?$ l) |
结果报错:
  1. Fatal error:  Class 'Person' not found
复制代码
5 i4 ]* Y. y+ h! A3 w" p
接着,就说说当前这点。
我们可以发现,最后一行代码对应的命名空间为test,并没有受到require文件里的命名空间的影响。
进一步加强验证,我修改了name.php文件如下:
  1. //name.php
    * e! m. S/ U; X5 W9 v7 O
  2. namespace test;8 B% n+ m/ K6 T
  3. require './1.php'; , `7 B& N4 F0 y  E% E

  4. 1 `: @8 z4 @) X$ {8 R6 i
  5. class Person{1 x" m/ O3 r" f7 {! A8 {+ d
  6.     function __construct(){
    1 @9 T7 U: F8 W8 U9 }8 v
  7.             echo 'I am test!';
    - X+ I  H/ I- Q$ X% n! l1 ]
  8.         }
    * ^4 V/ D/ g& f: Z. F) C
  9. }
    : _9 i  U1 n4 `7 t
  10. : q$ e$ e& o( f% w8 m+ M3 O' I5 [
  11. new \one\Person(); //输出 I am one!;
    7 x2 M' w8 u- |5 q1 y- R
  12. new Person();    //这里结果会是什么,自己猜猜看
复制代码

! r) }+ v8 \9 X, C! v7 `5 l! [# P
最后,这个例子刷新了我对require的认识了。
按照我以前对require的理解:PHP 程序在执行前,就会先读入 require 所指定引入的文件,使它变成 PHP 程序网页的一部分。所以我常常就简单的理解为替换,只不过把抽离出来的代码再放回原处而已。然后我试了将1.php文件内容放到name.php里:
  1. //name.php
    + b1 d& s3 a4 _  }7 |) R/ A- K) O
  2. namespace test;" j; h/ k% q0 f3 L" X
  3. namespace one;
    * G/ `$ d$ E' R, V6 x
  4. class Person{; u- j4 x3 z% I1 g
  5.     function __construct(){
    & u0 P1 X, ]# _  T% T; ?
  6.             echo 'I am one!';
    + G+ j, D6 x3 }8 }1 c0 _  h$ m
  7.         }
    , V: Q/ v" I/ ?, m: |3 |  L3 R
  8. }
    0 u6 D, H. a0 n5 e5 l% N; d
  9. , r% k' w7 {0 V4 b0 F
  10. class Person{
    5 w, c9 L7 r! |: D+ l, {3 H
  11.     function __construct(){
    & O( @7 w& _. |/ X/ q$ L
  12.             echo 'I am test!';
    + f0 ^. s6 Z/ Q9 v
  13.         }( I$ d) H  |2 o
  14. }
复制代码
7 j* z% H1 b) T
无需new类,该文件就会报错:
  1. Fatal error:  Cannot redeclare class one\Person
复制代码

& t- O! I: ^! S- r  m
看来简单的把require理解为替换,在这里行不通。

8 f9 B( H+ _1 t  N" L0 C4 ~; m6.namespace里不包含类名称,即使存在与类名称同名的部分,那也不代表类。new类时,还是得将这部分带上。  w# N& l( w* S0 B* o
  1. //name.php
    % v* H# Z, P. h* X1 T

  2. * H  ~4 S! K( W( Y" x; s
  3. namespace test\person;
    0 J, A6 Q+ ]. b& f

  4. ! b( o+ w$ A8 j, S9 s! y  w' e3 X
  5. class Person{, ]. n+ Z) _  k5 T" C, o
  6.     function __construct(){
    ! T! @* u  X4 d. S* z/ w" b0 p3 e
  7.             echo 'I am test!';# L2 x$ [9 b7 ], Y
  8.         }+ S- {. `# ?7 j% q* U' P% ]4 i5 D! o
  9. }
    & L, U$ m# z8 Z; f4 E. t" b9 h
  10. new \test\person\Person();  //命名空间里person无法代表类名
复制代码
" H# q7 n4 j/ f5 T' C) C0 A
不过这样纯粹是画蛇添足,直接干脆点,namespace里不要带类名称就好。

! c4 v1 L* z( k% e8 h' c0 V7.一个php文件中可以存在多个命名空间,第一个命名空间前不能有任何代码。
只说第一个命名空间前不能有任何代码,之后的命名空间之前可以有代码。这个自行测试即可。
  1. //name.php
    + q- _+ ^9 z4 p  x& ^# [: M! g# d3 p

  2. - @; Z, ^$ Y0 `1 J) @2 |0 ]
  3. namespace test;
    % Q+ c9 L1 [6 N2 l+ a
  4. echo 'zhai14';+ G9 h. p, p: X. U- e; P
  5. namespace zhai;5 ~) M3 ^) Y3 K8 H* x/ h
  6. require './1.php';
复制代码
" Z/ Y2 E( u6 _7 W# R  s
php命名空间namespace告一段落了,接下来说说use的用途。
使用use的目的:
在命名空间字符串过长时,使用use可以相应的缩短命名空间。

4 I1 {8 A7 ^/ ?use的使用方法:1.new类时,最前面无需用反斜杠。此外,use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。
0 I/ u7 D" [# d0 m1 I6 T; Y+ f
  1. //name.php  P9 o8 m4 S5 h! N. H( O
  2. 9 ?6 z$ D" D6 J' d: v; x
  3. namespace animal\dog;: d4 E. g8 C0 r2 e  A7 ]! L$ ~4 M
  4. ! k8 Y2 P' t, u+ }0 d
  5. class Life{
    . g/ h# q0 _- |0 Z" Y( k8 O" p
  6.     function __construct(){2 {; U% M, t5 |7 B
  7.             echo 'dog life!';
    - K3 p; J; m, e4 g" O5 S3 n
  8.         }& |+ o  s9 V2 i& ]0 \) p/ y
  9. }
    " N2 s  A0 n1 L8 o9 W
  10. 2 j$ g. M  J9 b! z3 o
  11. namespace animal\cat;
    + {3 q: S" t- i- z/ L: j, O! O+ E7 a
  12.   d0 b' V+ @7 Z0 I9 S; H0 A
  13. class Life{
    ; M8 r: H8 r2 J2 d0 o6 ~; U
  14.     function __construct(){' r/ w0 [4 n5 D2 T* b
  15.             echo 'cat life!';
    ) g- v% U; e; d2 S. d, ^" w6 K
  16.         }
    - [/ n3 ]9 |/ d( X! L
  17. }
    ! R9 ]; ?$ L% @

  18. 2 U- c4 `4 ?+ F; R, O* [: y
  19. new Life();  //按照代码执行顺序,这里默认animal\cat这个命名空间
    # r* e  M# ?6 ]( t2 t1 N
  20. new \animal\dog\Life();  //A' B3 G% H" T- v2 C0 a& N( o% L

  21. , C( X6 d' n3 Y
  22. use animal\dog;  //a& z1 H' }, E( R" r
  23. new dog\Life();  //B
    , |( E" q' H2 z4 ?* `& u; p

  24. / R/ x4 f: M8 c. |7 I, _+ {4 b
  25. use animal\dog as d;  //b
    & t0 g5 U- F3 O
  26. new d\Life();
复制代码

6 N' H* X1 I( E/ O
通过A、B行代码比较,需要注意:
使用use后,new类时,最前面没有反斜杠。
没使用use时,命名空间最前面有反斜杠
% Z' W. q% h" P5 G6 H( Q) l
通过a、b行代码比较,可以理解:
use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。如上的:
  1. use animal\dog;
复制代码

9 ?" Y: y  h- {( O
相当于
  1. use animal\dog as dog;
复制代码

- p% o# [. p2 ?, A: A2.namespace后面不建议加类名,但use后可以。7 q2 {% l; ?3 Z  v# j, F8 t
  1. //name.php
    4 a& o: S) I2 u
  2. 9 \2 L9 O( h# P5 ?
  3. namespace animal\dog;
    2 U. j' O2 G. G3 [8 [6 @1 n9 r
  4. ) \  _7 X( {) l3 }" \
  5. class Life{/ a+ ]5 F4 {" D% S
  6.     function __construct(){
    & W4 U4 K% u: |7 A, P
  7.             echo 'dog life!';4 {1 S5 R4 i% I
  8.         }
    3 \1 I8 o: @# J4 x# V  N9 Y
  9. }8 E- E5 b( M/ U) x- |

  10. # L$ i+ i$ Y- s( g4 N
  11. namespace animal\cat;: X$ \+ l: v1 Y4 g0 ?) R
  12. ( [$ k: i% W5 Y! t( M5 t) F
  13. class Life{* B4 d" q' Z, B& o0 O8 @
  14.     function __construct(){6 `- x  Z4 j) h5 s# t1 C+ z3 ^0 \
  15.             echo 'cat life!';* [5 q. ^' U, U( s! V8 ~- x5 Y/ c
  16.         }5 l" X4 G3 {+ n/ d5 Y8 U
  17. }" T4 p* P4 e" k, g+ z. F
  18. - u5 c" a: T. y1 ?6 b( E
  19. use animal\dog\Life as dog;  
    9 J. @# V$ I+ h# _' ?0 @
  20. new dog();
复制代码
; A7 @  o0 X; v& I+ B
如上所示,use后加上类名后,就相当于把类改了个名称:由Life改为dog了。
上面不用as dog就会报错:
  1. Fatal error:  Cannot use animal\dog\Life as Life because the name is already in use
复制代码
7 j4 H) Y; w- ~; ]$ _( |; n' _8 h
因为cat下也有个一样名称的Life类。
可以理解为,使用use后,这个昵称对应的类只能归当前命名空间占有,其它命名空间下不允许存在该类。
  1. //name.php" d' o2 L) V1 ]! A
  2. 1 w  ], |% `) \- N3 s/ c
  3. namespace animal\dog;9 W* w6 |' g* X/ V# @) w9 R

  4.   B$ v5 H8 }- {! ]8 l" q
  5. class Life{
    - h! i; L9 \) G1 ^* c) G
  6.     function __construct(){
    9 @, R# i1 S" n8 h% x
  7.             echo 'dog life!';
    1 t1 J. V- O/ |; b" r
  8.         }
    % k. q' @1 ]! B# ]+ N
  9. }# T3 }0 Z" T: J
  10. class Dog{3 D4 H6 X4 e" i. E; O+ ^6 ^: q. j' w: T
  11.     function __construct(){
    ; q+ E) m3 p/ f6 \( I  x; K3 H
  12.             echo 'dog in dog!';5 y  t, b. _. F) h
  13.         }- ^2 t0 H9 U4 J: k
  14. }( n/ Q4 z, K+ K$ L& q# Q$ y
  15. 9 c0 M# j, \) @" a: B
  16. namespace animal\cat;" M- Y1 [+ X" k- @. a

  17. 3 z( @3 n5 F7 y
  18. // class Dog{
    . G( ]; P4 d6 |. \7 K0 V
  19. //     function __construct(){0 ^3 R  \/ \+ k/ E  o9 M8 [3 A2 r
  20. //             echo 'dog in cat!';3 g& j+ C, t$ b! [4 _/ K* m
  21. //         }2 n" z' \  {% `# h
  22. // }% R& Q4 e1 w% ?
  23. class Life{/ x* B+ c* L5 E7 e( s
  24.     function __construct(){% h& @) k. O+ x; _) h  w* w" Q. G
  25.             echo 'cat life!';
    & A5 P! v9 m2 p8 X
  26.         }
    9 G' b7 B5 U3 M
  27. }
    ) A5 k0 n! A6 A8 H0 M  \
  28. ( x6 o' L( j- g' d7 ]
  29. use animal\dog;  
    0 W8 T' s7 D, A/ L9 w
  30. new dog\Dog();
复制代码

" X4 I* t5 j% P8 \* W0 {
如上,使用了
  1. use animal\dog;
复制代码
; B3 b0 y6 U+ m! a+ L9 h
cat
通过上面代码,我想使用use的目的效果(缩短命名空间名称)就很明显了。
0 [6 ^0 W1 }! l. d
简单总结一下:
namespace就是划分领域的作用,代表这些东西是属于某个命名空间下的。
use就是起小名的作用,不论写起来还是说起来都可以省不少事儿。

( ~9 B# ]$ U% y( [* f! \$ P9 ~
& _/ Y7 o7 R% b( Z  X8 d* {4 q$ r- G& `& c4 z. r

: r# X3 n- t. u* @- r
8 Q9 q9 K% n- j) p. d& V




欢迎光临 cncml手绘网 (http://bbs.cncml.com/) Powered by Discuz! X3.2