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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 12380|回复: 0

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

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

) [7 C' I# _6 u' R. m( V
文章大纲:
使用namespace的目的
namespace的使用方法
使用use的目的
use的使用方法

8 ?  L7 e% N% X" |( x: |( N. F
7 v" N4 K/ F' S: `使用namespace的目的:
团队合作项目时,避免与团队其它成员新建的类发生冲突;个人负责项目时,避免前后新建的类发生冲突;
4 l& j# E1 Q7 ?! `
据个人理解,用到所需要的类时,需要先require或include引入,所以会发生类重定义的错误的前提是:两个相同命名的类都有被引入。目前有些php框架会自动加载(即include)所有新建的model类,所以为了避免你新建的model类和项目框架原生的核心类发生重名冲突,采用了namespace。(想了想,与团队成员新建的类产生冲突应该通过沟通避免,即使事发后也应该重新调整类名即时维护,避免后期造成因为对类的理解混淆而带来维护上的复杂度提高)

! z. r9 F  i! _, ^9 r9 V2 m& }结合使用方法来进一步理解它的使用目的吧。

& D2 b% I. G5 g7 w3 s
, }/ q3 w& X) e4 anamespace的使用方法:
为了进行测试,我将创建3个文件:1.php和name.php(此文件用来执行测试),后面将不再说明,请自行注意代码的变化。
1.namespace后命名的定义不区分大小写
  1. namespace one;$ b5 j) P. a5 I) P  [9 B
  2. namespace One;, ]% a  j* {; x; D
  3. namespace ONE;
复制代码

  c1 y# {3 r$ c$ V
如上写法都可以,选择一种作为自己的规范即可。(后面代码我采用第一种进行测试哈)
$ k% ]) }' w5 U2 m
2. 没有定义命名空间,就理解为使用顶级命名空间。new类时,可以在类前加上反斜杠\,也可以不加。
  1. //1.php   
    4 ?' l$ l; x; M: S" R. ~+ K
  2. class Person{: k! F" V1 k( v: p
  3.     function __construct(){6 x/ w. t; \8 e2 ^
  4.             echo 'I am one!';
    ! ~, z3 b" Q. |5 V$ c1 C
  5.         }
    ; l/ Y# O" s2 U# b- H& A! b2 i  i
  6. }
