cncml手绘网

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

作者: admin    时间: 2020-7-1 23:37
标题: PHP命令空间namespace及use的用法实践总结
以下皆为本人自我理解内容,如有失误之处,请多多包涵。
( q! g  `8 F4 T( ]: b
文章大纲:
使用namespace的目的
namespace的使用方法
使用use的目的
use的使用方法

. Y/ u5 D4 Z# P+ `# R8 |6 e" c
& L* t+ u" [& K8 ]使用namespace的目的:
团队合作项目时,避免与团队其它成员新建的类发生冲突;个人负责项目时,避免前后新建的类发生冲突;
4 f/ d# a  D5 ^7 w3 A& `
据个人理解,用到所需要的类时,需要先require或include引入,所以会发生类重定义的错误的前提是:两个相同命名的类都有被引入。目前有些php框架会自动加载(即include)所有新建的model类,所以为了避免你新建的model类和项目框架原生的核心类发生重名冲突,采用了namespace。(想了想,与团队成员新建的类产生冲突应该通过沟通避免,即使事发后也应该重新调整类名即时维护,避免后期造成因为对类的理解混淆而带来维护上的复杂度提高)

' U  E0 c( X) R4 }# d/ ^: q结合使用方法来进一步理解它的使用目的吧。

, {9 X+ s, M, L0 @$ Q: k4 A& g" m$ Q. g8 D
namespace的使用方法:
为了进行测试,我将创建3个文件:1.php和name.php(此文件用来执行测试),后面将不再说明,请自行注意代码的变化。
1.namespace后命名的定义不区分大小写
  1. namespace one;
    5 f, I3 P) Y& ]3 O
  2. namespace One;
    ( |: m! F6 Y  h/ j" o
  3. namespace ONE;
复制代码

# w5 Q: D! u0 X8 ]2 }; Z
如上写法都可以,选择一种作为自己的规范即可。(后面代码我采用第一种进行测试哈)

0 w6 W; h! {7 m" [" v2. 没有定义命名空间,就理解为使用顶级命名空间。new类时,可以在类前加上反斜杠\,也可以不加。
  1. //1.php   $ t* V/ ~& Q& F: A* E
  2. class Person{
    ! `' I8 R" y- E
  3.     function __construct(){4 v2 j8 w1 u$ Z$ R) v
  4.             echo 'I am one!';, E6 q3 b& J" f% C" k2 E% Y
  5.         }
    ; R' B. q1 {" m  x1 u
  6. }
复制代码
  1. //name.php+ @/ N$ C9 x2 W( Y+ b
  2. require_once './1.php';
      u. L' [6 a4 y- h# E: i# `
  3. 4 o' _% D. s9 z3 g( C0 k6 J+ D
  4. new Person();     //输出 I am one!;
    & _8 F. P* d$ x% Q) b% t1 ?& k
  5. new \Person(); //输出 I am one!;
复制代码
7 U4 @0 o  H$ J2 t1 \3 y
3. new类时,带上命名空间时,之间一定用反斜杠字符,而不是顺斜杠。
记忆方法:按找%中斜杠的顺序理解为顺斜杠。(有时说反斜杠,自己都不知道是哪种方向,以前按自左向右上升方向这种方向记忆,现在感觉这个太不靠谱了)
  1. //name.php
    % u9 l8 Q. r) l
  2. require_once './1.php';
    8 O0 o2 l: F9 M7 @) t8 Y* M
  3. new /Person();  // 代码报错:Parse error: syntax error, unexpected '/'
复制代码
; R+ _. z, n( i
4.类在指定命名空间下, new类时,一定要带上指定的命名空间。
没有带上指定的命名空间,按照第2点,php就会从顶级命名空间里找这个类。切记:这里不能按照顶级命名空间包含一切其它的命名空间来理解。而应该将顶级命名空间完完全全与其他命名空间区分开。
  1. //1.php     w! d' f/ k: s# _0 s  R
  2. namespace one;
    , i7 D) t. @1 K9 A/ i) k
  3. class Person{
    - p0 p) G: \4 g/ H
  4.     function __construct(){
    : Z3 K  e6 u& f2 `& O  `; C) H
  5.             echo 'I am one!';
    6 {$ _  z* u4 X6 ~& q# V' H) R: a, x
  6.         }
    9 n2 ^6 U+ Y; H' k
  7. }
复制代码
  1. //name.php1 b8 f- ?% T% @$ A
  2. require_once './1.php';
    ( l$ C) Y5 e9 Z' t1 M
  3. new \one\Person(); //输出 I am one!;
    2 w' R% B/ g; @) x  b% y% e
  4. new \Person(); //代码报错:Fatal error: Class 'Person' not found
复制代码

