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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2020-7-1 23:37:46 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
以下皆为本人自我理解内容,如有失误之处,请多多包涵。
3 P; c! p" z3 {& f
文章大纲:
使用namespace的目的
namespace的使用方法
使用use的目的
use的使用方法

- e. ^" `3 a5 Q, K) R: L3 w& G) R0 ?$ V! u4 O) w( h* N/ E
使用namespace的目的:
团队合作项目时,避免与团队其它成员新建的类发生冲突;个人负责项目时,避免前后新建的类发生冲突;

& U7 b6 G/ @1 ?
据个人理解,用到所需要的类时,需要先require或include引入,所以会发生类重定义的错误的前提是:两个相同命名的类都有被引入。目前有些php框架会自动加载(即include)所有新建的model类,所以为了避免你新建的model类和项目框架原生的核心类发生重名冲突,采用了namespace。(想了想,与团队成员新建的类产生冲突应该通过沟通避免,即使事发后也应该重新调整类名即时维护,避免后期造成因为对类的理解混淆而带来维护上的复杂度提高)
% x" }0 J" ?: _2 c) z
结合使用方法来进一步理解它的使用目的吧。
: A  j! d* M; H9 o

9 G& m# R  S7 W+ c1 Fnamespace的使用方法:
为了进行测试,我将创建3个文件:1.php和name.php(此文件用来执行测试),后面将不再说明,请自行注意代码的变化。
1.namespace后命名的定义不区分大小写
  1. namespace one;
    , o' P0 r* N" S2 X
  2. namespace One;
    / {2 W) M, J- e5 ~
  3. namespace ONE;
复制代码
& S% }- z9 O# h  I1 j
如上写法都可以,选择一种作为自己的规范即可。(后面代码我采用第一种进行测试哈)

1 Q, M2 u& J1 _/ P. K2. 没有定义命名空间,就理解为使用顶级命名空间。new类时,可以在类前加上反斜杠\,也可以不加。
  1. //1.php   $ W9 U3 K9 W" ?6 @
  2. class Person{2 y6 @, ]" K: t8 [  h/ Y
  3.     function __construct(){
    2 }! D& A% v0 S
  4.             echo 'I am one!';8 b6 S# ^8 P- B$ Z# z8 f
  5.         }) W6 q- R3 S3 W+ M/ G% p( Z
  6. }
复制代码
  1. //name.php
    ) `7 k1 E6 y; d& [7 A( C
  2. require_once './1.php';0 \2 o5 z/ P7 E: ]1 Z2 r  x
  3. ) U8 d$ L; X6 S- u) X8 a
  4. new Person();     //输出 I am one!;
    * b, F- U% o1 `  w) ~  d- _' z
  5. new \Person(); //输出 I am one!;
复制代码
' f% [; Q6 F% u; x& Z! J3 ~0 Z
3. new类时,带上命名空间时,之间一定用反斜杠字符,而不是顺斜杠。
记忆方法:按找%中斜杠的顺序理解为顺斜杠。(有时说反斜杠,自己都不知道是哪种方向,以前按自左向右上升方向这种方向记忆,现在感觉这个太不靠谱了)
  1. //name.php
    . `6 ~# F* m, h7 v! x6 K, J! U
  2. require_once './1.php';2 t5 G& ]7 j* o" M6 S( @* N% O4 _
  3. new /Person();  // 代码报错:Parse error: syntax error, unexpected '/'
复制代码

7 c' |. `4 y8 ]4 h- c4.类在指定命名空间下, new类时,一定要带上指定的命名空间。
没有带上指定的命名空间,按照第2点,php就会从顶级命名空间里找这个类。切记:这里不能按照顶级命名空间包含一切其它的命名空间来理解。而应该将顶级命名空间完完全全与其他命名空间区分开。
  1. //1.php   - L2 j% z% f% }- C
  2. namespace one;
    8 t  X$ [4 b9 m3 ]
  3. class Person{7 u- ^9 Y+ I" u' z1 X
  4.     function __construct(){
    7 t  Z2 B- m/ P$ U
  5.             echo 'I am one!';! X) K! P- N# V
  6.         }) t+ Q1 h% [' y# J- ?
  7. }