复制代码
  1. //name.php2 S- ~# \! a5 ^# ?5 v* ?/ U
  2. require_once './1.php';# H( u3 P$ a; ]: w8 k$ u0 d

  3. ( ~+ H% @) t( E! }7 `6 ]& n( V4 J
  4. new Person();     //输出 I am one!;
    9 x# F$ W' c- ~; u$ b8 E
  5. new \Person(); //输出 I am one!;
复制代码
0 Z3 p; S) J7 Y. ?
3. new类时,带上命名空间时,之间一定用反斜杠字符,而不是顺斜杠。
记忆方法:按找%中斜杠的顺序理解为顺斜杠。(有时说反斜杠,自己都不知道是哪种方向,以前按自左向右上升方向这种方向记忆,现在感觉这个太不靠谱了)
  1. //name.php- I2 I' p4 \  w5 k  F+ q
  2. require_once './1.php';
    * y. c, o3 C- u- N' O
  3. new /Person();  // 代码报错:Parse error: syntax error, unexpected '/'
复制代码
/ }0 @/ _, `4 h! n5 ^+ H- q0 x
4.类在指定命名空间下, new类时,一定要带上指定的命名空间。
没有带上指定的命名空间,按照第2点,php就会从顶级命名空间里找这个类。切记:这里不能按照顶级命名空间包含一切其它的命名空间来理解。而应该将顶级命名空间完完全全与其他命名空间区分开。
  1. //1.php   
    7 J% i" ?, A: A2 ^+ h
  2. namespace one;
    $ }8 t4 v- h- g+ M+ m
  3. class Person{, M( p. ^  q4 A7 x8 y1 l
  4.     function __construct(){" R/ H3 G( N( |7 U' ~, K
  5.             echo 'I am one!';
    " t, g2 I. q) M- O$ J: P
  6.         }/ c- M3 G5 d3 s$ v( ^9 K" g8 e
  7. }
复制代码
  1. //name.php
    " c8 c- o/ ~( O3 K* r, f
  2. require_once './1.php';
    % X8 }1 r( s; o" H
  3. new \one\Person(); //输出 I am one!;+ }; o) V. w% ?" Q( ]% u3 i1 p
  4. new \Person(); //代码报错:Fatal error: Class 'Person' not found
复制代码

5 L" d& J! T, P3 X5 B7 C. V* o
可以举个这个通俗例子来理解:带上指定命名空间代表某人的苹果(在他手里),顶级命名空间代表苹果箱里的苹果(在箱子里)。现在要找某人的苹果,就将某人的命名空间带上,否则就会从箱子里找某人的苹果,结果当然是找不到。

' L* {7 ?6 i: `) ^3 _/ M5.命名空间声明后的代码便属于这个命名空间,即使有include或require也不影响(重点是对后半句的理解,具体看代码)。6 v5 ?6 m4 Y" t8 O: t; j& R
  1. //1.php   
    9 A6 R" f; p2 v, N4 i) i" z
  2. namespace one;
    $ M3 V/ r# F4 a4 l1 `
  3. class Person{
    : u3 E) t+ r) H; p' u7 K; o! z9 Z
  4.     function __construct(){
    / v$ ]2 x8 N% Z3 H8 h( R3 Q; q- N' {
  5.             echo 'I am one!';0 S$ s# ~  J" y0 a* \7 e2 t
  6.         }; \2 k: }+ [4 V& ^* a; z
  7. }