# p6 {* @& t5 I: Q, K
可以举个这个通俗例子来理解:带上指定命名空间代表某人的苹果(在他手里),顶级命名空间代表苹果箱里的苹果(在箱子里)。现在要找某人的苹果,就将某人的命名空间带上,否则就会从箱子里找某人的苹果,结果当然是找不到。

+ m7 V1 ?* W1 y) Y2 D" H5.命名空间声明后的代码便属于这个命名空间,即使有include或require也不影响(重点是对后半句的理解,具体看代码)。
4 i" Y5 ~+ @9 Z  w* t) l$ \
  1. //1.php   1 z% s" F- W9 ?9 y( `* Z, I
  2. namespace one;
    6 w& c$ o+ Z5 Z& S) |7 h) g- {" a
  3. class Person{' D' F: c' B  b6 p% b$ H4 A
  4.     function __construct(){' @6 c0 A# z+ X+ O5 @) P
  5.             echo 'I am one!';
    4 y' y, }0 x( I9 s9 x
  6.         }! r5 S; `: }# j* F  j3 I8 A
  7. }
复制代码
  1. //name.php2 r" Z9 g9 Y! b
  2. namespace test;
    2 z% S; M4 |* c+ s+ M# E. |; x
  3. require './1.php'; & N+ S0 G2 Z, ]. k# G
  4. new \one\Person(); //输出 I am one!;
    " f- y. C0 z  }# V8 A
  5. new Person();      //这里结果会是什么呢,猜猜看
    ( w. |5 C( y! ~+ g2 V4 H- [) Z. Q/ U
  6. 最后一行结果报错:
    0 R' @' S" k1 l! C! `
  7. Fatal error:  Class 'test\Person' not found
复制代码

% q5 T. _; ]% @" B. ?' J2 b4 ]

, _9 ^1 W5 W& N) j6 Z首先,这里与第2点比较一下:
第2点,我说,没有命名空间时,new类时,有没有反斜杠意义一样。
在这里,有了命名空间,有和没有反斜杠的意义就不一样了。
最后一行换成
  1. new \Person();
复制代码

' V- z& f$ O: O9 o# ]  h
结果报错:
  1. Fatal error:  Class 'Person' not found
复制代码

