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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2020-7-1 23:37:46 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
以下皆为本人自我理解内容,如有失误之处,请多多包涵。

5 o( j# X6 C) g0 [& V* R3 A
文章大纲:
使用namespace的目的
namespace的使用方法
使用use的目的
use的使用方法
  Q% Y$ g, }1 v1 F. U$ B5 `
$ x! D# y1 T  h7 Q# ]
使用namespace的目的:
团队合作项目时,避免与团队其它成员新建的类发生冲突;个人负责项目时,避免前后新建的类发生冲突;
6 h; X3 {7 Y8 I. ~( U) n6 Q& e
据个人理解,用到所需要的类时,需要先require或include引入,所以会发生类重定义的错误的前提是:两个相同命名的类都有被引入。目前有些php框架会自动加载(即include)所有新建的model类,所以为了避免你新建的model类和项目框架原生的核心类发生重名冲突,采用了namespace。(想了想,与团队成员新建的类产生冲突应该通过沟通避免,即使事发后也应该重新调整类名即时维护,避免后期造成因为对类的理解混淆而带来维护上的复杂度提高)
3 E+ L. E3 j2 ]$ f7 t
结合使用方法来进一步理解它的使用目的吧。

- h! y( e2 M" U: f4 K- @5 L! ?. H( {- B: [% u9 ]# h- }
namespace的使用方法:
为了进行测试,我将创建3个文件:1.php和name.php(此文件用来执行测试),后面将不再说明,请自行注意代码的变化。
1.namespace后命名的定义不区分大小写
  1. namespace one;
    6 \- w# z2 V6 s3 e, y
  2. namespace One;
    $ n# K! S. `/ x: M
  3. namespace ONE;
复制代码
' ~# P4 K/ v4 t1 ^. Q
如上写法都可以,选择一种作为自己的规范即可。(后面代码我采用第一种进行测试哈)

5 n2 j. k6 \0 v- V4 \2. 没有定义命名空间,就理解为使用顶级命名空间。new类时,可以在类前加上反斜杠\,也可以不加。
  1. //1.php   + L+ Y9 P. }) @
  2. class Person{
    ' K7 {* H: w4 V9 l  ^) ^4 w# t
  3.     function __construct(){
    6 c* m3 R) ]1 m; F; w
  4.             echo 'I am one!';3 d; F8 }: S! n  s# ~# G% N
  5.         }
    $ G, X% A- i) h$ ~4 L* V
  6. }