复制代码
  1. //name.php
    3 ?: ^5 S" Q7 u' w, H: F
  2. namespace test;& v  |4 a! R0 r
  3. require './1.php';
    ; q' }5 w7 T9 h
  4. new \one\Person(); //输出 I am one!;
    ; w' Y* @0 a5 G6 [0 j" Y
  5. new Person();      //这里结果会是什么呢,猜猜看  |8 a# G  R, d4 E
  6. 最后一行结果报错:
    ( `0 O# g8 x+ {- w
  7. Fatal error:  Class 'test\Person' not found
复制代码

: @; ~$ w( _2 g# _- E" ~7 X  f! o3 ]
+ W8 c3 b8 o# p3 V3 F* z5 O4 h0 f: b
首先,这里与第2点比较一下:
第2点,我说,没有命名空间时,new类时,有没有反斜杠意义一样。
在这里,有了命名空间,有和没有反斜杠的意义就不一样了。
最后一行换成
  1. new \Person();
复制代码

( f0 ~9 Q2 |. a: z% z$ q
结果报错:
  1. Fatal error:  Class 'Person' not found
复制代码

+ ~7 [/ H3 V4 o0 T5 m
接着,就说说当前这点。
我们可以发现,最后一行代码对应的命名空间为test,并没有受到require文件里的命名空间的影响。
进一步加强验证,我修改了name.php文件如下:
  1. //name.php
    7 X/ z2 A1 d  d- Z% I) N% a: E
  2. namespace test;
    ) R$ `3 m# R. h8 H) m* p2 f/ n7 Y8 L
  3. require './1.php'; $ j0 Z# N* v# U
  4. ; L3 t" [% i" T0 T8 j. E
  5. class Person{
    % k' c: X* ?# r3 Q" V& u; k
  6.     function __construct(){2 D5 `3 o0 ~. ^/ s
  7.             echo 'I am test!';5 Y& y, O5 _6 v  b
  8.         }
    1 N! n  h4 P/ H
  9. }
    9 {8 E" u/ z& ?, w$ X  }

  10. 9 Z8 o& j' l3 o# y! N
  11. new \one\Person(); //输出 I am one!;) P/ ?) m. b  t/ W! S$ @2 Y: q
  12. new Person();    //这里结果会是什么,自己猜猜看
复制代码
1 }# }) }) i# Z5 J5 R
最后,这个例子刷新了我对require的认识了。
按照我以前对require的理解:PHP 程序在执行前,就会先读入 require 所指定引入的文件,使它变成 PHP 程序网页的一部分。所以我常常就简单的理解为替换,只不过把抽离出来的代码再放回原处而已。然后我试了将1.php文件内容放到name.php里:
  1. //name.php, ]0 ^9 c0 }( `/ u
  2. namespace test;
    : U1 N5 v  m5 ~- m
  3. namespace one;
    ' Q! }) O% g6 L+ d) d/ L# u+ S+ R
  4. class Person{
    ( g4 N! [- T; L* h- W1 l4 k  c1 B" A
  5.     function __construct(){) L& C1 f& `4 ^0 @0 ?9 o) [( ^
  6.             echo 'I am one!';) [( L/ B2 \' U2 m# `+ y1 {9 s3 b
  7.         }2 x$ _+ W  M& Z9 T# n8 a* D
  8. }
    & N" ^2 r2 ^* r1 X8 S$ }5 s* B
  9. ) V2 I3 n0 s, ]" [0 {  ^
  10. class Person{
    4 |. c; b  B4 {& I- R# |
  11.     function __construct(){$ x9 W  }* F* x" D( ~8 g" ~
  12.             echo 'I am test!';' v# Y% x2 ~. Q1 ]8 o, h) o' @3 k
  13.         }
    " h: L9 Q9 c1 W* O8 u* h
  14. }
复制代码

5 S) m0 A7 c; L0 Q' R
无需new类,该文件就会报错:
  1. Fatal error:  Cannot redeclare class one\Person
复制代码
% c, |9 @% Q; q- `8 `9 O
看来简单的把require理解为替换,在这里行不通。

9 V$ ?1 e" k+ \0 `6.namespace里不包含类名称,即使存在与类名称同名的部分,那也不代表类。new类时,还是得将这部分带上。" M9 D6 @; W: @- h! w* g$ @7 L/ t9 M
  1. //name.php
    1 w; o- K+ G5 w0 ?' ~/ V& \+ r
  2. " V, Y& d5 Y) e  l* }
  3. namespace test\person;' O! H9 N+ J- A- W/ o$ A0 ?

  4. ! n# g& N1 t4 u; \5 h2 h: z- n
  5. class Person{
    0 _! q7 W+ o0 f
  6.     function __construct(){
    7 @8 ~* Y, s' C. S. Q' m
  7.             echo 'I am test!';! K2 c  Y+ g- }9 ?8 [
  8.         }$ ]5 }" _4 Y0 ?4 R6 K
  9. }, P3 K  @2 w# P5 y( ^) x
  10. new \test\person\Person();  //命名空间里person无法代表类名
