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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

) `1 N+ x# Q& [5 B
" w/ Z* {/ A! ]# ]. [5 ~2 S! l8 @使用namespace的目的:
团队合作项目时,避免与团队其它成员新建的类发生冲突;个人负责项目时,避免前后新建的类发生冲突;
% l, L) U+ k$ P: ]" s. ?, O1 ]
据个人理解,用到所需要的类时,需要先require或include引入,所以会发生类重定义的错误的前提是:两个相同命名的类都有被引入。目前有些php框架会自动加载(即include)所有新建的model类,所以为了避免你新建的model类和项目框架原生的核心类发生重名冲突,采用了namespace。(想了想,与团队成员新建的类产生冲突应该通过沟通避免,即使事发后也应该重新调整类名即时维护,避免后期造成因为对类的理解混淆而带来维护上的复杂度提高)
% [5 x/ S1 k) V8 N% T
结合使用方法来进一步理解它的使用目的吧。
9 X! x4 G$ [; x* {  d: s

2 P7 j$ d$ }  w8 K% H) w# ?+ {namespace的使用方法:
为了进行测试,我将创建3个文件:1.php和name.php(此文件用来执行测试),后面将不再说明,请自行注意代码的变化。
1.namespace后命名的定义不区分大小写
  1. namespace one;: w+ B- b2 B% F/ ]
  2. namespace One;
    : v  }$ h9 R- A4 ]3 [3 K8 H7 c: p/ S
  3. namespace ONE;
复制代码
8 {6 S$ x1 f/ U; C* ^2 r
如上写法都可以,选择一种作为自己的规范即可。(后面代码我采用第一种进行测试哈)
$ a; y% w8 A$ ~: A6 e5 ^$ M
2. 没有定义命名空间,就理解为使用顶级命名空间。new类时,可以在类前加上反斜杠\,也可以不加。
  1. //1.php   
    9 X0 ]" y3 X0 k1 Y1 i/ G7 f
  2. class Person{- s- j! d7 j  z
  3.     function __construct(){. _1 o& S; w# X- S5 U
  4.             echo 'I am one!';& ~* n4 v3 Q) T& \( j
  5.         }
    ) }. `% z; A' M4 t% ]
  6. }
复制代码
  1. //name.php# j+ Z) O+ ?/ J  b! E; `
  2. require_once './1.php';) o0 V& D7 r6 L3 ?5 c

  3. 8 s: G9 V9 b+ d" Y8 T2 A0 }6 m& e
  4. new Person();     //输出 I am one!;
    3 C: R1 }( P/ y' l
  5. new \Person(); //输出 I am one!;
复制代码

4 K0 t* z) Z* E. _# O$ Z8 ?3. new类时,带上命名空间时,之间一定用反斜杠字符,而不是顺斜杠。
记忆方法:按找%中斜杠的顺序理解为顺斜杠。(有时说反斜杠,自己都不知道是哪种方向,以前按自左向右上升方向这种方向记忆,现在感觉这个太不靠谱了)
  1. //name.php
    8 t) w9 ]8 j5 p+ b& e- g8 I+ }) V  Q$ l
  2. require_once './1.php';. g" t# L/ _" a9 f3 E/ Z+ T
  3. new /Person();  // 代码报错:Parse error: syntax error, unexpected '/'
复制代码