复制代码
  1. //name.php8 ~# [' ~1 f  b& v, U6 E% I- o4 Q
  2. require_once './1.php';
    . _+ z$ {. ?  X$ j& {' R

  3.   I  g) Y3 h. z
  4. new Person();     //输出 I am one!;1 Y. O/ C4 H- A+ E3 W8 W5 q1 S  ~, p, X
  5. new \Person(); //输出 I am one!;
复制代码
+ w% P, i) b* p
3. new类时,带上命名空间时,之间一定用反斜杠字符,而不是顺斜杠。
记忆方法:按找%中斜杠的顺序理解为顺斜杠。(有时说反斜杠,自己都不知道是哪种方向,以前按自左向右上升方向这种方向记忆,现在感觉这个太不靠谱了)
  1. //name.php3 g" |7 O8 n# }$ r6 X$ U& I
  2. require_once './1.php';1 `/ X5 w3 V! l! k2 r# ~
  3. new /Person();  // 代码报错:Parse error: syntax error, unexpected '/'
复制代码
# O# h" T1 r! g% q! }
4.类在指定命名空间下, new类时,一定要带上指定的命名空间。
没有带上指定的命名空间,按照第2点,php就会从顶级命名空间里找这个类。切记:这里不能按照顶级命名空间包含一切其它的命名空间来理解。而应该将顶级命名空间完完全全与其他命名空间区分开。
  1. //1.php   
    $ r% C0 }3 a* M" D  O- w/ W
  2. namespace one;
    : J1 f+ G8 P% m9 ?* i
  3. class Person{
      h" F1 T" y2 J* f" v: @
  4.     function __construct(){! ^7 \* y9 y0 L
  5.             echo 'I am one!';% T* Z( [! W/ i* ?, I3 d
  6.         }
    ; C! g. D! t3 l! J
  7. }
复制代码
  1. //name.php% {) ^0 U, v1 E  b, _
  2. require_once './1.php';
    ; j( Z0 d# M! ?# a4 F
  3. new \one\Person(); //输出 I am one!;
    - n- U- w" o% t4 k4 [8 \
  4. new \Person(); //代码报错:Fatal error: Class 'Person' not found
复制代码

" b  w) a  V& f# B% g5 p" ]
可以举个这个通俗例子来理解:带上指定命名空间代表某人的苹果(在他手里),顶级命名空间代表苹果箱里的苹果(在箱子里)。现在要找某人的苹果,就将某人的命名空间带上,否则就会从箱子里找某人的苹果,结果当然是找不到。

2 H) @1 M+ Q1 J3 M, q" g5.命名空间声明后的代码便属于这个命名空间,即使有include或require也不影响(重点是对后半句的理解,具体看代码)。7 E. i, a9 y9 v! [: K; w% l
  1. //1.php   
    3 K( X, x) \, K! L
  2. namespace one;6 a: n6 h+ I; s; W* `1 v
  3. class Person{6 J6 U1 E  u! G  f/ d% \6 c% x
  4.     function __construct(){5 E9 R# n  L. B" Q$ R
  5.             echo 'I am one!';$ i' @" Z" r3 q0 i" c! o$ x
  6.         }
    0 O4 Q3 T" k0 W5 w9 x! z: {
  7. }
复制代码
  1. //name.php: R# u3 r( ^- C& b
  2. namespace test;
    3 y/ ~: B  I  a, C5 k) J
  3. require './1.php';
    $ ?4 S. ^) R) f$ Y' }5 `* X
  4. new \one\Person(); //输出 I am one!;* o2 H( ^8 m: n; Q3 W& P6 f+ l
  5. new Person();      //这里结果会是什么呢,猜猜看
    4 u2 n/ ~6 S$ [- R  F) @
  6. 最后一行结果报错:
    6 G- F; n  [' A; d5 p" o
  7. Fatal error:  Class 'test\Person' not found
复制代码

8 p7 I. j  x! P/ O9 t- @

% O  g) ]# G* W3 q' Y0 O首先,这里与第2点比较一下:
第2点,我说,没有命名空间时,new类时,有没有反斜杠意义一样。
在这里,有了命名空间,有和没有反斜杠的意义就不一样了。
最后一行换成
  1. new \Person();
复制代码
6 K$ P" K$ _8 D2 W8 ?6 f, O+ |
结果报错:
  1. Fatal error:  Class 'Person' not found