复制代码
& |5 r" z# N- z: @; [
不过这样纯粹是画蛇添足,直接干脆点,namespace里不要带类名称就好。

  w, v4 U2 F+ g0 E7 {" W( w7.一个php文件中可以存在多个命名空间,第一个命名空间前不能有任何代码。
只说第一个命名空间前不能有任何代码,之后的命名空间之前可以有代码。这个自行测试即可。
  1. //name.php# `; {! q" ^) o8 u& p" h3 a

  2. ! [" p/ @3 Z- T5 O% d
  3. namespace test;
    9 r% I9 Y) Q+ a6 H( C. k
  4. echo 'zhai14';
    2 x' t) p8 G8 ?1 O* y
  5. namespace zhai;
    5 |, E. O4 ^8 X$ n8 @
  6. require './1.php';
复制代码

1 o0 z' A. v# h- H
php命名空间namespace告一段落了,接下来说说use的用途。
使用use的目的:
在命名空间字符串过长时,使用use可以相应的缩短命名空间。

9 b' {+ n1 h5 Wuse的使用方法:1.new类时,最前面无需用反斜杠。此外,use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。$ M1 n; o7 ~9 Z3 x
  1. //name.php, n4 O+ p! P8 x  p. M) c, Y3 H
  2. * D+ \7 I- k( G2 G# `# S
  3. namespace animal\dog;1 g3 o. Y4 k/ B2 S7 T

  4. 9 T5 n- |. b1 z/ o" M/ c$ q
  5. class Life{
    + U4 y/ S+ t: |4 }8 Y! |0 l
  6.     function __construct(){
    ) z0 G9 z( A+ g
  7.             echo 'dog life!';
    5 v9 m# F; z- |$ [! i. }
  8.         }
    # d* z- M4 @' y2 J+ |
  9. }
    ( W# F7 P* g( f) n. x8 O) q
  10. : j! A% B( w4 ^, D! ?. |( x
  11. namespace animal\cat;0 L/ I9 ~; M  C& l1 W. A7 I4 F  g
  12. $ w; f& N7 @# W4 z6 @3 l, \
  13. class Life{; R8 p: \( Y6 h  I# l
  14.     function __construct(){
    , R, `( B& B9 [0 c
  15.             echo 'cat life!';( A- X' q0 g+ m; @
  16.         }6 ~: ~) U/ A' W/ u
  17. }
    / a* m, X6 U) U9 v, `. S8 o7 }6 t
  18. 0 }; {2 B! [3 p: Q0 K" b
  19. new Life();  //按照代码执行顺序,这里默认animal\cat这个命名空间1 _2 g  R4 H' m7 U+ z! I
  20. new \animal\dog\Life();  //A6 {3 w$ a5 g% d) Q! V( d2 e

  21. 8 s2 B1 P) H6 `/ D& N6 ~7 G
  22. use animal\dog;  //a- _$ I( s. R8 p9 i- k
  23. new dog\Life();  //B/ l" N4 E8 U+ A2 g
  24. 4 b4 Z' J7 f; b/ S, H0 c8 o) a) [
  25. use animal\dog as d;  //b
    , J- J- m; ^4 C; N
  26. new d\Life();
复制代码
9 c. Q, [, M# J+ o# L2 _  h
通过A、B行代码比较,需要注意:
使用use后,new类时,最前面没有反斜杠。
没使用use时,命名空间最前面有反斜杠

- [7 I# y" K# D: j$ s3 ~- [- |4 k3 d
通过a、b行代码比较,可以理解:
use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。如上的:
  1. use animal\dog;
复制代码

5 x4 W, F  X" E$ z* C% M* L
相当于
  1. use animal\dog as dog;
复制代码

4 x( w% E3 Z: E% H! V+ J2.namespace后面不建议加类名,但use后可以。
3 O* k4 n" |/ ~
  1. //name.php
    # q5 [6 k% A" @' D! e
  2. 6 E' Y% g; V$ _3 h5 ]: X
  3. namespace animal\dog;* A& E3 Q# L" Z2 }, j* m! f
  4.   e8 f5 e6 T0 N1 w. A+ J3 J5 l
  5. class Life{, m) O$ K# t# B5 h2 v* P
  6.     function __construct(){
    ( i, M) o4 T6 k
  7.             echo 'dog life!';
    & ~8 d1 Y& U2 i: ]3 v. b
  8.         }
    . s, O( \& S; e- g
  9. }5 d7 }$ y/ u" i0 g+ t+ @" a. L
  10. 3 q4 I" O4 k# ?7 O1 L) r
  11. namespace animal\cat;; O: W) n: Z$ x) t0 s. m+ ?7 D
  12. ' e) @+ c0 |* ]; s1 Q
  13. class Life{
    0 r5 E7 f! K0 N3 }
  14.     function __construct(){
    9 {. I: g  M& r. I: K& {* q) V3 |
  15.             echo 'cat life!';6 l" j" {7 {' V5 O1 [
  16.         }" }& h. g! g& D4 o4 v# I6 R
  17. }3 ~$ Z' o1 q( f5 U
  18. 6 E4 e* r, V/ r4 J
  19. use animal\dog\Life as dog;  
    % e2 P) l! {9 b% q
  20. new dog();
复制代码
$ B* f% @5 W0 L1 v8 z5 B: W
如上所示,use后加上类名后,就相当于把类改了个名称:由Life改为dog了。
上面不用as dog就会报错:
  1. Fatal error:  Cannot use animal\dog\Life as Life because the name is already in use
复制代码
& a- \2 E  E* s( t0 r2 {
因为cat下也有个一样名称的Life类。
可以理解为,使用use后,这个昵称对应的类只能归当前命名空间占有,其它命名空间下不允许存在该类。
  1. //name.php( L! ^! G/ J5 T* d8 B

  2. 3 m8 U  p7 f2 Q- c3 r) f; x
  3. namespace animal\dog;
    / i9 D7 [1 n5 @6 V3 i
  4. & n; I3 F1 e. i0 X$ S, u
  5. class Life{
    3 ]! _; u( K4 `! P
  6.     function __construct(){! C! s4 l4 W0 q8 Q$ k( T
  7.             echo 'dog life!';+ ^# X. v  _% e3 z! y% {2 H5 }
  8.         }; A  [5 a) n3 R; G' u. m+ c& g4 `- t
  9. }
    + ^; P# l! B9 `% ^$ B4 I. @  q
  10. class Dog{
    1 {' U3 \# Y$ {$ x: u! W; e
  11.     function __construct(){" \4 K+ s" i7 U* J. C8 B
  12.             echo 'dog in dog!';
    6 ]8 W/ T9 ^5 S2 x# ?7 u6 A
  13.         }
    3 y! R1 E( M% [; r$ b
  14. }# w3 T$ @; t; T  G8 H( y
  15. 8 a9 @) T# ]9 e) t
  16. namespace animal\cat;+ K7 T- K% o' M$ @; B/ C5 C7 `

  17. 6 b, M2 L. k& d, a
  18. // class Dog{
    & w2 B: m& I) G
  19. //     function __construct(){5 s$ O1 l4 n6 Z2 X3 q& L
  20. //             echo 'dog in cat!';
    " B# d) j& M1 e$ X, S
  21. //         }
    % n2 u( b" |. I4 d7 P
  22. // }
    . M( t0 }" |# |0 A$ ], \2 D
  23. class Life{
    % C( V, T" ^$ H0 x9 R
  24.     function __construct(){
    3 h, n' k0 a; R! P
  25.             echo 'cat life!';7 J6 b: j4 @0 {. b% n" Y6 h# Q
  26.         }
    4 u. Y0 Y! i* k- r7 i
  27. }
    ' T# x, J5 a) ~% H8 o6 _

  28. - J6 F; N( F, W( w0 \
  29. use animal\dog;  1 s! B% z* W1 n4 w
  30. new dog\Dog();
复制代码

9 g" f8 r2 q. w7 ~. c4 v
如上,使用了
  1. use animal\dog;
复制代码

8 i) r( k* f; K0 ]& {
cat
通过上面代码,我想使用use的目的效果(缩短命名空间名称)就很明显了。

  h% Z( w. }: J
简单总结一下:
namespace就是划分领域的作用,代表这些东西是属于某个命名空间下的。
use就是起小名的作用,不论写起来还是说起来都可以省不少事儿。
, N- N1 I$ O! r- U2 h2 i' k

& g+ q3 \4 s% i7 O* |& F, ?! `- Y4 l7 G: j1 x2 B
0 F  `( l' q+ \+ ~) |" u
8 D* L8 K: i+ U& H  P! U
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2025-2-11 22:19 , Processed in 0.123218 second(s), 20 queries .

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