复制代码
  1. //name.php
    4 Y/ ~. ?4 ~# B7 u& c5 A$ x
  2. require_once './1.php';1 u5 a' L. i; I7 T$ Y0 O3 V
  3. new \one\Person(); //输出 I am one!;
    + D8 ], E; Q0 S0 J' K7 g0 i* G9 L
  4. new \Person(); //代码报错:Fatal error: Class 'Person' not found
复制代码

5 j' O2 }( J4 ^6 y" Q0 Y' K+ @
可以举个这个通俗例子来理解:带上指定命名空间代表某人的苹果(在他手里),顶级命名空间代表苹果箱里的苹果(在箱子里)。现在要找某人的苹果,就将某人的命名空间带上,否则就会从箱子里找某人的苹果,结果当然是找不到。

8 s5 s5 X- O5 P" m  }& B, j0 @5.命名空间声明后的代码便属于这个命名空间,即使有include或require也不影响(重点是对后半句的理解,具体看代码)。0 Q/ X( C7 S7 {3 ]0 g6 }4 {
  1. //1.php   
    - l: a5 s1 M6 S& d) B. J; }
  2. namespace one;! k3 R1 F1 H: H4 {$ f: X; q' ?2 T0 o
  3. class Person{
    ) C# l1 S; z: P+ q3 T' W
  4.     function __construct(){3 v; O7 J1 Z* {6 b3 V) P; D0 K/ |
  5.             echo 'I am one!';; r$ @& j; e& M7 \
  6.         }$ t7 j, I' U0 m( v) |  J
  7. }
复制代码
  1. //name.php8 x9 s: ?- |' }! K$ p" Z* E; s
  2. namespace test;
    4 U6 V' ?) P% Z
  3. require './1.php';
    6 `) d0 A# I6 B& Y. u+ }6 p% r$ R
  4. new \one\Person(); //输出 I am one!;. K3 N0 a, |7 r  r6 I! w
  5. new Person();      //这里结果会是什么呢,猜猜看  m9 n; q& T  o" s
  6. 最后一行结果报错:! i9 t1 ]) `" C0 y1 G1 Y9 e: q. X, }
  7. Fatal error:  Class 'test\Person' not found
复制代码

" P7 v/ T+ A, C: Q0 S

9 k1 H6 W' n. n2 T( v- Y首先,这里与第2点比较一下:
第2点,我说,没有命名空间时,new类时,有没有反斜杠意义一样。
在这里,有了命名空间,有和没有反斜杠的意义就不一样了。
最后一行换成
  1. new \Person();
