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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 10142|回复: 0

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

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

/ l& a" A! o( T/ Q7 Y0 t$ y
文章大纲:
使用namespace的目的
namespace的使用方法
使用use的目的
use的使用方法
, s9 R! C( P, u

1 G8 o2 \, Z+ }. C% V使用namespace的目的:
团队合作项目时,避免与团队其它成员新建的类发生冲突;个人负责项目时,避免前后新建的类发生冲突;
! D, y* V6 M0 l- r& t
据个人理解,用到所需要的类时,需要先require或include引入,所以会发生类重定义的错误的前提是:两个相同命名的类都有被引入。目前有些php框架会自动加载(即include)所有新建的model类,所以为了避免你新建的model类和项目框架原生的核心类发生重名冲突,采用了namespace。(想了想,与团队成员新建的类产生冲突应该通过沟通避免,即使事发后也应该重新调整类名即时维护,避免后期造成因为对类的理解混淆而带来维护上的复杂度提高)

6 b# n, k  ?6 i6 r; ~# t结合使用方法来进一步理解它的使用目的吧。

- |5 V* {0 V6 y( ?2 K& C, z9 H- J: T6 B0 r% }
namespace的使用方法:
为了进行测试,我将创建3个文件:1.php和name.php(此文件用来执行测试),后面将不再说明,请自行注意代码的变化。
1.namespace后命名的定义不区分大小写
  1. namespace one;
    3 u$ L- j% u+ L  l+ S! X/ E
  2. namespace One;
    # t  G% ^& W8 j2 q9 C! z$ q
  3. namespace ONE;
复制代码
, k: @6 H! q0 ^" ~+ _* D9 ^2 c) j
如上写法都可以,选择一种作为自己的规范即可。(后面代码我采用第一种进行测试哈)
, [4 l& V% g$ `9 ?
2. 没有定义命名空间,就理解为使用顶级命名空间。new类时,可以在类前加上反斜杠\,也可以不加。
  1. //1.php   $ Q8 O3 t( Y" C! N- l
  2. class Person{
    ; {' W0 v- o$ U: m1 p/ }
  3.     function __construct(){. ]2 J3 h- s4 v7 x/ a. D
  4.             echo 'I am one!';
      ?7 e& v: H0 E5 l
  5.         }/ p5 Y% t) J, Z1 x' S- z
  6. }
复制代码
  1. //name.php+ y  H+ n' C; m( V7 M% c3 v
  2. require_once './1.php';' h" A0 }5 ~- [* r1 R

  3. * I: U5 B, ~, X7 _" z+ V
  4. new Person();     //输出 I am one!;3 x  ~' B! [0 E7 U( Q7 M) o
  5. new \Person(); //输出 I am one!;
复制代码
* b0 U6 z- ]* g6 p
3. new类时,带上命名空间时,之间一定用反斜杠字符,而不是顺斜杠。
记忆方法:按找%中斜杠的顺序理解为顺斜杠。(有时说反斜杠,自己都不知道是哪种方向,以前按自左向右上升方向这种方向记忆,现在感觉这个太不靠谱了)
  1. //name.php3 K; }, y. a6 S0 k; y
  2. require_once './1.php';4 u5 b. Z( b( Q3 p7 A- H
  3. new /Person();  // 代码报错:Parse error: syntax error, unexpected '/'
复制代码
8 L( Q. [8 O3 E2 n
4.类在指定命名空间下, new类时,一定要带上指定的命名空间。
没有带上指定的命名空间,按照第2点,php就会从顶级命名空间里找这个类。切记:这里不能按照顶级命名空间包含一切其它的命名空间来理解。而应该将顶级命名空间完完全全与其他命名空间区分开。
  1. //1.php   
    4 e  W: u  U5 J, v
  2. namespace one;
    $ e5 Q0 K* f6 D
  3. class Person{: b7 o# i7 [, z3 }. I* ?
  4.     function __construct(){
    ( c" f  x7 d6 v$ Y
  5.             echo 'I am one!';3 i: @2 o% q& d
  6.         }: C1 d: c6 ^- H. R( s
  7. }
复制代码
  1. //name.php2 o& ?, K$ j# C4 z: n4 I
  2. require_once './1.php';1 u3 c3 F& K5 T
  3. new \one\Person(); //输出 I am one!;5 A* s% w+ R: w. O
  4. new \Person(); //代码报错:Fatal error: Class 'Person' not found
复制代码
4 e4 {4 u+ t" E
可以举个这个通俗例子来理解:带上指定命名空间代表某人的苹果(在他手里),顶级命名空间代表苹果箱里的苹果(在箱子里)。现在要找某人的苹果,就将某人的命名空间带上,否则就会从箱子里找某人的苹果,结果当然是找不到。
& m' i- a. i) I# @
5.命名空间声明后的代码便属于这个命名空间,即使有include或require也不影响(重点是对后半句的理解,具体看代码)。$ t! f0 T2 Q) q7 t2 \$ ^
  1. //1.php   $ Q" g6 z2 O1 L# b4 F! |' B
  2. namespace one;+ A$ i( Q4 Q* b1 ?$ B
  3. class Person{/ Q+ N5 s4 ?0 L. [3 S1 E! K1 Q) P- f
  4.     function __construct(){
    ; m3 ~$ }* v1 v
  5.             echo 'I am one!';
    8 l% U1 O# F' f7 T; |
  6.         }9 I5 Q8 O; H7 E1 i
  7. }
复制代码
  1. //name.php$ s. }+ l7 `- I
  2. namespace test;$ q. @; k: ~# p! q, b9 y& z* g
  3. require './1.php'; 2 V+ f  o2 [& a# t4 Z& [- g
  4. new \one\Person(); //输出 I am one!;
    ' }  m- x7 I+ w
  5. new Person();      //这里结果会是什么呢,猜猜看
    0 h* Y+ R9 ]. k
  6. 最后一行结果报错:6 [: j6 G" G) I
  7. Fatal error:  Class 'test\Person' not found
复制代码
/ {2 b% \3 N4 ~( O4 K; z. Q* ^
, G* B! l2 N  x/ u2 v
首先,这里与第2点比较一下:
第2点,我说,没有命名空间时,new类时,有没有反斜杠意义一样。
在这里,有了命名空间,有和没有反斜杠的意义就不一样了。
最后一行换成
  1. new \Person();
复制代码

$ b& w- `; l; H/ Q0 P
结果报错:
  1. Fatal error:  Class 'Person' not found
复制代码

; n+ o, W' t- e" [& d7 Y
接着,就说说当前这点。
我们可以发现,最后一行代码对应的命名空间为test,并没有受到require文件里的命名空间的影响。
进一步加强验证,我修改了name.php文件如下:
  1. //name.php! J9 x- ]4 J3 t( s
  2. namespace test;
    8 K$ e! F' z% \9 w5 Z) L
  3. require './1.php';
    : f: u- V1 K% g. R! f) D

  4. 6 k% C  ~, r- B3 B) i! ~3 T8 {
  5. class Person{
    8 F. p5 R$ \9 ?# K
  6.     function __construct(){
    % |# G) y  j7 ]* @+ B7 V1 B. _
  7.             echo 'I am test!';' k+ |. N3 R# g8 ]
  8.         }
    7 m) }- \0 q. d. F0 ^! J+ C
  9. }) Y/ y" U8 j& Z5 z

  10. : Z# V5 y1 F9 Y" B& ]
  11. new \one\Person(); //输出 I am one!;' D2 V, X) |# v
  12. new Person();    //这里结果会是什么,自己猜猜看
复制代码
7 S! y+ L8 w1 m( O8 |) d
最后,这个例子刷新了我对require的认识了。
按照我以前对require的理解:PHP 程序在执行前,就会先读入 require 所指定引入的文件,使它变成 PHP 程序网页的一部分。所以我常常就简单的理解为替换,只不过把抽离出来的代码再放回原处而已。然后我试了将1.php文件内容放到name.php里:
  1. //name.php
    " ~+ Y" ^6 _, U' j! m
  2. namespace test;: H+ _5 j* A# Y& c8 B; A
  3. namespace one;
    6 |5 ~" b& I* Q" R
  4. class Person{; r) }1 r& t8 M5 i
  5.     function __construct(){# U" A" v, q& \
  6.             echo 'I am one!';3 g! h0 n+ f: H+ c9 q- d
  7.         }/ X& `2 ^5 n( y% |
  8. }
    4 c5 o: E1 @6 i" K

  9.   p  U% E" W; [/ Y* D" ]5 |
  10. class Person{8 p7 H/ h7 E2 C6 ?
  11.     function __construct(){
    3 j- k# q! w, ?- y
  12.             echo 'I am test!';4 v& G9 O) Z7 r; r
  13.         }
    1 c7 o' P* ~4 J# @
  14. }
复制代码
4 E3 q7 O8 p% q/ T( m* i/ @
无需new类,该文件就会报错:
  1. Fatal error:  Cannot redeclare class one\Person
复制代码
* J( ^6 c* ]1 G+ o$ l  t; h5 ~! [5 n
看来简单的把require理解为替换,在这里行不通。

9 r2 U# G4 E7 ]9 J, m- T6.namespace里不包含类名称,即使存在与类名称同名的部分,那也不代表类。new类时,还是得将这部分带上。
" v5 Y$ v5 T( W% N5 j
  1. //name.php2 R1 ~$ G4 k- T% b* q- E
  2. , n" t& @' q- e3 ]9 f% T
  3. namespace test\person;! E* m4 p* E& g) L! ?

  4. ) A+ }& n6 R4 t6 \
  5. class Person{
    ; t6 h+ r, o; u3 u8 H( k
  6.     function __construct(){
    / y% I( n& r; O. s/ s& P; v8 c& O
  7.             echo 'I am test!';3 X6 M; g: G0 H" C1 I* h
  8.         }
    6 G# _% S7 Y( l" k! T$ r
  9. }
    ; k  B6 F5 Z) R/ j
  10. new \test\person\Person();  //命名空间里person无法代表类名
复制代码

3 w1 _3 P/ r4 c) h
不过这样纯粹是画蛇添足,直接干脆点,namespace里不要带类名称就好。

7 N' l- A8 O" u- W7 y7.一个php文件中可以存在多个命名空间,第一个命名空间前不能有任何代码。
只说第一个命名空间前不能有任何代码,之后的命名空间之前可以有代码。这个自行测试即可。
  1. //name.php  w' Z, `' K# c9 t2 h
  2. ) S# D4 D9 `- G. w7 l, f# {
  3. namespace test;
    + O; O) Y) W* B0 I) e
  4. echo 'zhai14';
    5 K! F) x0 q( W" b
  5. namespace zhai;3 r" k# g" R0 ?! }; G+ k
  6. require './1.php';
