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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

+ s, `1 k" A$ C2 m
文章大纲:
使用namespace的目的
namespace的使用方法
使用use的目的
use的使用方法

- f- z3 O6 l$ Z+ I8 n" g/ M) |9 w; M6 V7 x8 f1 J
使用namespace的目的:
团队合作项目时,避免与团队其它成员新建的类发生冲突;个人负责项目时,避免前后新建的类发生冲突;
( j  T+ |# H6 L, ^
据个人理解,用到所需要的类时,需要先require或include引入,所以会发生类重定义的错误的前提是:两个相同命名的类都有被引入。目前有些php框架会自动加载(即include)所有新建的model类,所以为了避免你新建的model类和项目框架原生的核心类发生重名冲突,采用了namespace。(想了想,与团队成员新建的类产生冲突应该通过沟通避免,即使事发后也应该重新调整类名即时维护,避免后期造成因为对类的理解混淆而带来维护上的复杂度提高)
6 C2 Q5 z; S* T" Z
结合使用方法来进一步理解它的使用目的吧。
% G: i- C1 v2 T  U. X) Q
; K. j' x+ j) N! n
namespace的使用方法:
为了进行测试,我将创建3个文件:1.php和name.php(此文件用来执行测试),后面将不再说明,请自行注意代码的变化。
1.namespace后命名的定义不区分大小写
  1. namespace one;1 M8 v+ n6 L, Z& s4 k, m5 F8 Z+ Q
  2. namespace One;& h3 [8 N5 K2 Y4 x+ `
  3. namespace ONE;
复制代码
* i; |9 r- W4 `3 }& |7 Y7 {4 Y# d
如上写法都可以,选择一种作为自己的规范即可。(后面代码我采用第一种进行测试哈)
$ ^9 B1 R0 V. {) n3 @! J* }/ O7 }
2. 没有定义命名空间,就理解为使用顶级命名空间。new类时,可以在类前加上反斜杠\,也可以不加。
  1. //1.php   
    9 \0 X* I% n3 S2 l
  2. class Person{& J9 J4 h/ Z8 z6 Q6 z! @! j/ b
  3.     function __construct(){9 ^, t. B; B1 X  {
  4.             echo 'I am one!';
    6 ]2 \, j% Z! @* _2 d2 Q; j. ~: _
  5.         }
    ; h: Y$ G* a8 t6 H$ Q3 X0 w6 k
  6. }
复制代码
  1. //name.php* a! H+ b- E+ y2 R1 k
  2. require_once './1.php';& G  d; u; v. C( J4 z" y, m2 w

  3. 0 @3 H  ]7 m9 a* T9 }( f" R0 _! ]
  4. new Person();     //输出 I am one!;
    " \' t0 M( @  w) [: J. x
  5. new \Person(); //输出 I am one!;
复制代码
8 G5 p0 P' S1 q8 w3 G# f9 U- b, B9 {
3. new类时,带上命名空间时,之间一定用反斜杠字符,而不是顺斜杠。
记忆方法:按找%中斜杠的顺序理解为顺斜杠。(有时说反斜杠,自己都不知道是哪种方向,以前按自左向右上升方向这种方向记忆,现在感觉这个太不靠谱了)
  1. //name.php0 k% u1 h5 Z9 {# r: E
  2. require_once './1.php';
    - m6 A: T/ T4 E
  3. new /Person();  // 代码报错:Parse error: syntax error, unexpected '/'
复制代码

, O; Y- o+ L# D& ]& }4.类在指定命名空间下, new类时,一定要带上指定的命名空间。
没有带上指定的命名空间,按照第2点,php就会从顶级命名空间里找这个类。切记:这里不能按照顶级命名空间包含一切其它的命名空间来理解。而应该将顶级命名空间完完全全与其他命名空间区分开。
  1. //1.php   
    * z2 k6 ~5 r( ?" ~/ @$ L
  2. namespace one;
    5 `7 y* ~5 n" `  x5 o3 Q0 r
  3. class Person{
    - i! v! ?1 Z+ o
  4.     function __construct(){
    2 C$ L0 z. M. d" b% @; Y3 r" ~
  5.             echo 'I am one!';
    9 d4 G/ C# z: `5 U
  6.         }1 H4 w5 V; ]5 W0 ^- o, e
  7. }
