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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2020-7-1 23:37:46 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
以下皆为本人自我理解内容,如有失误之处,请多多包涵。
# c( o- j3 d# p
文章大纲:
使用namespace的目的
namespace的使用方法
使用use的目的
use的使用方法
7 Z: ?* k5 v0 {2 a) A& p- ]2 a2 j- E8 s' g

0 N$ g7 h6 @; F$ l& R( d  L使用namespace的目的:
团队合作项目时,避免与团队其它成员新建的类发生冲突;个人负责项目时,避免前后新建的类发生冲突;
2 b. A3 {) J0 }/ t, w0 G
据个人理解,用到所需要的类时,需要先require或include引入,所以会发生类重定义的错误的前提是:两个相同命名的类都有被引入。目前有些php框架会自动加载(即include)所有新建的model类,所以为了避免你新建的model类和项目框架原生的核心类发生重名冲突,采用了namespace。(想了想,与团队成员新建的类产生冲突应该通过沟通避免,即使事发后也应该重新调整类名即时维护,避免后期造成因为对类的理解混淆而带来维护上的复杂度提高)
! X* y9 z, y: s8 A3 k* U
结合使用方法来进一步理解它的使用目的吧。
/ a( Y; ]' \% `5 b$ H; N
$ T  A  {+ b; K! L& I
namespace的使用方法:
为了进行测试,我将创建3个文件:1.php和name.php(此文件用来执行测试),后面将不再说明,请自行注意代码的变化。
1.namespace后命名的定义不区分大小写
  1. namespace one;
    $ w! i  k* Z3 k! D* ]# L" U, P
  2. namespace One;
    7 `/ e6 c: N. I: x4 U
  3. namespace ONE;
复制代码
8 P6 L, A+ ?. r! M* \7 S
如上写法都可以,选择一种作为自己的规范即可。(后面代码我采用第一种进行测试哈)
, O3 u# g, y* |3 ^% P
2. 没有定义命名空间,就理解为使用顶级命名空间。new类时,可以在类前加上反斜杠\,也可以不加。
  1. //1.php   
    ; ?+ e0 y' s  c' o. `
  2. class Person{2 Q  g8 `' F# ^2 z. r4 a4 S
  3.     function __construct(){% _# N+ s8 P: z- ]. r( Z
  4.             echo 'I am one!';. m2 ?; _4 c3 }. {
  5.         }
    8 ?- M9 N7 s, ^  b, ?( R: h
  6. }
复制代码
  1. //name.php
    " S% m& T# A5 d, ]; f0 ?
  2. require_once './1.php';
    4 c: _. k3 I( Y# R# @
  3. ! E7 ~' Z+ G: j3 C9 r) @
  4. new Person();     //输出 I am one!;
    ( k* T" y& b( U
  5. new \Person(); //输出 I am one!;
复制代码
5 y- H  I" u  P: E' x2 F: \
3. new类时,带上命名空间时,之间一定用反斜杠字符,而不是顺斜杠。
记忆方法:按找%中斜杠的顺序理解为顺斜杠。(有时说反斜杠,自己都不知道是哪种方向,以前按自左向右上升方向这种方向记忆,现在感觉这个太不靠谱了)
  1. //name.php
    ' |% g- R" U% m4 u) O# y& e8 z1 b1 g, `
  2. require_once './1.php';( \. ^6 x& a, N9 o% P8 q, K
  3. new /Person();  // 代码报错:Parse error: syntax error, unexpected '/'
复制代码

' `5 u' i6 i2 @3 M4.类在指定命名空间下, new类时,一定要带上指定的命名空间。
没有带上指定的命名空间,按照第2点,php就会从顶级命名空间里找这个类。切记:这里不能按照顶级命名空间包含一切其它的命名空间来理解。而应该将顶级命名空间完完全全与其他命名空间区分开。
  1. //1.php   0 m, @* }' d) f: Y
  2. namespace one;
    " B; m: [5 N0 [4 g- O! ]8 Y5 k
  3. class Person{. J5 ?( K* @  l' e! k
  4.     function __construct(){% w" D3 B* L% l4 \0 f
  5.             echo 'I am one!';1 o9 E- k. J8 y$ N
  6.         }5 p5 b% M8 m1 E) y0 P; M; e5 R7 p
  7. }
复制代码
  1. //name.php
    0 ?6 u: n5 t! y1 x& ^; ^
  2. require_once './1.php';
    6 |- H  f6 [7 Z
  3. new \one\Person(); //输出 I am one!;
    7 t/ U7 T9 Q( a) y9 F9 K1 V' B) Z: p6 D
  4. new \Person(); //代码报错:Fatal error: Class 'Person' not found
复制代码

4 v( S9 s' m. @
可以举个这个通俗例子来理解:带上指定命名空间代表某人的苹果(在他手里),顶级命名空间代表苹果箱里的苹果(在箱子里)。现在要找某人的苹果,就将某人的命名空间带上,否则就会从箱子里找某人的苹果,结果当然是找不到。

# H3 c* ~& N. D: i* L5.命名空间声明后的代码便属于这个命名空间,即使有include或require也不影响(重点是对后半句的理解,具体看代码)。
7 L9 {) v9 o- f( `  p5 l: X
  1. //1.php   
      I0 e& t* s6 B8 q( Q1 `
  2. namespace one;0 K* R8 L$ o5 O' b: [
  3. class Person{
    . ]' _, X+ V- y2 K* I# W# N
  4.     function __construct(){
    / T/ }. A  W8 j; v0 l
  5.             echo 'I am one!';' h8 [4 l$ M8 k+ ~* b. ~  W; L
  6.         }
    ; M, Z. B- b  ]1 Y" x
  7. }
复制代码
  1. //name.php5 G+ W4 R7 A8 A5 l4 s
  2. namespace test;) Q% n# O3 t; ?' F$ E
  3. require './1.php';
    ; l0 D( _  _; |1 G1 V3 Y9 {: ^* m
  4. new \one\Person(); //输出 I am one!;
    8 e& @5 Z  b" q4 t; L# H) n+ h, ?# }
  5. new Person();      //这里结果会是什么呢,猜猜看
    ! t$ Q, ?0 b$ G0 `
  6. 最后一行结果报错:  _9 t% o8 a# a# d) P* Q9 }( P5 g6 R
  7. Fatal error:  Class 'test\Person' not found
复制代码

$ s6 G, R7 k: @. _& i
9 J) X( y9 O0 R8 B
首先,这里与第2点比较一下:
第2点,我说,没有命名空间时,new类时,有没有反斜杠意义一样。
在这里,有了命名空间,有和没有反斜杠的意义就不一样了。
最后一行换成
  1. new \Person();
复制代码
  o! J) Q4 h; O/ D
结果报错:
  1. Fatal error:  Class 'Person' not found
复制代码
  C9 L9 H* C  Y  s1 a( d
接着,就说说当前这点。
我们可以发现,最后一行代码对应的命名空间为test,并没有受到require文件里的命名空间的影响。
进一步加强验证,我修改了name.php文件如下:
  1. //name.php
    7 ^+ Y8 ^7 C% x7 h8 f! V2 {9 X
  2. namespace test;
    8 g% Y: x. i! r' f$ a
  3. require './1.php';
    5 l; K. X# v* S1 c
  4. % Z7 a! j& ]) {! n: D( }
  5. class Person{$ z; X2 r: ~  m4 i5 i6 E& M& {) p+ }
  6.     function __construct(){
    # b; s: K& q/ y# T; g+ D
  7.             echo 'I am test!';
    # _; t* x2 B- X# F
  8.         }
    8 |. {8 Z7 c* Z+ M8 Q2 ^
  9. }
    7 V+ `: B) T; e' O5 k8 R

  10.   |/ ?9 o8 ?6 V) h7 `1 r
  11. new \one\Person(); //输出 I am one!;
    : C6 R$ R- j9 m9 B8 o3 W
  12. new Person();    //这里结果会是什么,自己猜猜看
复制代码
* f% }. i' Y5 }- Q) {# F
最后,这个例子刷新了我对require的认识了。
按照我以前对require的理解:PHP 程序在执行前,就会先读入 require 所指定引入的文件,使它变成 PHP 程序网页的一部分。所以我常常就简单的理解为替换,只不过把抽离出来的代码再放回原处而已。然后我试了将1.php文件内容放到name.php里:
  1. //name.php5 T8 F$ ]& {- j0 v4 y
  2. namespace test;
    ( o. s) H# O% r) T& O6 |3 i* }
  3. namespace one;9 B# x' o  @  B3 S3 z! t4 h, }
  4. class Person{
    , G. b! h9 v, y& C+ X; N
  5.     function __construct(){
    - U& v$ H% x, ^  V+ X
  6.             echo 'I am one!';
    % L" ?3 L7 j1 S9 t+ F3 \
  7.         }( L0 s0 w5 @2 U* k
  8. }
    " {* S2 y3 ~7 _

  9. % d+ Z/ ?( }/ l) b! H
  10. class Person{; a5 k; ~2 P* R* {5 Z9 ]
  11.     function __construct(){6 R9 ^2 D; N6 L) w. o; f2 P2 L
  12.             echo 'I am test!';
    ; I. j' M" y( t' u3 Z
  13.         }
    ! p* U8 T* p; f' E3 B) I
  14. }
复制代码

% P" h+ w4 Z% S/ Z. B" z2 f! p/ R
无需new类,该文件就会报错:
  1. Fatal error:  Cannot redeclare class one\Person
复制代码
& t% |: V2 g& @/ Q* ^& m6 A$ K
看来简单的把require理解为替换,在这里行不通。

% L6 b7 X+ C7 L2 b2 Y) K" w/ a4 l* F6.namespace里不包含类名称,即使存在与类名称同名的部分,那也不代表类。new类时,还是得将这部分带上。
* N, z' S3 H6 Q
  1. //name.php
    $ z( l. ^8 p% B5 \! k+ K

  2. 4 H6 q, s! r4 T
  3. namespace test\person;
    ' Z3 H- R$ Z& K/ \4 G* w

  4. ( @+ \+ t) [/ M) L
  5. class Person{
    7 T6 D: R9 S. S6 b0 }
  6.     function __construct(){
      Q; w) n% ]* s7 v# ]2 K( b4 F5 E9 `
  7.             echo 'I am test!';
    3 S. z9 B: q  r: S7 U
  8.         }, U3 ?1 p# c1 _4 C
  9. }7 q4 I. Z' K- w- q
  10. new \test\person\Person();  //命名空间里person无法代表类名