复制代码
' t/ k4 L; G2 k$ v& f* c, z* c
接着,就说说当前这点。
我们可以发现,最后一行代码对应的命名空间为test,并没有受到require文件里的命名空间的影响。
进一步加强验证,我修改了name.php文件如下:
  1. //name.php8 }7 w( i& C' K/ j3 l' a
  2. namespace test;
    8 T; E+ ]3 N4 f" }- R$ h
  3. require './1.php'; & O$ a% L6 s/ R9 e' i  Q! {" V  P, L

  4. 8 U& W  R0 h2 ?) d# S; Z, R
  5. class Person{
    ( t) T* I' U7 Q3 d
  6.     function __construct(){/ O- x& C7 Y" F
  7.             echo 'I am test!';
    & X- w4 v4 G7 [, B: [
  8.         }& d1 |/ Y8 k5 k, \! W
  9. }
    , i  {8 k( y4 B' K/ R& _2 R

  10. " l( Q4 _; C# h6 g
  11. new \one\Person(); //输出 I am one!;
    * [* B8 C* U9 P( w7 L, ]3 c
  12. new Person();    //这里结果会是什么,自己猜猜看
复制代码

: @7 p: |" n, X
最后,这个例子刷新了我对require的认识了。
按照我以前对require的理解:PHP 程序在执行前,就会先读入 require 所指定引入的文件,使它变成 PHP 程序网页的一部分。所以我常常就简单的理解为替换,只不过把抽离出来的代码再放回原处而已。然后我试了将1.php文件内容放到name.php里:
  1. //name.php
    3 F/ ?1 d; F% T/ u4 k
  2. namespace test;
    6 N* h+ D8 q8 {! b# x; ]; r3 A' N
  3. namespace one;
    ) O( I  c7 d- D
  4. class Person{! q$ |0 r2 K' N: e4 a
  5.     function __construct(){
    + g9 |' M7 ]. \% V6 Z$ o* s
  6.             echo 'I am one!';" z" x" l# t! Y7 y4 G0 J7 B
  7.         }7 Z$ `( j9 K4 W6 M
  8. }
    ' T$ W5 ~' _; k% N$ k

  9. ' {8 o1 K, ?! l+ X: j/ i; ^% }
  10. class Person{$ B9 B! B+ X9 g) }
  11.     function __construct(){' t, |! s5 @) V# A  X/ G
  12.             echo 'I am test!';- S) k+ e* ]* |- p. e' r- |
  13.         }
    0 @& C7 u  H& }9 S
  14. }
复制代码

6 C4 l& b1 t. h; W9 V
无需new类,该文件就会报错:
  1. Fatal error:  Cannot redeclare class one\Person
复制代码

8 H. o8 B4 K3 ?( ]( p3 l
看来简单的把require理解为替换,在这里行不通。

3 v- X( U6 b1 `6.namespace里不包含类名称,即使存在与类名称同名的部分,那也不代表类。new类时,还是得将这部分带上。* v! s: Y6 X! l$ C% b
  1. //name.php0 ?& Q  R# B7 N
  2. 8 j" R! m1 J( B  i- x0 r
  3. namespace test\person;
    % I$ i( H* B9 X/ f" Q6 A% n

  4. 5 A+ ^/ V6 L/ a* `2 A, [6 ~8 W
  5. class Person{
    7 |2 b5 E! `) I% Z" ^! f
  6.     function __construct(){  s! k9 Z9 e# V# ]4 n
  7.             echo 'I am test!';
    9 ]/ H% q( o9 L4 c( m% f
  8.         }
    - h9 I& ?& Q. C1 v  Q  w
  9. }
    ( l& U: @2 z, Y  h; L4 _0 d" A6 \
  10. new \test\person\Person();  //命名空间里person无法代表类名
复制代码
1 U% h% }/ }- l
不过这样纯粹是画蛇添足,直接干脆点,namespace里不要带类名称就好。
) ^/ p7 U5 w7 @
7.一个php文件中可以存在多个命名空间,第一个命名空间前不能有任何代码。
只说第一个命名空间前不能有任何代码,之后的命名空间之前可以有代码。这个自行测试即可。
  1. //name.php
    % S. v+ G! r# y9 d
  2. 5 o8 G8 ]& o7 W9 j6 T# s
  3. namespace test;
    ; ]$ E9 I5 F# }' B6 Z' \
  4. echo 'zhai14';5 s! a. ^+ q& F5 B* B9 I0 K
  5. namespace zhai;5 j" P$ v5 O9 E- L/ b
  6. require './1.php';
复制代码
0 V3 ?' R% r7 a& @
php命名空间namespace告一段落了,接下来说说use的用途。
使用use的目的:
在命名空间字符串过长时,使用use可以相应的缩短命名空间。

+ ]. _: a4 T7 U% y+ Fuse的使用方法:1.new类时,最前面无需用反斜杠。此外,use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。
' K3 y2 Y/ o4 u4 i5 U3 ~" k2 x
  1. //name.php) E. q$ \* P, V! K2 G9 K
  2. 2 ?4 p  i9 q* F7 Q
  3. namespace animal\dog;& |( r: x' Z. Z! N" j3 w! O* z' K

  4. - Z, ]  x( J5 R" V
  5. class Life{0 x6 J8 u& v) `- c/ e
  6.     function __construct(){
    4 v; J& z& H# {2 H* B, p
  7.             echo 'dog life!';
    ; c& v7 ?5 V) F& S! _' `4 [
  8.         }
    * H" Y7 @" S7 X# x) _
  9. }5 j5 E9 g, {, l
  10. 0 D/ |% N) ~7 f+ Y  M
  11. namespace animal\cat;
    4 y5 T- y8 r. R. k* v# Q; v0 Q3 x1 P
  12. 0 B  r: x# T4 m5 M
  13. class Life{0 Z3 q& X3 m* l# R
  14.     function __construct(){
    3 S& B. I; X. O" m9 R% ^
  15.             echo 'cat life!';3 q5 A/ x1 @: s2 U
  16.         }9 P1 T7 c5 Z. {. G
  17. }
    : l! x" l5 Y+ B; R% F
  18. ; B* V. C) H6 j( x, B- X' P
  19. new Life();  //按照代码执行顺序,这里默认animal\cat这个命名空间
    : I0 [- J6 E, [0 |8 i
  20. new \animal\dog\Life();  //A
    5 Z- Q1 S! O$ j7 g2 G! P
  21. - Z5 O" r5 ]5 h# B& \
  22. use animal\dog;  //a& y2 z0 e$ H7 l  d+ u$ H. b
  23. new dog\Life();  //B5 w# Y5 t- M  j, ]2 c
  24. $ b! ~7 ^& L/ H4 f2 p: g: T( M& {; k
  25. use animal\dog as d;  //b+ E7 w7 x( P9 S, f$ u. i
  26. new d\Life();
复制代码
1 y' T: B! k& i" R+ s* F2 Z9 x
通过A、B行代码比较,需要注意:
使用use后,new类时,最前面没有反斜杠。
没使用use时,命名空间最前面有反斜杠
* c. N5 g! f4 X$ J$ _) |
通过a、b行代码比较,可以理解:
use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。如上的:
  1. use animal\dog;
复制代码

/ g5 M$ @5 r9 B/ v
相当于
  1. use animal\dog as dog;
复制代码

/ r  J* ?& _6 C$ s2.namespace后面不建议加类名,但use后可以。3 W% J! c1 ^% f- b
  1. //name.php
    % w, P3 y6 [) @9 F7 [) E: z

  2. 8 ]6 X) k2 q0 Z2 `* Y# I5 R! {* z( ~. t
  3. namespace animal\dog;
    + g1 H9 y4 w' G+ X5 F
  4. 6 ]" Q% P5 P" `
  5. class Life{
    $ [2 l; B( O3 i5 N9 m
  6.     function __construct(){
    % L( i# O, ^) ~2 v2 A7 u1 u
  7.             echo 'dog life!';1 H/ R$ }& p1 d2 W. n1 @
  8.         }
    3 Z$ S8 z, T* {8 [/ C" F
  9. }9 p3 X& \' y/ y" c$ _4 g) d

  10. $ N6 I: D* c8 t) I8 z
  11. namespace animal\cat;2 r; }, U& F8 p1 R: y

  12. $ Y  D4 ~$ a2 q4 E. ^% ~
  13. class Life{
    ( f% q! O- ?8 `# G" [
  14.     function __construct(){( P) Q7 J# z6 |+ |
  15.             echo 'cat life!';
    ! l$ a4 {8 ^2 j2 j# ~0 c" y
  16.         }3 f3 a( e* F, ~1 j" N) R5 T( t
  17. }
    # l- u* ]" B- W- ?- ?
  18. 4 j6 O2 F( t" M' P. i4 z
  19. use animal\dog\Life as dog;  9 I, v9 Y( A& t' v6 _
  20. new dog();
复制代码

7 Y+ e* f* ?3 ]; O1 u, o0 o
如上所示,use后加上类名后,就相当于把类改了个名称:由Life改为dog了。
上面不用as dog就会报错:
  1. Fatal error:  Cannot use animal\dog\Life as Life because the name is already in use
复制代码
3 o% u9 N3 t$ e9 u
因为cat下也有个一样名称的Life类。
可以理解为,使用use后,这个昵称对应的类只能归当前命名空间占有,其它命名空间下不允许存在该类。
  1. //name.php
    ) J/ s+ ]7 z( [+ l, n" v& y

  2. + y5 y+ r, @) {5 S( P$ U
  3. namespace animal\dog;: ^% ]* U, l5 L% p2 ]
  4. ' r7 ]3 N8 o) Q6 J3 a+ A
  5. class Life{$ J8 n& h9 w  W- `& I% v9 J
  6.     function __construct(){0 D2 q: f: q6 ]' M9 I
  7.             echo 'dog life!';
    7 d, d- q5 Y" u
  8.         }9 t7 \% u8 E7 d0 R
  9. }
    $ {; S4 x+ h6 _+ W2 i( y. ]2 E
  10. class Dog{
    5 k& ]& L  F( b1 [, J
  11.     function __construct(){- ^1 W% c. D$ [
  12.             echo 'dog in dog!';
    ' r8 g. v6 O+ m4 y& r% b; X3 T
  13.         }
    7 q" t8 ?$ }# b
  14. }
    $ U, V( b  _) `, L) _$ |4 K; n# I

  15. 9 {# A! u' C* n* u% K) V
  16. namespace animal\cat;$ Q# z0 w% c+ d* X
  17. - D; Y5 ?( ~7 @" o7 l0 m
  18. // class Dog{5 B; {# f: X% ?1 T9 k
  19. //     function __construct(){$ q  T5 j& p8 E( B
  20. //             echo 'dog in cat!';
    ) N, r4 L6 ]/ d$ W8 u" B7 h
  21. //         }- h9 t6 ^3 g7 U9 l+ U
  22. // }: ~  H' Z% Z# s6 W$ j
  23. class Life{4 L0 P" s8 o% I0 W0 L
  24.     function __construct(){
    4 T, s5 g% n! c& y
  25.             echo 'cat life!';
    ( d" @1 J0 c7 E2 p. E4 M
  26.         }
    2 d+ j, m) M+ \; X& N3 W: x. l
  27. }
    ! G0 f6 o. |8 L9 K8 Q
  28. . j/ Q% I* g2 h" J
  29. use animal\dog;  
    0 f. q0 a" j7 i: v7 x" h
  30. new dog\Dog();
复制代码
1 Y. h/ W. H; q* D/ y
如上,使用了
  1. use animal\dog;
复制代码

1 F$ T" ~2 M, L) V7 {
cat
通过上面代码,我想使用use的目的效果(缩短命名空间名称)就很明显了。
* e2 [5 w- p% n7 A
简单总结一下:
namespace就是划分领域的作用,代表这些东西是属于某个命名空间下的。
use就是起小名的作用,不论写起来还是说起来都可以省不少事儿。
( L6 s- n+ A5 X4 a; F  R' B0 f. V
3 b7 B8 M3 n( J  v4 {8 V$ z8 y( E, I! Z
7 t4 t7 W+ s( ]7 A0 u
  F" r0 R; i4 Z

5 e: a: u# \5 l$ A
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-4-20 00:51 , Processed in 0.121564 second(s), 19 queries .

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