3 Z% F6 @/ n9 r& o0 G4.类在指定命名空间下, new类时,一定要带上指定的命名空间。
没有带上指定的命名空间,按照第2点,php就会从顶级命名空间里找这个类。切记:这里不能按照顶级命名空间包含一切其它的命名空间来理解。而应该将顶级命名空间完完全全与其他命名空间区分开。
  1. //1.php   # m. m% W& Z. _- B4 R( R: c6 ^5 C
  2. namespace one;9 p, u$ J$ h$ A( r& H8 A
  3. class Person{
    ; o2 [0 d* y% P  t! D
  4.     function __construct(){
    - n$ V' l) U' W. h0 p' H' B
  5.             echo 'I am one!';
    9 D3 X. Q, U" g7 o& C+ ]
  6.         }6 W) A' C+ i2 C: j. q2 J2 N/ O
  7. }
复制代码
  1. //name.php/ l$ w: E6 b3 ~; d: O( Z) K4 g; _
  2. require_once './1.php';) D  S$ O1 z+ z) N6 ^
  3. new \one\Person(); //输出 I am one!;
    / y+ L0 m0 q* [8 o8 y2 B& Z+ K2 N+ U
  4. new \Person(); //代码报错:Fatal error: Class 'Person' not found
复制代码
* `* A& G# o1 Q, J8 k4 w5 u
可以举个这个通俗例子来理解:带上指定命名空间代表某人的苹果(在他手里),顶级命名空间代表苹果箱里的苹果(在箱子里)。现在要找某人的苹果,就将某人的命名空间带上,否则就会从箱子里找某人的苹果,结果当然是找不到。
" ?* [# W9 }- O/ Z
5.命名空间声明后的代码便属于这个命名空间,即使有include或require也不影响(重点是对后半句的理解,具体看代码)。6 m9 t4 G, \+ m& |' q& {: V8 S4 `, h
  1. //1.php   , d; H" a3 L" p5 Z4 `
  2. namespace one;9 ]; R, M  Q  n' F6 `
  3. class Person{1 D; [# f  ^& o6 I, t
  4.     function __construct(){( L7 R* D/ z- v: q: Y% G$ f
  5.             echo 'I am one!';
    " }& H7 x8 [8 L1 q7 t: r
  6.         }3 N0 L+ l) N4 \" `  g- F. `& B
  7. }
复制代码
  1. //name.php2 V9 G  c1 ~5 K+ u" e
  2. namespace test;
    ! r, h3 ^% Y% N( |; W# V4 h! a
  3. require './1.php'; ) M( _+ H. L0 \! D8 @6 f+ p% P
  4. new \one\Person(); //输出 I am one!;
    . y* F& [; w1 P, Q
  5. new Person();      //这里结果会是什么呢,猜猜看) F. ?2 `, u2 L& s$ H4 s6 U
  6. 最后一行结果报错:
    - B4 l  `4 d. [# U
  7. Fatal error:  Class 'test\Person' not found
复制代码

3 ^; S0 {  ?$ u2 k% h) t/ w

- f4 A: |7 \8 I2 |首先,这里与第2点比较一下:
第2点,我说,没有命名空间时,new类时,有没有反斜杠意义一样。
在这里,有了命名空间,有和没有反斜杠的意义就不一样了。
最后一行换成
  1. new \Person();
复制代码

5 f- \# S+ o9 y
结果报错:
  1. Fatal error:  Class 'Person' not found
复制代码
3 K4 T" z. w8 b% W
接着,就说说当前这点。
我们可以发现,最后一行代码对应的命名空间为test,并没有受到require文件里的命名空间的影响。
进一步加强验证,我修改了name.php文件如下:
  1. //name.php- P8 x% |" Q* ?, Y. q/ B' g5 p
  2. namespace test;
    - ~4 R7 D- g9 f- {$ [& E5 X4 G
  3. require './1.php'; 4 r) ^& h3 R' x5 j  S9 L4 u
  4. 7 {5 u* p8 O( E3 l5 X
  5. class Person{$ ~& L* F5 d6 w* K8 T4 G4 _6 H
  6.     function __construct(){  K4 @- W. ]& G7 b5 ~' d
  7.             echo 'I am test!';% |* q* }1 L5 @/ H9 T& ^+ \* M$ `
  8.         }
    ! @8 n  w9 k1 Q, ?
  9. }4 L4 `4 Q4 p7 f/ {; I

  10. 0 a- Z( m* H# ^3 D
  11. new \one\Person(); //输出 I am one!;
    " {& l. f6 i" w" A/ v6 U1 d
  12. new Person();    //这里结果会是什么,自己猜猜看
复制代码

9 t6 t( k, p$ @" d) i2 s. ], ]# ~
最后,这个例子刷新了我对require的认识了。
按照我以前对require的理解:PHP 程序在执行前,就会先读入 require 所指定引入的文件,使它变成 PHP 程序网页的一部分。所以我常常就简单的理解为替换,只不过把抽离出来的代码再放回原处而已。然后我试了将1.php文件内容放到name.php里:
  1. //name.php% |0 _4 L* P' ~2 Y" g
  2. namespace test;
    0 L' i8 P2 p  X' }7 R( R2 s
  3. namespace one;
    * L+ Q1 [3 D/ [7 v6 m. n$ a+ S% L7 F
  4. class Person{
    9 j( E4 m, t4 H0 [, p5 x
  5.     function __construct(){
    - g9 P3 w& _% Z1 R9 B$ r
  6.             echo 'I am one!';
    6 ^) ]( Y% \0 y, n! N, l* x3 \
  7.         }
    ( F" N% G. ?7 H' _! X
  8. }7 s* n) l3 L9 x: a* {/ t7 }
  9. & A1 u2 k5 _$ O( o" N" \3 a
  10. class Person{% r0 {' F2 e+ o7 _- f- r+ y
  11.     function __construct(){& Q9 Q2 T* n3 w& b( o4 j
  12.             echo 'I am test!';$ s8 n  W9 g+ ~, z! t7 i
  13.         }9 _4 F0 l6 R: s2 d" `
  14. }