复制代码
& k0 }+ T  h9 q, E, R% N& p
php命名空间namespace告一段落了,接下来说说use的用途。
使用use的目的:
在命名空间字符串过长时,使用use可以相应的缩短命名空间。

" `% y- V' p  C# s/ k2 iuse的使用方法:1.new类时,最前面无需用反斜杠。此外,use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。0 v' m% Z3 d" j: q8 I+ S: O
  1. //name.php
    % n: k9 X; O8 }7 u8 q

  2. ! r$ I! A* g/ n. k  j( h2 q
  3. namespace animal\dog;; g$ I4 K, O, L0 Z; L, h
  4. : V7 l: [, Z) n/ L& A$ g6 L/ @* T
  5. class Life{
    # _( Z! Y% K, H
  6.     function __construct(){
    / L' e( K2 h: o: h! ~# }7 z
  7.             echo 'dog life!';
    % L- D/ [8 e9 o
  8.         }2 _! E* s% h4 z- F/ g7 d: o* m1 z
  9. }1 R; M  P0 Z- v5 N) N4 x
  10. : L$ [) N9 D0 @9 l9 }1 I' |: A
  11. namespace animal\cat;
    : n3 u+ K& e0 @( X1 u7 f( y/ Y

  12. : Y! G9 }* O5 U& D% ]' z
  13. class Life{
    / |3 u- L* g( v5 h( L$ f9 [
  14.     function __construct(){' l2 n' n/ B" r; ^7 w- I* M
  15.             echo 'cat life!';( @( Q( F4 a, E! q8 ^' U
  16.         }3 v- Z9 X$ o+ C; K( {
  17. }
    0 G4 d. t9 b+ |$ i: n  M
  18. 0 v; Y7 D/ q+ B. y' {+ m
  19. new Life();  //按照代码执行顺序,这里默认animal\cat这个命名空间
    0 q3 O6 ^: y# R( h# y
  20. new \animal\dog\Life();  //A0 ?- b6 U& e+ \* ^" d. P! L

  21. 6 O; H. B  O/ W( f8 `; D
  22. use animal\dog;  //a! t# |3 s% c8 n; d) x% r
  23. new dog\Life();  //B
    % J: y, d% Y. r' b& n
  24. # }$ q: j5 X* T
  25. use animal\dog as d;  //b
    7 o+ j' x: S9 I  g0 u/ K
  26. new d\Life();
复制代码

7 E, J! }0 y) T: C# C0 `
通过A、B行代码比较,需要注意:
使用use后,new类时,最前面没有反斜杠。
没使用use时,命名空间最前面有反斜杠
) C. @/ ^6 X- {* }2 \0 {8 j
通过a、b行代码比较,可以理解:
use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。如上的:
  1. use animal\dog;
复制代码
: f7 E) @" b) D3 o, `$ B8 v
相当于
  1. use animal\dog as dog;
复制代码

  g, j7 u6 d/ u5 i# I4 a5 d/ k# d& d5 G2.namespace后面不建议加类名,但use后可以。; _4 U! r4 P$ P/ D5 I
  1. //name.php/ R! O& `0 L4 w: E% V
  2. ) H8 Q. I7 @- I% e* }! w5 {
  3. namespace animal\dog;
    * R9 \, y8 {! [
  4. + S5 x: h4 ^/ O1 [( r  m, M  }$ h
  5. class Life{( e% F4 G4 ^# W1 o) L
  6.     function __construct(){2 v! |( ]* ~  V) ~& b* ^
  7.             echo 'dog life!';% F# r% m% d* S+ |( p
  8.         }* w: q( ]9 w* }5 n8 v
  9. }
    8 a; `' @, S# T. r3 u. e

  10. " t8 ^5 s6 S5 [; Z3 C5 g
  11. namespace animal\cat;
    & [- @0 s! z+ f- J  i- K# O6 V  P
  12. 7 x9 d# |* C1 ]* J4 c$ V; n
  13. class Life{- t# u6 j. e! A+ `7 P
  14.     function __construct(){
    : y0 z% r) V/ \% U1 U2 d# x
  15.             echo 'cat life!';
    $ _& I$ I) G: c% {# h( |
  16.         }) ]1 V! A5 c3 {  B: n
  17. }
    4 W- ?5 z+ j1 x% `# `

  18. & K; k0 C" b# U4 H3 n# H1 p
  19. use animal\dog\Life as dog;  
    ( s% z3 i0 G2 ~; ]
  20. new dog();
复制代码
! c& w* S( w. J! e
如上所示,use后加上类名后,就相当于把类改了个名称:由Life改为dog了。
上面不用as dog就会报错:
  1. Fatal error:  Cannot use animal\dog\Life as Life because the name is already in use
复制代码
6 O3 a+ i6 y2 T: o& @' I
因为cat下也有个一样名称的Life类。
可以理解为,使用use后,这个昵称对应的类只能归当前命名空间占有,其它命名空间下不允许存在该类。
  1. //name.php' f9 E! i% G( ~- m- J+ e. s
  2. 2 m, A0 }( V1 \7 Y
  3. namespace animal\dog;7 K& H" I6 }( i# W  c/ o! Y

  4. 6 t3 f& ]9 p& h, d% ~3 o
  5. class Life{
    : F% G8 o, V/ ^7 C9 f
  6.     function __construct(){
      J  w  v" o1 a$ B7 E' N
  7.             echo 'dog life!';5 S4 p  `+ O% N5 v( }5 P" x5 q' m
  8.         }7 K" v% C1 C4 {- M  Y
  9. }/ v. `# [4 a9 w9 w# W" L$ x
  10. class Dog{
    2 D" s- b! J. M5 x: P0 ~+ d/ t1 P
  11.     function __construct(){
    + j  \; W# c* A
  12.             echo 'dog in dog!';
    6 w2 @, u4 b9 {/ U7 T2 s/ @5 a7 a1 a
  13.         }8 p9 d- n& ]3 ~7 S
  14. }- t. j* b$ @4 `% q  p& y2 z" k

  15. / Y# w" ?9 c0 T5 z2 h$ R; n
  16. namespace animal\cat;& N& d' q+ B3 I* i$ L+ y  M
  17. 2 ]: ~( q' _; G% l
  18. // class Dog{
    & B9 e% e  n+ d3 R. {
  19. //     function __construct(){+ }/ G( X3 s) k/ Y: l
  20. //             echo 'dog in cat!';. c. ~9 T$ t; \
  21. //         }; @2 j7 R9 Z/ l( @! y% s& \6 H+ Z
  22. // }3 I$ z: @3 x4 L1 \9 q$ z( ]
  23. class Life{
    4 X5 }0 m/ Z" X/ W5 B  H+ T# I
  24.     function __construct(){8 c) M5 Y$ x; n/ l
  25.             echo 'cat life!';3 D! X3 y6 \# G1 q- n) s2 Y6 f& C
  26.         }. v; q; n% h& q- A1 B9 |
  27. }( u9 F* c$ G5 z! i& l5 O
  28. # M: G6 q; r$ t) H4 X! m! _
  29. use animal\dog;  
    8 l, v/ {7 n" F- _( S, Q
  30. new dog\Dog();
复制代码

1 s8 x3 M/ i0 I& J
如上,使用了
  1. use animal\dog;
复制代码

. a" \$ g" D# P
cat
通过上面代码,我想使用use的目的效果(缩短命名空间名称)就很明显了。

" E2 W; L7 J! N' y
简单总结一下:
namespace就是划分领域的作用,代表这些东西是属于某个命名空间下的。
use就是起小名的作用,不论写起来还是说起来都可以省不少事儿。
+ L- l$ N1 Y; C* f( n
# @: z) F1 ~" v( d

: T' |4 R4 j, m" d1 K1 H; N
: Y( m6 V. }0 N) t, ~/ ~2 ]. `! q
2 a6 k( [% }/ h" q1 V
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-7-18 20:03 , Processed in 0.133552 second(s), 20 queries .

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