复制代码

  q0 @! _+ K1 H6 `% @5 L7 ?3 U( G
结果报错:
  1. Fatal error:  Class 'Person' not found
复制代码

: m' m8 R' M$ y* t. Q) j
接着,就说说当前这点。
我们可以发现,最后一行代码对应的命名空间为test,并没有受到require文件里的命名空间的影响。
进一步加强验证,我修改了name.php文件如下:
  1. //name.php
    - E/ K- P: T8 Z2 I9 r* l
  2. namespace test;
    ' X$ r& ~" e4 [. e& L+ l" Q
  3. require './1.php'; - D+ `) d8 s& X6 s. C! j6 H/ u

  4. ) m( e: }- T& @& U
  5. class Person{& M: G3 a; X$ a# x2 F: q/ C
  6.     function __construct(){' T0 V8 C, n* w* f' T2 l
  7.             echo 'I am test!';9 l' n5 |, E) I! N8 N4 X: p; V
  8.         }
    . J1 I6 x* Y( z- L
  9. }
    2 @2 {4 Q! s! S0 U6 J( ^% G
  10. 6 {8 ~" j" n+ e- _* w) w" |4 F
  11. new \one\Person(); //输出 I am one!;, d" X" L0 ]9 ~
  12. new Person();    //这里结果会是什么,自己猜猜看
复制代码
& H& S6 k& g# ~) z; n* q0 B
最后,这个例子刷新了我对require的认识了。
按照我以前对require的理解:PHP 程序在执行前,就会先读入 require 所指定引入的文件,使它变成 PHP 程序网页的一部分。所以我常常就简单的理解为替换,只不过把抽离出来的代码再放回原处而已。然后我试了将1.php文件内容放到name.php里:
  1. //name.php
    8 Y' M6 i2 A1 R- ]
  2. namespace test;
    : G/ p; c, d* f
  3. namespace one;( u' Q8 W! E% Z; |- p8 o4 ?
  4. class Person{/ K/ H. \9 \2 |/ }8 ~$ t) U" x
  5.     function __construct(){) O0 Z# c! F4 d' u* O7 q
  6.             echo 'I am one!';1 |" j8 O) y7 n$ e1 a9 [, o
  7.         }9 {3 ^% l! I3 g! T
  8. }
    * V* s* o- h* f9 X) c* s& i1 e

  9. . n0 @. g: j+ g3 r
  10. class Person{( ^6 ?) E7 r! [1 ?6 g" Z8 k
  11.     function __construct(){7 W, j- X; J3 p( B, [, l+ d
  12.             echo 'I am test!';
    & ]( n6 ?  u# d( e1 L! {$ k1 t2 J
  13.         }
    . @  X7 h7 D2 \4 N& }! x
  14. }
复制代码

. w; C6 J5 i+ z2 Q, H% v9 k
无需new类,该文件就会报错:
  1. Fatal error:  Cannot redeclare class one\Person
复制代码

  c( p" w. R  G6 }& W
看来简单的把require理解为替换,在这里行不通。

6 e  q+ K& @' I) i" N6.namespace里不包含类名称,即使存在与类名称同名的部分,那也不代表类。new类时,还是得将这部分带上。
5 B) I/ P! X+ W8 d' K0 Y
  1. //name.php
    3 g7 Z2 m5 k2 l9 O! K1 s7 m' z

  2. 5 s" g2 A2 `( ^
  3. namespace test\person;  s& C  c3 Y. |) J/ P  R
  4. / ~% D) S/ }0 O: _+ |+ a$ k
  5. class Person{
    ) F& |% g0 k& L8 Z4 z( N7 `* O! w
  6.     function __construct(){; s; ]* X3 W: x( O  M
  7.             echo 'I am test!';
    - S) G: C6 z& P! n) w% ?
  8.         }
    9 ?5 t3 Y1 c; F& D9 D1 m
  9. }
    5 M! a9 R( j- j! K1 f
  10. new \test\person\Person();  //命名空间里person无法代表类名
复制代码
9 V3 F* Q1 f. R+ l0 I5 Z
不过这样纯粹是画蛇添足,直接干脆点,namespace里不要带类名称就好。
: m7 v0 ?1 C3 O, r: X3 g; \
7.一个php文件中可以存在多个命名空间,第一个命名空间前不能有任何代码。
只说第一个命名空间前不能有任何代码,之后的命名空间之前可以有代码。这个自行测试即可。
  1. //name.php1 d( r* W0 |0 M: R2 Z
  2. 6 x" ~8 B1 j( I0 ~% Y& h" O! w5 W' O
  3. namespace test;) t! J! W0 _, T$ Z2 G0 V. q" F
  4. echo 'zhai14';5 w5 T# \' J# K0 o2 y$ }- W
  5. namespace zhai;7 `+ x# F9 x( x' Z0 i( F
  6. require './1.php';
复制代码

4 H2 r  ?9 W7 B; l. X) _
php命名空间namespace告一段落了,接下来说说use的用途。
使用use的目的:
在命名空间字符串过长时,使用use可以相应的缩短命名空间。
: |8 n& i0 J# s7 T) L+ v
use的使用方法:1.new类时,最前面无需用反斜杠。此外,use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。
& x8 E8 i5 A5 l, D/ d3 V# o: F
  1. //name.php
    & Q; `, A" r5 w  h) U/ J
  2. + N- J5 R8 `2 Z9 q& q4 ^  |& M0 A
  3. namespace animal\dog;
    , ^+ |+ S& A( Y& Z3 ]. h

  4. ( t: a  M, Z" H( \. j2 j5 |
  5. class Life{
    0 q' y. e0 D: ~3 [+ G8 P0 Q
  6.     function __construct(){' A9 [: _& `8 a: H, e* K* L, F
  7.             echo 'dog life!';1 M/ Z4 A6 h) n9 D
  8.         }  S; x# u& ]: D$ n
  9. }
    " \) {3 M' m5 g2 C& U6 k4 M
  10. 0 ~, x' {. u  ?: @# k" K
  11. namespace animal\cat;
    6 W5 N$ P' d) s
  12. 8 N2 s5 V& A7 J$ A2 e
  13. class Life{* i6 U" C9 \7 t5 F- r0 |
  14.     function __construct(){  |( T# f7 W4 h* ~* v! k& z7 J" p
  15.             echo 'cat life!';
    . x2 ?  a" n) b1 K
  16.         }* `/ p" c9 d- G) G8 \
  17. }
    4 }' G4 L* z9 U4 k9 k- g6 E

  18. ( x6 T) i0 Q. q0 N3 o
  19. new Life();  //按照代码执行顺序,这里默认animal\cat这个命名空间
    6 k$ A9 T5 {; u( C9 K- t' C
  20. new \animal\dog\Life();  //A
    8 t" z4 J$ t! k* d/ k+ F

  21. . i8 \' P4 S5 Y$ O1 t
  22. use animal\dog;  //a
      r6 n1 K% s+ c5 S' d
  23. new dog\Life();  //B% D3 |/ I  C7 p7 {$ l5 f) _
  24. $ L9 N3 S8 V; J+ P3 X+ }* a( {
  25. use animal\dog as d;  //b
    ) n+ C; A& {+ F( @1 X
  26. new d\Life();
复制代码
1 s) y( D, R+ T& J5 s6 T$ H* i& c# U
通过A、B行代码比较,需要注意:
使用use后,new类时,最前面没有反斜杠。
没使用use时,命名空间最前面有反斜杠

5 v. c( H0 S# F3 o2 ]
通过a、b行代码比较,可以理解:
use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。如上的:
  1. use animal\dog;
复制代码

! {4 L& G8 s; A  l
相当于
  1. use animal\dog as dog;
复制代码

. F+ k- D: b6 y. ~2 v2.namespace后面不建议加类名,但use后可以。
3 J( f# R* o7 A6 \3 _$ G
  1. //name.php
    . X9 Q6 o6 L* p4 N: t7 X
  2. ( v) Q! ~2 m. q8 t) M: j" R
  3. namespace animal\dog;9 n& z+ s) }: l# @
  4. ) q& _( I* m1 P+ i" k
  5. class Life{# B, v: J/ o: V2 [: Z1 D( C; z+ s3 |
  6.     function __construct(){
    ; s+ y7 {+ v' f( P3 M
  7.             echo 'dog life!';; R; s1 L  s* d
  8.         }  p2 N7 I/ B' s5 D1 t3 x/ N
  9. }. _# t- A8 n; K  I( j8 V2 }

  10. 1 d" Y5 I3 [/ p% O) }
  11. namespace animal\cat;
    , L4 T% I' L& i2 g' Y
  12. $ b2 d; o9 K, c. @" X" @
  13. class Life{* D9 q  r( E# U; f
  14.     function __construct(){
    / p2 i( ^( i- |' E6 p
  15.             echo 'cat life!';% C8 M0 ?: t7 [# O: Y* s
  16.         }! b7 j5 I: N' m
  17. }
    & T- N5 t& ^. @, i
  18. ' e; W4 s* o1 X3 a$ C; q0 Z- O
  19. use animal\dog\Life as dog;  
    " E) ]. W& v  x! K; p2 }* J' J
  20. new dog();
复制代码
6 }/ ^0 }3 p4 A. R/ W/ z
如上所示,use后加上类名后,就相当于把类改了个名称:由Life改为dog了。
上面不用as dog就会报错:
  1. Fatal error:  Cannot use animal\dog\Life as Life because the name is already in use
复制代码
+ T3 x3 l9 F) L6 {
因为cat下也有个一样名称的Life类。
可以理解为,使用use后,这个昵称对应的类只能归当前命名空间占有,其它命名空间下不允许存在该类。
  1. //name.php( v& y/ h6 @2 v( I0 v: ~

  2. " J. D- j6 Z& I1 [
  3. namespace animal\dog;# D: i4 J3 K( A8 P( A3 ^
  4. 4 p$ `( P0 |  \% l* m- Z$ V% f
  5. class Life{+ l' ~) x' c' q! q3 A- z7 c
  6.     function __construct(){5 I% t9 G" T4 q, G
  7.             echo 'dog life!';& _# R7 ?' p0 M4 o* k% _# ^) K' g8 |
  8.         }
    ( V% z$ ~( w4 U/ ^7 g7 c
  9. }; d/ S3 }2 `5 z  L
  10. class Dog{- C2 r4 k" L$ N! Z
  11.     function __construct(){, H" Z* |3 y" m& G# @: f
  12.             echo 'dog in dog!';
    # b# |2 G4 U( Q! p
  13.         }6 c8 c. ]' j) o" n' Z: Z9 R
  14. }
    & S: L0 R  U3 e) w
  15. & ?2 u' m" b( ?6 [- t8 a. g
  16. namespace animal\cat;( r9 A6 Q* E" H6 s2 @
  17. 5 ]7 E( L2 L3 o4 F6 M2 H
  18. // class Dog{
    # G# z* }; X* d. s4 W
  19. //     function __construct(){
    ( Y: a4 M9 a0 ~. u- A( N
  20. //             echo 'dog in cat!';" X* r' p3 ]8 I- D
  21. //         }
      v3 ]/ ?( j" u; I; T6 r
  22. // }
    7 U( I+ b/ I3 K2 G" n
  23. class Life{
    6 {2 ^3 |8 X' |$ E
  24.     function __construct(){
    6 S6 ^3 v. D! B; L3 E1 _
  25.             echo 'cat life!';3 Q1 w. B7 z! P0 m- i, p
  26.         }1 H' H% w5 Z$ {% \" ]) V  a3 Z$ Q0 P
  27. }( }& E& X1 O. ]

  28. 8 {; q0 F) j3 ?! d) t! Z3 w
  29. use animal\dog;  
    ; u$ s% l  \  p9 R0 n
  30. new dog\Dog();
复制代码
, @) l2 u5 A4 `, `$ D
如上,使用了
  1. use animal\dog;
复制代码

" D0 z0 m' b5 P
cat
通过上面代码,我想使用use的目的效果(缩短命名空间名称)就很明显了。
1 B6 k1 z0 z; @
简单总结一下:
namespace就是划分领域的作用,代表这些东西是属于某个命名空间下的。
use就是起小名的作用,不论写起来还是说起来都可以省不少事儿。
& X8 A& H( ]# }. Y/ y5 T8 W0 B2 m

9 C$ r* Q; X2 n$ Q( s7 h; [/ v1 `7 i
7 I* N0 M& A% |3 k  ?1 d  d# `8 b( Q1 X2 I# q: W& J3 D
* o! Q) [* _# V: \1 W  \
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-5-17 17:16 , Processed in 0.121718 second(s), 19 queries .

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