复制代码
  1. //name.php
    . T% A% U* z. m( b4 f' g
  2. require_once './1.php';+ D4 |3 i% n/ R3 t* c7 e; U
  3. new \one\Person(); //输出 I am one!;  S" E" j; S$ C# x
  4. new \Person(); //代码报错:Fatal error: Class 'Person' not found
复制代码
% s/ k7 P' J* s: D0 u
可以举个这个通俗例子来理解:带上指定命名空间代表某人的苹果(在他手里),顶级命名空间代表苹果箱里的苹果(在箱子里)。现在要找某人的苹果,就将某人的命名空间带上,否则就会从箱子里找某人的苹果,结果当然是找不到。

6 Q( }" @  A! k5.命名空间声明后的代码便属于这个命名空间,即使有include或require也不影响(重点是对后半句的理解,具体看代码)。
  j% [4 h; Z: z& i8 ]9 n4 t
  1. //1.php   
    1 b  x0 c9 z4 U& u# k3 M; f8 `
  2. namespace one;
    # z0 v2 w# Z. W3 {6 M
  3. class Person{
    ' q) w5 ~; ?3 O4 o2 n+ d* ]7 P
  4.     function __construct(){
    3 G9 a  T, N# ?$ L$ W
  5.             echo 'I am one!';7 h+ m& ~" D" N0 ]5 X
  6.         }
    6 L' w) Y' r& t+ V- B
  7. }
复制代码
  1. //name.php
    / T! ]% R7 H; ?$ ]) _9 J0 a# _
  2. namespace test;
    4 |: R8 [- |7 }9 W: s
  3. require './1.php';
    1 I6 I& E; g* q  ^
  4. new \one\Person(); //输出 I am one!;/ a4 L  h5 k* W8 [- A" A
  5. new Person();      //这里结果会是什么呢,猜猜看4 r% P3 h7 Z5 S$ ]
  6. 最后一行结果报错:) ?, A! F  P( }0 h4 y- \. O
  7. Fatal error:  Class 'test\Person' not found
复制代码