复制代码

; U6 y! z5 V8 l; c: K; {* L8 [
不过这样纯粹是画蛇添足,直接干脆点,namespace里不要带类名称就好。

# q8 u* L3 j2 s' c7 O7.一个php文件中可以存在多个命名空间,第一个命名空间前不能有任何代码。
只说第一个命名空间前不能有任何代码,之后的命名空间之前可以有代码。这个自行测试即可。
  1. //name.php' r0 [0 M6 Z  E9 G4 I7 e5 _/ E( O
  2. * [6 a# z- _( k* o
  3. namespace test;
    , s1 {6 X5 n2 U- Q6 D- J- z% \5 @
  4. echo 'zhai14';' C7 i! N! R# u" y
  5. namespace zhai;
    : r- c+ m/ T9 C0 [, G; M% r
  6. require './1.php';
复制代码
& D" k; O% w7 A: }  e5 Y' U
php命名空间namespace告一段落了,接下来说说use的用途。
使用use的目的:
在命名空间字符串过长时,使用use可以相应的缩短命名空间。
. t1 u; m& R, \: `8 h
use的使用方法:1.new类时,最前面无需用反斜杠。此外,use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。
. }( `9 O- Y: @  s
  1. //name.php
    1 ?8 T+ E) p% B: Z

  2. , C' [/ v  T$ s8 }6 m3 X  W* J
  3. namespace animal\dog;9 ]) h, n: Y& s- ?( d
  4. 2 n4 S4 S- _) T9 U9 ~
  5. class Life{0 [( \' Z5 Z% ?- g/ m
  6.     function __construct(){, d; _7 Z/ x6 U# D! n) J0 e
  7.             echo 'dog life!';
    + C7 K/ ]$ F5 m
  8.         }
    - v4 [. y: N4 T! d( F/ ^3 n
  9. }
    ; Q. _! X7 t- K( D% b( b- V% ~& ~

  10. 1 ]' G" r2 b8 [. f  i
  11. namespace animal\cat;
    - {/ v$ P  n# R4 T  |% s4 Z

  12. 4 y& f6 S3 a5 E) K
  13. class Life{* G" v$ i7 s% F0 j' X* D
  14.     function __construct(){% C7 s% D3 u. J) c
  15.             echo 'cat life!';( {" M; O0 }5 ^. v, m) h2 `2 [
  16.         }% f3 t3 `; T* s; u
  17. }
    ! U; M- @* v6 m$ c, E  q) ?

  18. 2 V% p# @1 z/ R( ]6 Y9 y1 Z
  19. new Life();  //按照代码执行顺序,这里默认animal\cat这个命名空间! C8 [* D5 m; l. K4 b  i
  20. new \animal\dog\Life();  //A+ `1 z7 }! X( h: }6 A
  21. $ c5 _$ O( c8 |! Q: ?4 ^9 ~
  22. use animal\dog;  //a
    0 B1 z0 \6 V8 d  K; k) _! l' F
  23. new dog\Life();  //B
    . w9 J9 V- W# p  n7 z
  24. 0 v8 s, q) `, I5 s4 g
  25. use animal\dog as d;  //b6 @  F4 f7 }. P
  26. new d\Life();
复制代码

+ }3 h% w+ k+ ^$ ~" S. E1 ?
通过A、B行代码比较,需要注意:
使用use后,new类时,最前面没有反斜杠。
没使用use时,命名空间最前面有反斜杠

% b- Y, ~, O7 I
通过a、b行代码比较,可以理解:
use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。如上的:
  1. use animal\dog;
复制代码
2 j/ _" n7 \; i$ w* U
相当于
  1. use animal\dog as dog;
复制代码
  G% S6 v: ]# X! c1 f( f. `# ?
2.namespace后面不建议加类名,但use后可以。2 `! y& }( c1 @2 N& X! s
  1. //name.php
    6 @; Y$ i% i$ C6 K8 g) _- D

  2. 0 W. Q( J0 e( d" Y4 j5 X
  3. namespace animal\dog;
    ; E! d4 v4 a; x9 x% S& o3 }. r# o
  4. & {1 F7 p" F/ B1 Y. l; s
  5. class Life{! C. [( M; U2 h5 W) O
  6.     function __construct(){
    5 E) m% z  A4 ?( E- }8 N- F
  7.             echo 'dog life!';
    # W4 k7 n& W+ p0 l7 K
  8.         }
      B/ ^! [2 D3 n: X' m( q
  9. }
    ( [$ ^! b+ @7 j9 _
  10. 8 G2 X; i3 P: ?% n9 _
  11. namespace animal\cat;
    & U) j) C- Y1 ?/ P& V4 r* ?1 c* J( _

  12. * V5 \! E6 J4 ?6 e' n; W
  13. class Life{6 M; H. u9 y9 A( T
  14.     function __construct(){' J' M' e0 E! z% N# Y8 U' h9 r
  15.             echo 'cat life!';1 Y" p8 k3 ]  h: L0 U
  16.         }
    & S( R/ F; E' f6 U3 G
  17. }
    ! J# m, y: X: {! t  @
  18. : ?2 S4 }7 y4 R. C6 \( i# D
  19. use animal\dog\Life as dog;  % d$ u5 O/ Y2 T
  20. new dog();
复制代码
  n: V9 C9 }* c) X0 d7 s
如上所示,use后加上类名后,就相当于把类改了个名称:由Life改为dog了。
上面不用as dog就会报错:
  1. Fatal error:  Cannot use animal\dog\Life as Life because the name is already in use
复制代码

8 }8 a; }) {: S* B  i/ a
因为cat下也有个一样名称的Life类。
可以理解为,使用use后,这个昵称对应的类只能归当前命名空间占有,其它命名空间下不允许存在该类。
  1. //name.php
    8 }4 k' _- O/ [: p/ C
  2. 5 y7 b* \6 X+ I& X' Y
  3. namespace animal\dog;
    $ _# J) n2 l- _" y8 g

  4. + p2 q2 y, j) x  x. a
  5. class Life{
    % e3 d- y. W- T+ z# X# {
  6.     function __construct(){
    4 Q9 ^/ b( ~* O0 \' E! I6 |
  7.             echo 'dog life!';9 ]+ @( h9 @8 v  P1 Y, X
  8.         }
    6 _  ]' f( o$ p& o3 |( d
  9. }
    , s$ M" g) c4 w2 w/ X
  10. class Dog{2 N* m/ Z3 ^# m
  11.     function __construct(){
    / w' w4 E/ g1 `$ [( R+ R
  12.             echo 'dog in dog!';( Z3 ^7 u& g: i% F# v) J% Q8 g
  13.         }, c' R3 ]( c: G4 O+ o( b$ V
  14. }
    * Z3 G9 b) U- N( K7 p+ v$ }

  15. ' Q; G3 q) M( A& I# d4 i; m
  16. namespace animal\cat;
    : m( X6 m; D) v4 g( W3 x

  17. # _- k9 `9 S; @5 D
  18. // class Dog{
    / J* W! d7 C! ^/ g, ?8 a$ T( |- ]  q
  19. //     function __construct(){+ G' G& d' A) `& V) f7 l' w5 ]
  20. //             echo 'dog in cat!';
    , i! P  Z* L1 S0 B5 n6 Z
  21. //         }' f5 L2 l- g4 _% p# ?
  22. // }9 h3 H# D; f1 u/ I" r2 U
  23. class Life{
    5 V. t9 b( H& T6 e
  24.     function __construct(){
    7 {+ e" Q4 o) ^) t" w
  25.             echo 'cat life!';
    2 z! \' V! N& _) {/ G' g  G: k8 _8 H
  26.         }/ Z) b; D6 p# X& r3 i
  27. }
    : D( |: L8 l! |2 f+ Z

  28. . M9 i1 b: p, A" e2 o% Y2 a2 ^8 b
  29. use animal\dog;  
    ! Q! ^4 z2 Q9 B6 b1 k  b0 W
  30. new dog\Dog();
复制代码

2 u8 c2 A- @" f1 o: n9 V4 e4 ]8 V. N
如上,使用了
  1. use animal\dog;
复制代码

6 C3 g0 [6 [, j7 S6 w
cat
通过上面代码,我想使用use的目的效果(缩短命名空间名称)就很明显了。
( ?2 q. y# |  R& p' w. r
简单总结一下:
namespace就是划分领域的作用,代表这些东西是属于某个命名空间下的。
use就是起小名的作用,不论写起来还是说起来都可以省不少事儿。

: z4 l( Q  |: W8 k5 Q0 {4 {# T
: a" f" \! t2 t1 `' X( `1 @3 {
5 f4 v4 j0 m( }" w# u: W1 H8 }+ j  D8 r

( N% q' m. C7 B
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-1-30 11:34 , Processed in 0.056865 second(s), 22 queries .

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