+ u/ q1 k) h* g" J
接着,就说说当前这点。
我们可以发现,最后一行代码对应的命名空间为test,并没有受到require文件里的命名空间的影响。
进一步加强验证,我修改了name.php文件如下:
  1. //name.php0 M# r  I& E2 A* C( _( S
  2. namespace test;
    5 x/ v3 d7 p2 D9 l' N! ?4 u
  3. require './1.php';
    , s* X& Z- {/ ?- I6 {/ e- |; f

  4. , q- C' A. R* m
  5. class Person{
    + \# h# s6 \4 S/ G* i* L
  6.     function __construct(){4 ?  g$ U4 q- s* s% U
  7.             echo 'I am test!';
    7 h9 u) t) W7 b% ?  C6 ]
  8.         }
    ! @. n! _5 S& |
  9. }
    - w! o# r& X' d# p. l3 R
  10. , e2 X7 ^1 [5 _9 d6 g$ d+ ~1 F
  11. new \one\Person(); //输出 I am one!;
    # U+ W' k8 B. \" @2 H2 H
  12. new Person();    //这里结果会是什么,自己猜猜看
复制代码

& f/ b) g% P8 J
最后,这个例子刷新了我对require的认识了。
按照我以前对require的理解:PHP 程序在执行前,就会先读入 require 所指定引入的文件,使它变成 PHP 程序网页的一部分。所以我常常就简单的理解为替换,只不过把抽离出来的代码再放回原处而已。然后我试了将1.php文件内容放到name.php里:
  1. //name.php% t- w; N3 e" {$ U8 q
  2. namespace test;
    2 S9 K; i4 M. }( D  U' d$ R7 m
  3. namespace one;
    2 ~$ Z9 @" G. r; n  c( d
  4. class Person{6 e7 M- y! o9 O
  5.     function __construct(){
    " i% C+ Q4 K7 K- {- B
  6.             echo 'I am one!';, p  K- P6 H# T% B' n1 i+ ~
  7.         }: u) W( X& c5 F3 ]
  8. }
    ( D% M; {+ H+ c

  9. & _( P4 S6 k# g: j; k* |
  10. class Person{
    ; P" \( J% |% u
  11.     function __construct(){
    - z/ f2 G4 z3 n0 d0 C. @8 n
  12.             echo 'I am test!';4 L' q; S. c8 k" G$ N7 W2 c; C
  13.         }8 |1 {$ a5 h" j2 j) V2 d. |
  14. }
复制代码
2 v' z/ Z3 Y6 i: i6 r3 P& J  s: m7 E
无需new类,该文件就会报错:
  1. Fatal error:  Cannot redeclare class one\Person
复制代码
9 ^" x* j1 H5 V! s
看来简单的把require理解为替换,在这里行不通。
, z- F. D3 x: t
6.namespace里不包含类名称,即使存在与类名称同名的部分,那也不代表类。new类时,还是得将这部分带上。" S  O+ m5 j) |9 q* [+ p
  1. //name.php- j. g$ t9 _( x' ]
  2. ; [/ q9 J/ ~; h7 m
  3. namespace test\person;+ V7 l; K0 U3 e+ `4 b  L  k: A

  4. $ C/ x6 z$ J- `! y# f( v" ]' J
  5. class Person{, x) I+ O6 q3 e) @
  6.     function __construct(){' A- H  {5 Z* {- i
  7.             echo 'I am test!';
    3 t3 a3 q+ z  q. E% j8 L
  8.         }- F8 u+ G' E. U$ ~+ F% a6 |  H
  9. }" K1 K9 o4 a" K
  10. new \test\person\Person();  //命名空间里person无法代表类名
复制代码
/ H% s; H* w( \3 F0 ]
不过这样纯粹是画蛇添足,直接干脆点,namespace里不要带类名称就好。

" Z. ^' g2 b3 m1 |: \) a0 D8 S8 [7.一个php文件中可以存在多个命名空间,第一个命名空间前不能有任何代码。
只说第一个命名空间前不能有任何代码,之后的命名空间之前可以有代码。这个自行测试即可。
  1. //name.php( D6 a1 ~9 V/ ^; ]9 n

  2. & U9 x! o& E  y7 T
  3. namespace test;
    ! g& \$ ~0 H6 _: L! k% m8 D
  4. echo 'zhai14';7 V5 H: K6 \, ?! U& e4 \. A
  5. namespace zhai;) O! {; f  Y$ `0 q* v
  6. require './1.php';
复制代码
8 N0 R- ^2 t1 L9 d2 @# E
php命名空间namespace告一段落了,接下来说说use的用途。
使用use的目的:
在命名空间字符串过长时,使用use可以相应的缩短命名空间。
' F5 R! Q: Y! V# m  z  K
use的使用方法:1.new类时,最前面无需用反斜杠。此外,use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。/ s; s* K* ]! k: B: a
  1. //name.php& O1 m0 }, G1 f; \

  2. ) e) L# l+ {1 x. P7 R
  3. namespace animal\dog;
    , `8 P% K8 F5 N
  4. . T' H9 H6 V2 q; s# I
  5. class Life{, j; N4 v2 f/ U+ h( w( h
  6.     function __construct(){& m! T2 }% ^* _2 c7 J
  7.             echo 'dog life!';
    % {0 O0 C5 M: {% H
  8.         }8 w  _0 I6 r3 O
  9. }) r6 ^7 Z. v" a, E, U; \
  10. 7 p: q8 J2 J. Y/ D' n
  11. namespace animal\cat;
    0 l# R* p- L  L  r# s' y# p$ |

  12. - j, A$ Q% ]& t- E
  13. class Life{' s  d8 q& w8 F' x
  14.     function __construct(){/ h' u8 r1 s7 g" o4 X9 K
  15.             echo 'cat life!';
    ) G' R- l6 p0 T
  16.         }0 A$ @; u! p* k( }/ n! {
  17. }) h% \1 q( ^* F

  18. / H" N0 Q. ~) A3 {0 }4 O! d3 Z
  19. new Life();  //按照代码执行顺序,这里默认animal\cat这个命名空间/ ]; R8 i3 }# N8 K/ a
  20. new \animal\dog\Life();  //A& Y" P( k1 |- K
  21. + G, t8 X  s7 F$ T
  22. use animal\dog;  //a: ~5 @, k; M5 q1 x) C
  23. new dog\Life();  //B
      I) X9 z% J# R/ h, L: C. f) _
  24. 7 [9 W5 \( g  t2 |
  25. use animal\dog as d;  //b9 K% `- D0 C# d; W
  26. new d\Life();
复制代码
3 q: _) F6 m% \& G( J
通过A、B行代码比较,需要注意:
使用use后,new类时,最前面没有反斜杠。
没使用use时,命名空间最前面有反斜杠
9 G4 ]( p2 T7 M( m) @
通过a、b行代码比较,可以理解:
use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。如上的:
  1. use animal\dog;
复制代码

7 v; x& N- u1 E, \5 c3 p6 T
相当于
  1. use animal\dog as dog;
复制代码
7 R# ]. F+ S2 `/ R8 s
2.namespace后面不建议加类名,但use后可以。8 v  y9 S: k( f4 `& ~; v
  1. //name.php- ^" L2 s, |2 e% [2 i& B0 G5 _, P( R4 z

  2. 8 U" G7 t* d, i! R, t: q+ e
  3. namespace animal\dog;
    , ?/ m4 Z" X5 @. `0 `

  4. 9 E9 o' _, l) [1 C
  5. class Life{3 D9 b' A) t/ y3 M* _2 Z
  6.     function __construct(){4 u* o6 @9 J& u
  7.             echo 'dog life!';
    + S$ _+ v2 l. @2 k) L  K) m
  8.         }
    1 y. P. Y* y* Q$ [" a: L1 h
  9. }" X& U, }3 h* k+ f6 C
  10. " ], N$ T1 Q$ b- W; G1 @2 D  t- u
  11. namespace animal\cat;
    $ f' B) G' h9 ?. \
  12. ; g& D7 S; P) w
  13. class Life{# E. h" P$ A" E! c2 f0 |, `$ J" E
  14.     function __construct(){: J5 I1 o( g$ b1 X
  15.             echo 'cat life!';( F* s2 L+ w* F! @4 }3 R- W5 x
  16.         }! l* I( ~& i4 {+ K5 v3 ?
  17. }
      ?( H' b: E# D* u1 @+ N9 ?

  18. ) p# O! J$ |) c% p
  19. use animal\dog\Life as dog;  
    . C; r6 a4 D, g
  20. new dog();
复制代码
! `8 D( j4 r' _* K' e, F8 H
如上所示,use后加上类名后,就相当于把类改了个名称:由Life改为dog了。
上面不用as dog就会报错:
  1. Fatal error:  Cannot use animal\dog\Life as Life because the name is already in use
复制代码
  U: \- f6 k. y* x, j0 r
因为cat下也有个一样名称的Life类。
可以理解为,使用use后,这个昵称对应的类只能归当前命名空间占有,其它命名空间下不允许存在该类。
  1. //name.php& V6 g* `3 i' G9 [( G

  2. : z( l2 [. [6 X  ^% N$ P8 W
  3. namespace animal\dog;% t) x8 Q( X' _0 M2 p) l: `

  4. , ]( P% S- `' i2 [+ V
  5. class Life{
    + ?% @/ s0 D- C2 w3 a$ B, \
  6.     function __construct(){9 @6 I  w( Y& |7 `& t5 |1 L
  7.             echo 'dog life!';9 D" b9 Z0 N! t8 [4 d1 q8 R$ l" s
  8.         }. U1 `" j) {0 c! L. N
  9. }
    5 Z9 l  P- g# s6 u3 ^9 h- a
  10. class Dog{( g$ r- E  @" y- S% E
  11.     function __construct(){( m% I( d  O9 }1 r: {$ @+ R
  12.             echo 'dog in dog!';: V  w) }5 d, r
  13.         }/ d! ]7 y6 \# Y
  14. }
    / T6 @: C+ G& ?$ d

  15. % z: Y! [& i. C2 t
  16. namespace animal\cat;2 b9 |6 o7 I3 L) ^( b3 w
  17. ! U8 m8 w. b4 ~3 d* D# W" k
  18. // class Dog{( ?$ K" u$ z4 K" _
  19. //     function __construct(){
    0 w3 p, s) P' l- M5 d
  20. //             echo 'dog in cat!';
    # d% X+ F6 L9 n5 P. X7 m
  21. //         }& I2 U# g& j5 g0 ~4 f( w5 b/ j
  22. // }, B6 Q: g$ n3 k9 s# _
  23. class Life{
    ) C4 C" }( Z8 `, v0 u" r) {( I5 r
  24.     function __construct(){
    " u& S0 G0 |+ V7 c$ W( Y
  25.             echo 'cat life!';# K$ o! w5 ], Z' O, P2 |
  26.         }! {% m! g5 f9 [; S# n4 n
  27. }- P! X! y+ G) X. ~. h+ m5 M7 ~
  28. - D  O9 |9 w0 s8 u
  29. use animal\dog;  
    8 M) ?* i# u* k6 O8 T9 @/ x6 i0 F
  30. new dog\Dog();
复制代码

0 b/ M0 a3 W* r6 y3 U" S& p) A
如上,使用了
  1. use animal\dog;
复制代码

  k& L, ^! r3 o
cat
通过上面代码,我想使用use的目的效果(缩短命名空间名称)就很明显了。

7 R0 g( B. L! A
简单总结一下:
namespace就是划分领域的作用,代表这些东西是属于某个命名空间下的。
use就是起小名的作用,不论写起来还是说起来都可以省不少事儿。

' l& D7 W  A* Z$ ]$ p
* ^! K. n3 H7 @* [
; L  t! Z: ]6 G) Q0 T* F2 t8 q) r
. j6 \3 B9 O$ ^+ m; F0 H1 ?8 @) h$ @6 s: j( {" V0 C





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