6 Y5 ~, E" s8 t0 `* l- H- T1 f
  d) y$ ~- _& b8 Q( `1 \3 b
首先,这里与第2点比较一下:
第2点,我说,没有命名空间时,new类时,有没有反斜杠意义一样。
在这里,有了命名空间,有和没有反斜杠的意义就不一样了。
最后一行换成
  1. new \Person();
复制代码

( i+ Y0 i# R) z: {: K
结果报错:
  1. Fatal error:  Class 'Person' not found
复制代码

5 B4 z' [$ S8 \7 c9 i1 D" o
接着,就说说当前这点。
我们可以发现,最后一行代码对应的命名空间为test,并没有受到require文件里的命名空间的影响。
进一步加强验证,我修改了name.php文件如下:
  1. //name.php, }) }6 u( o3 f7 T
  2. namespace test;
    ( ]! ?) p0 r4 }8 |. |3 Z( x, M
  3. require './1.php';
    $ e8 r  F* X* t0 y  ~8 x+ {

  4. - j! v- u& p0 B: ^4 E2 o
  5. class Person{2 w$ Z# x$ ?9 b" ?2 M/ G" b; t' o
  6.     function __construct(){  i" Z  e) n* ~6 U9 o" H5 l
  7.             echo 'I am test!';( v2 W. I& h% ]- y. j8 q5 ]' H
  8.         }, C2 y  X' w, R6 b2 ]- @# k
  9. }
    8 k* _) Z  V& m) |) f

  10. 2 f. C, {/ q+ Y/ z& ^2 P5 M! g
  11. new \one\Person(); //输出 I am one!;
    ) F" L- l+ w9 g8 i% d1 A5 ^! |
  12. new Person();    //这里结果会是什么,自己猜猜看
复制代码

- T! h# j- k2 t; K/ G/ c* p
最后,这个例子刷新了我对require的认识了。
按照我以前对require的理解:PHP 程序在执行前,就会先读入 require 所指定引入的文件,使它变成 PHP 程序网页的一部分。所以我常常就简单的理解为替换,只不过把抽离出来的代码再放回原处而已。然后我试了将1.php文件内容放到name.php里:
  1. //name.php
    , o/ l, |$ X2 p# g3 S1 }& i# _
  2. namespace test;
    - Z" S8 o1 [2 H8 a( T9 Y
  3. namespace one;
    , t2 E% R: @2 H; O# y$ J+ ]6 |+ Y
  4. class Person{, Q5 r9 [6 M! G6 p' J7 Y; ]
  5.     function __construct(){
    5 l9 ?+ \$ M$ O$ b5 K, k1 b: s
  6.             echo 'I am one!';
    1 L2 W. j- P; P- B, \' h- r
  7.         }' S( F5 ~5 j6 k6 k$ V0 V$ \
  8. }. F! |' c1 ?& G8 F# T

  9. - P8 v, o: t5 r$ b
  10. class Person{! w) h) g  L6 N/ R* }2 J5 T: U
  11.     function __construct(){3 [' G1 X- T/ k; {( R
  12.             echo 'I am test!';
    1 E! D! j9 a. [) R, ?
  13.         }
    & G( \5 v' \' E) {
  14. }
复制代码

& \) W: y8 B+ \2 m5 \5 N
无需new类,该文件就会报错:
  1. Fatal error:  Cannot redeclare class one\Person
复制代码
% \  p6 Z; V5 z! o
看来简单的把require理解为替换,在这里行不通。
! o, l: J5 A* B1 {% x- h
6.namespace里不包含类名称,即使存在与类名称同名的部分,那也不代表类。new类时,还是得将这部分带上。
1 P2 Z. r/ a# o2 Y. a% j5 t8 R
  1. //name.php
    8 i  y7 C) A# x
  2. / @+ y1 G- t5 k3 v
  3. namespace test\person;: a+ i/ }5 u! ?

  4. 5 Q1 P' S5 {  p* w9 i
  5. class Person{+ c4 Y# \$ ?9 L% j$ x" Y
  6.     function __construct(){
    # T8 ^  A8 @' l  R
  7.             echo 'I am test!';! J2 f- N& F& X0 q
  8.         }
    ) c/ u  n% q3 n  I) ~
  9. }+ o) k9 t9 g8 o& O! l0 l0 v
  10. new \test\person\Person();  //命名空间里person无法代表类名
复制代码
4 D3 D1 z, Q' L3 Q6 A5 w
不过这样纯粹是画蛇添足,直接干脆点,namespace里不要带类名称就好。

0 [4 w2 |6 F  ]6 s3 C$ z1 h7 s1 J7.一个php文件中可以存在多个命名空间,第一个命名空间前不能有任何代码。
只说第一个命名空间前不能有任何代码,之后的命名空间之前可以有代码。这个自行测试即可。
  1. //name.php
    . n7 E4 C9 ?5 [' w: p

  2. 8 N" E9 s7 U. }2 F
  3. namespace test;0 A% @  j3 v7 ~
  4. echo 'zhai14';/ d6 S5 Y9 ]/ j, }+ S
  5. namespace zhai;5 ]( k! [' a% B) s0 e
  6. require './1.php';
复制代码
: u' U3 s. u/ G( s% `' q! }; }
php命名空间namespace告一段落了,接下来说说use的用途。
使用use的目的:
在命名空间字符串过长时,使用use可以相应的缩短命名空间。
! t* ^5 G. [) s# d4 z+ F% T) T  F
use的使用方法:1.new类时,最前面无需用反斜杠。此外,use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。+ W6 m9 |, [9 F6 v
  1. //name.php
    " f; |6 r; _7 V9 F* v9 j
  2. ( t( L" N# b8 i1 e; U0 Z" c% V
  3. namespace animal\dog;3 @( H5 F/ z' J$ [

  4. ( D# }( A5 A2 {5 R" Q
  5. class Life{
    7 a: V3 }+ \9 n* _  ^' y: t
  6.     function __construct(){5 O2 z9 h: r% k
  7.             echo 'dog life!';6 ~1 w# n0 G$ a' R
  8.         }) g9 x5 K1 I/ l& v: B! ^8 A/ Q
  9. }
    - r: T; J! o7 u

  10. + D7 W7 J0 I9 b7 c. W( ^& v0 q& A
  11. namespace animal\cat;( ?- ~& Z4 i/ x" T, |4 r$ {, Y

  12. 3 l8 ~+ R2 c  {7 F! k4 U
  13. class Life{9 H( _* o# w" J
  14.     function __construct(){  ^" s" @0 j+ h% p9 g' ?
  15.             echo 'cat life!';: W& q9 N4 c. D/ \: H& S/ I* ^
  16.         }
    $ _! A& [/ x' M' v  Z7 P  N, L
  17. }8 |! P1 G- G9 L8 t4 K* o
  18. 0 ~' n- h3 h; v1 H' a
  19. new Life();  //按照代码执行顺序,这里默认animal\cat这个命名空间2 w1 J* `7 X( n# W2 C
  20. new \animal\dog\Life();  //A
    ! n# _% E! F" R- o; E
  21. $ |3 [: B& f: a# s/ X* N' ~
  22. use animal\dog;  //a
    4 `1 G8 i7 A% d. J
  23. new dog\Life();  //B
    9 U: T( ?$ a. U* z9 \$ G

  24. 0 _7 Z4 d7 N. f' v
  25. use animal\dog as d;  //b
    + h3 v, F  y$ g* k3 ~' h2 ]
  26. new d\Life();
复制代码

- K) L, T/ s% `: n1 x7 y
通过A、B行代码比较,需要注意:
使用use后,new类时,最前面没有反斜杠。
没使用use时,命名空间最前面有反斜杠
& {4 r' Q9 `* e$ }& w/ u4 F$ C, |& _
通过a、b行代码比较,可以理解:
use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。如上的:
  1. use animal\dog;
复制代码
1 W# \& G( }0 @( [! R
相当于
  1. use animal\dog as dog;
复制代码
: a0 e8 S6 ~; a$ D
2.namespace后面不建议加类名,但use后可以。8 @! K# Q3 j' o; S3 u, o7 n
  1. //name.php
    & f3 x  `" @; y

  2. / {& C" s5 z1 E+ Y' d
  3. namespace animal\dog;/ k% _  N1 g& m" S6 Y

  4. 6 z8 X* q( M7 K8 H1 j9 U% n
  5. class Life{
    0 N/ T: Q3 ?; i# O: s* r
  6.     function __construct(){3 G' Z& z7 k4 x/ a5 N! d, |
  7.             echo 'dog life!';6 G3 Y( g3 p& v' [! }
  8.         }
    5 Y; }5 O. y6 Y7 n; {8 r
  9. }
    % y1 u/ m4 O/ B2 c/ _. Y
  10. : m9 e  Q& r, `, ^) d8 ]) ]
  11. namespace animal\cat;
    , k: h* c: q7 j  g8 i  @# W' h
  12. ( k% j& ]- m5 l: V7 A1 v3 l
  13. class Life{' y4 h: _: h* e  Z/ c: j, J3 p; c8 G
  14.     function __construct(){
    % t" @  Y# e3 u1 f
  15.             echo 'cat life!';
    . C  l  z9 a/ V$ f
  16.         }: D& N  X6 m2 P  r1 s
  17. }  X. l( Z  k+ d6 t, Z5 M4 b% K

  18. ! B+ O8 m2 Z7 F. Q6 R
  19. use animal\dog\Life as dog;  4 U2 o8 d0 Z6 m# Q0 `/ W
  20. new dog();
复制代码

; g+ z  }7 q% W. `3 n2 P9 A
如上所示,use后加上类名后,就相当于把类改了个名称:由Life改为dog了。
上面不用as dog就会报错:
  1. Fatal error:  Cannot use animal\dog\Life as Life because the name is already in use
复制代码
: `2 q; h$ q' L% q
因为cat下也有个一样名称的Life类。
可以理解为,使用use后,这个昵称对应的类只能归当前命名空间占有,其它命名空间下不允许存在该类。
  1. //name.php4 S0 ]: u3 s, a, c; x

  2. * S6 b+ _! C8 n+ j
  3. namespace animal\dog;
    ; _/ o/ b' S1 W  c) i

  4. , n4 Z) s" k6 x0 k- C
  5. class Life{
    ) {; O0 }) }# P4 N5 E- S5 {; b
  6.     function __construct(){0 @+ J+ D7 B, o) s1 B* O' }
  7.             echo 'dog life!';
    $ O/ ?7 N1 I* B( ]5 w) I
  8.         }
    2 A6 y# X! f5 |1 p. C/ O! f. A0 I
  9. }
    , x' }6 `- Q  D' d, [
  10. class Dog{
    % p; [8 Y6 l  _
  11.     function __construct(){( K* ?4 g0 b! d% ^7 K
  12.             echo 'dog in dog!';
    / J' c( _3 V7 ^) d4 {
  13.         }
    1 S5 E. i7 c9 B) V6 d% J
  14. }
    / N3 `5 L( \7 @2 `& j

  15. : D$ W4 v3 _* v6 A7 Y  z& X5 s. I7 X
  16. namespace animal\cat;
    + g; M- ]( U* z8 @
  17. , J7 E8 m) y/ ]5 W. E3 A# [. t  k
  18. // class Dog{: z1 e- x+ Z+ F6 p# {0 k2 x: F7 _. @
  19. //     function __construct(){
    / z) B& S+ U. [: g7 {  B: A7 F
  20. //             echo 'dog in cat!';
    / C# s, `8 u3 x! x; z9 w; H
  21. //         }' K. f2 r1 B; A: B4 F
  22. // }
    ; Q# r: Q0 T6 n
  23. class Life{
    ; j  u& i/ ?# W1 A
  24.     function __construct(){) t2 W# B* S. J$ V% X% {
  25.             echo 'cat life!';: J* E" G# ?- P# M. y
  26.         }- r) S" S& _/ Y4 n  D; s
  27. }
    + _' x) R8 U- D! k$ C7 q
  28. $ j! U0 s& k% {9 V
  29. use animal\dog;  ; n8 J$ J* y% g. C9 Q  s( }, I
  30. new dog\Dog();
复制代码
0 R# g, z% ], [' ]  [
如上,使用了
  1. use animal\dog;
复制代码
8 s( Y' w( l! p# {  t; o0 Z
cat
通过上面代码,我想使用use的目的效果(缩短命名空间名称)就很明显了。
# M) T& H3 ~' t/ ^
简单总结一下:
namespace就是划分领域的作用,代表这些东西是属于某个命名空间下的。
use就是起小名的作用,不论写起来还是说起来都可以省不少事儿。

. m, O# M4 k- W$ p$ @4 A2 ^
5 o9 P* l$ G. Z" L% [
/ d/ y* n" d& q3 G, ?$ k( i' B  i) ^4 A
- ]! q# n2 T5 b, ?
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-3-17 18:10 , Processed in 0.059509 second(s), 20 queries .

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