复制代码
# d' w% N7 w5 Q& `
无需new类,该文件就会报错:
  1. Fatal error:  Cannot redeclare class one\Person
复制代码
, |$ i$ o$ a& {! q
看来简单的把require理解为替换,在这里行不通。

3 |8 Y! O: H, j3 b+ A6.namespace里不包含类名称,即使存在与类名称同名的部分,那也不代表类。new类时,还是得将这部分带上。" E: b/ z8 \# V9 p; e6 b0 o# L
  1. //name.php
    # \; {* b9 z  r& W- f9 o& v
  2. 4 Q7 c( v) Q2 @* b1 r
  3. namespace test\person;) H. z' w, z  G/ z/ F2 D% ^
  4. % R& p6 R( y7 q6 j" o
  5. class Person{( A2 W, a% U4 k1 W* N, c7 W' D8 h2 s
  6.     function __construct(){
    3 z' w5 f( |' ^' z$ V- }7 Y
  7.             echo 'I am test!';  g8 G; P# [' `0 d
  8.         }8 I: l& g3 k5 }' `$ v
  9. }& e4 d9 {. t% q$ a4 A
  10. new \test\person\Person();  //命名空间里person无法代表类名
复制代码
+ l0 ^. p$ {) @, v  Y8 j4 K
不过这样纯粹是画蛇添足,直接干脆点,namespace里不要带类名称就好。
8 ~, W2 q1 G2 r# q4 f
7.一个php文件中可以存在多个命名空间,第一个命名空间前不能有任何代码。
只说第一个命名空间前不能有任何代码,之后的命名空间之前可以有代码。这个自行测试即可。
  1. //name.php7 {- r9 m. y9 v/ j4 x
  2. 5 f' u/ Q4 p8 X4 v1 \
  3. namespace test;: U. B6 T  f: n
  4. echo 'zhai14';
    3 Z7 k, q' l- K9 |& F  \
  5. namespace zhai;& v" m/ `$ U2 B4 X
  6. require './1.php';
复制代码
) a& ^  P* s% F
php命名空间namespace告一段落了,接下来说说use的用途。
使用use的目的:
在命名空间字符串过长时,使用use可以相应的缩短命名空间。

8 X) Y1 P; C  n3 i9 ^8 zuse的使用方法:1.new类时,最前面无需用反斜杠。此外,use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。5 [5 D" m6 G3 M1 s& n
  1. //name.php* v" {: D) S! m$ _5 R# f$ W
  2. % y3 O# R+ x8 j8 R1 _, J6 R
  3. namespace animal\dog;
    % m, k% P6 \: L4 E

  4. $ [: @$ `9 a7 b+ k* x9 F: O0 p! \
  5. class Life{* i6 k  |9 K( w6 {9 g; {5 t) |
  6.     function __construct(){
      s  K0 ], h& y6 r
  7.             echo 'dog life!';1 [/ x: C( s7 H& [# D5 `1 F0 H
  8.         }8 l/ D2 m/ ]6 G" D- `6 ^0 F
  9. }
    6 A1 S/ M2 k9 }; ^
  10. $ s- t- ~, |& T! ~: w/ ?0 T: r
  11. namespace animal\cat;0 a' {: E1 L5 V& w! v5 {0 ]: a; z2 E
  12. ' T9 p7 A* P/ \% `0 m
  13. class Life{0 O& J, [! C0 Z8 A* C, z
  14.     function __construct(){& ~% |9 f1 o- P( q+ ?9 G+ M
  15.             echo 'cat life!';* Z5 A4 u) `& j" ]/ @; }, l
  16.         }1 A) R: G) h& Y  V# {- S; W0 H$ q8 `
  17. }
    7 t# Z) L* }7 x) @/ [; L+ `* e  M
  18. ! W5 V1 M9 e7 ~7 u  A1 M3 {4 U
  19. new Life();  //按照代码执行顺序,这里默认animal\cat这个命名空间
    ' X% g% L: O2 c' \# m# }
  20. new \animal\dog\Life();  //A. ^& ]" Q7 f( H) D5 S* @4 x- c

  21. , b& t, ^  {& u  d5 O
  22. use animal\dog;  //a& d. V$ F; p% P3 I! `  b8 ]6 {1 c
  23. new dog\Life();  //B
    ( @. c: J% [. r7 J3 ]3 \
  24. 4 T* ]* {  P; x3 z! q1 H! z' n; q
  25. use animal\dog as d;  //b5 J1 V2 H( Y% J* [
  26. new d\Life();
复制代码

6 s$ @. C/ L9 i
通过A、B行代码比较,需要注意:
使用use后,new类时,最前面没有反斜杠。
没使用use时,命名空间最前面有反斜杠

! m+ x, F. G8 h% E$ g# }& ?
通过a、b行代码比较,可以理解:
use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。如上的:
  1. use animal\dog;
复制代码

. u0 S( A/ H( \/ ~4 A' @
相当于
  1. use animal\dog as dog;
复制代码

$ m0 V  e- |8 p+ D# F7 Y2.namespace后面不建议加类名,但use后可以。7 Q) J$ n* {4 Q9 j: n8 f
  1. //name.php- Z1 _  U7 x' T1 x' A. u  |" Q/ y1 j

  2. & K1 q. c0 u4 Y/ S7 o
  3. namespace animal\dog;8 T  t8 |5 c* ~, ^
  4. 3 b& y0 N. _6 F
  5. class Life{
      r2 ^2 F0 k# K% |
  6.     function __construct(){
    2 m% g' r9 U5 f3 f( T9 n  }) e& H
  7.             echo 'dog life!';' y5 J5 r& g) y; N" B! P0 f
  8.         }9 o. @. _4 }; G
  9. }
    * T/ s- D. h! e% A

  10. $ {$ g7 q6 w4 A0 o2 x
  11. namespace animal\cat;
    0 B9 z) c% A3 x5 P9 q. L0 c; S
  12. / a" a( p% ~" f' D
  13. class Life{& g8 G/ G% J/ u+ U) a
  14.     function __construct(){
    & A# J  G: q( ]! d8 ^# M5 F# D
  15.             echo 'cat life!';
    7 a2 a8 J' R* d9 u  O
  16.         }' M4 I0 A7 i( f
  17. }
    6 i- {+ y6 r+ ~8 z3 R) p  D

  18. $ `# a. s$ H) F
  19. use animal\dog\Life as dog;  5 X+ u+ Z4 ?+ d, Q
  20. new dog();
复制代码
$ L" t: U4 o$ x( L6 f0 O
如上所示,use后加上类名后,就相当于把类改了个名称:由Life改为dog了。
上面不用as dog就会报错:
  1. Fatal error:  Cannot use animal\dog\Life as Life because the name is already in use
复制代码
) ^: m+ k$ h% V. A& N3 R$ f
因为cat下也有个一样名称的Life类。
可以理解为,使用use后,这个昵称对应的类只能归当前命名空间占有,其它命名空间下不允许存在该类。
  1. //name.php3 ~! C! n0 l8 p4 c4 C
  2. 6 N. M3 A: D: u. V0 c) V8 m8 f
  3. namespace animal\dog;2 r( ^! s# b& M4 i+ w0 K

  4. . z  m$ _- Y* C# n( T' v
  5. class Life{* J4 t1 w) Q5 ^+ t
  6.     function __construct(){
    1 w) N  c8 H/ }5 n1 E, k2 Z
  7.             echo 'dog life!';/ ^* w- x! h$ t, |
  8.         }
    0 H7 T& u# e3 ^$ `: C; `
  9. }2 B0 D7 R  Y- H6 I/ }
  10. class Dog{
    & {: c, `* [/ c. i9 j5 v! |2 U
  11.     function __construct(){! z) \! s% V, r% r% o0 @, [9 x
  12.             echo 'dog in dog!';
    / V+ }6 w6 O% x8 F7 i1 _( B
  13.         }: A2 _4 C; p$ U1 o
  14. }
    , G  {* Q4 S' _3 k) z
  15. , b; L1 H6 m) y3 E, k* P+ g
  16. namespace animal\cat;
    6 d- Q3 s" ]) A; Q2 _% c9 r5 V2 w& p

  17. ; U. J' z' C2 s% b+ e1 h
  18. // class Dog{, d& Y/ s8 R% |: D- |0 t
  19. //     function __construct(){4 c/ d, O) s% Q, I) J* s0 T/ h
  20. //             echo 'dog in cat!';9 w7 m4 p3 B/ S& W9 P7 ~7 Z" z
  21. //         }
    6 c" f- ~% ]' s  `5 }# v) ?; K% N
  22. // }! L( i6 H/ z0 U7 y2 O6 K  S
  23. class Life{
    ) s5 a. p0 Z, I2 r/ P  d
  24.     function __construct(){
    & \4 x9 d0 K6 Y4 C
  25.             echo 'cat life!';
    3 h" o  u( B3 u# Q. S% D
  26.         }3 h# A4 }" O& E3 h1 s. X
  27. }8 T  E) a; a6 S* A3 [

  28. 4 f4 h, p) O" M5 C* a2 w+ |
  29. use animal\dog;  9 p: F/ z5 M7 X4 r' q
  30. new dog\Dog();
复制代码

! b3 @  a8 \2 ?- k# ?2 }
如上,使用了
  1. use animal\dog;
复制代码
$ _5 F/ i, W/ c) h# S0 e
cat
通过上面代码,我想使用use的目的效果(缩短命名空间名称)就很明显了。

! S; p5 a7 X: V* v1 \/ B
简单总结一下:
namespace就是划分领域的作用,代表这些东西是属于某个命名空间下的。
use就是起小名的作用,不论写起来还是说起来都可以省不少事儿。

5 `- F8 f# @& N' p3 `5 ~
: h% G& I0 ]; _6 Q% n) }+ }
- o! Z0 E) T3 q& E5 d# h3 T% ]5 d. a. r( B/ d/ F8 R0 p1 u

3 m& x+ j  ?0 J: F
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-22 11:55 , Processed in 0.122522 second(s), 19 queries .

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