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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

! ?! {+ a& x  X' [! t) G) |- S, s0 a
文章大纲:
使用namespace的目的
namespace的使用方法
使用use的目的
use的使用方法

  M. j) s- @3 B4 O# U
' R; j( H. k- b使用namespace的目的:
团队合作项目时,避免与团队其它成员新建的类发生冲突;个人负责项目时,避免前后新建的类发生冲突;
+ R( w* U/ \1 }5 h4 V3 f
据个人理解,用到所需要的类时,需要先require或include引入,所以会发生类重定义的错误的前提是:两个相同命名的类都有被引入。目前有些php框架会自动加载(即include)所有新建的model类,所以为了避免你新建的model类和项目框架原生的核心类发生重名冲突,采用了namespace。(想了想,与团队成员新建的类产生冲突应该通过沟通避免,即使事发后也应该重新调整类名即时维护,避免后期造成因为对类的理解混淆而带来维护上的复杂度提高)

* B, {; S' {2 d* D7 }$ `! q- b2 A结合使用方法来进一步理解它的使用目的吧。
' l+ ?4 r2 |" k# p/ S

. i* W: `; T8 B( a9 h8 ~4 o! bnamespace的使用方法:
为了进行测试,我将创建3个文件:1.php和name.php(此文件用来执行测试),后面将不再说明,请自行注意代码的变化。
1.namespace后命名的定义不区分大小写
  1. namespace one;
    - u8 f- Z3 k8 A; \4 t0 P
  2. namespace One;
    3 x- @% T& H3 P( s# N" `
  3. namespace ONE;
复制代码

6 {8 u5 ~% I1 v' J, g* I
如上写法都可以,选择一种作为自己的规范即可。(后面代码我采用第一种进行测试哈)

8 V# @& S( a: z9 j2. 没有定义命名空间,就理解为使用顶级命名空间。new类时,可以在类前加上反斜杠\,也可以不加。
  1. //1.php   
    8 y8 R& U2 E1 c% H# y- Z; D3 ]. `
  2. class Person{& L' _4 b% n5 p. P; g
  3.     function __construct(){3 s/ F: O- S, E2 f5 Y" \
  4.             echo 'I am one!';+ [0 e3 z' ]2 z0 d" B; y$ f5 r
  5.         }; A1 t- n* L5 m9 i# W
  6. }
复制代码
  1. //name.php
    & z0 K8 q7 I/ U7 q4 [) N+ ?
  2. require_once './1.php';" c$ I' J* r. t0 _! p  o

  3. . ?+ i7 T7 ~- ~1 m# M
  4. new Person();     //输出 I am one!;
    $ S* Z& W/ N1 C2 I
  5. new \Person(); //输出 I am one!;
复制代码

. ^2 Q( |/ o: O% [) s2 P' r8 L3. new类时,带上命名空间时,之间一定用反斜杠字符,而不是顺斜杠。
记忆方法:按找%中斜杠的顺序理解为顺斜杠。(有时说反斜杠,自己都不知道是哪种方向,以前按自左向右上升方向这种方向记忆,现在感觉这个太不靠谱了)
  1. //name.php8 U4 r/ j* ?( s# {& `) L9 Z' G
  2. require_once './1.php';$ S( H2 r6 _$ n) X; D1 g
  3. new /Person();  // 代码报错:Parse error: syntax error, unexpected '/'
复制代码

) J# `) p; k4 z# j8 i4.类在指定命名空间下, new类时,一定要带上指定的命名空间。
没有带上指定的命名空间,按照第2点,php就会从顶级命名空间里找这个类。切记:这里不能按照顶级命名空间包含一切其它的命名空间来理解。而应该将顶级命名空间完完全全与其他命名空间区分开。
  1. //1.php   9 Q, c) U% b7 s) S  Y% W8 O0 V
  2. namespace one;4 l7 v) ^  f2 P% Y  @* Y
  3. class Person{
    ! ?3 n( _, k. [1 ^4 I9 W: O
  4.     function __construct(){; }% [) y: Z  c' o. W4 {, c2 d
  5.             echo 'I am one!';% g- l' l8 d5 K+ T  t
  6.         }8 }  s+ m9 Z' n- k( s9 l
  7. }
复制代码
  1. //name.php7 j9 j8 x" ^3 T, B& _( Y  U
  2. require_once './1.php';
    8 p- a& T8 j3 U7 X' b
  3. new \one\Person(); //输出 I am one!;
    * b7 F7 w( `* F4 _2 Y/ N
  4. new \Person(); //代码报错:Fatal error: Class 'Person' not found
复制代码

0 k/ N% E9 @$ ~
可以举个这个通俗例子来理解:带上指定命名空间代表某人的苹果(在他手里),顶级命名空间代表苹果箱里的苹果(在箱子里)。现在要找某人的苹果,就将某人的命名空间带上,否则就会从箱子里找某人的苹果,结果当然是找不到。

9 D( B4 H4 a: n  k5.命名空间声明后的代码便属于这个命名空间,即使有include或require也不影响(重点是对后半句的理解,具体看代码)。
5 X6 c2 B5 h' q; y
  1. //1.php   ( Y! i% ~. b+ Z! R# k
  2. namespace one;
    % z$ z, [5 G- o7 H' v, X5 d/ s, C
  3. class Person{, V9 A1 O$ w! N. l' w6 O/ g6 |! T1 c
  4.     function __construct(){
    " L, i3 h: H% R" `. F8 l+ D/ g
  5.             echo 'I am one!';
    & x# f/ a5 ^4 c% I# L' v( q: s" \( V
  6.         }
    % x# u5 c) j6 r+ Y' Z
  7. }
复制代码
  1. //name.php; X" P  E; d/ m, V
  2. namespace test;
    - w5 a1 }: x' j/ p4 Y( q5 G
  3. require './1.php';
    + g# M+ T4 B" C, e: _3 u
  4. new \one\Person(); //输出 I am one!;
    ( B% L' V4 o% W. j1 N
  5. new Person();      //这里结果会是什么呢,猜猜看9 ?0 ]! X! m! q- _
  6. 最后一行结果报错:( z  k6 i% |7 E- u3 R
  7. Fatal error:  Class 'test\Person' not found
复制代码
1 e0 @/ Y0 w+ m5 g! e8 R) X; u
4 [( O8 U4 ], `" J; }6 C- U- s% |% K
首先,这里与第2点比较一下:
第2点,我说,没有命名空间时,new类时,有没有反斜杠意义一样。
在这里,有了命名空间,有和没有反斜杠的意义就不一样了。
最后一行换成
  1. new \Person();
复制代码
  F: A* `, L& o, ]; X( ]
结果报错:
  1. Fatal error:  Class 'Person' not found
复制代码

6 F" X: q8 @5 W1 W  e  x( }; }
接着,就说说当前这点。
我们可以发现,最后一行代码对应的命名空间为test,并没有受到require文件里的命名空间的影响。
进一步加强验证,我修改了name.php文件如下:
  1. //name.php( |$ Y3 C( D6 k
  2. namespace test;
    + {1 r# ^  f7 @! f6 |
  3. require './1.php'; 4 b: n  S: T. z  y5 ^+ ]
  4. & x! |( [8 m4 o4 l' Q8 K% x
  5. class Person{
    # ~& f' W$ a0 L% g
  6.     function __construct(){
    ( `* D* H4 C" W2 f" E' D" O
  7.             echo 'I am test!';
    1 s4 }$ ]: L5 c# C1 Q
  8.         }% n; B% ]+ n! q
  9. }
    ) h/ n: s- O) W. Y

  10. 1 h5 |3 a! C+ v' q0 C
  11. new \one\Person(); //输出 I am one!;
      p( \/ `9 e* p* ^) v% z
  12. new Person();    //这里结果会是什么,自己猜猜看
复制代码

1 Q+ `1 y+ F+ b# U( j& w
最后,这个例子刷新了我对require的认识了。
按照我以前对require的理解:PHP 程序在执行前,就会先读入 require 所指定引入的文件,使它变成 PHP 程序网页的一部分。所以我常常就简单的理解为替换,只不过把抽离出来的代码再放回原处而已。然后我试了将1.php文件内容放到name.php里:
  1. //name.php
    / s. F3 q+ A; S; G3 \/ W7 p2 Z
  2. namespace test;7 ?6 V- T0 s5 I7 B9 a5 j5 G! P0 x
  3. namespace one;
    7 I: f4 f& a% B- Q% H4 j
  4. class Person{
    % i, w. k2 ]# T- R, c% q6 F4 w
  5.     function __construct(){. A, p& t. M  K& H+ u  A6 a
  6.             echo 'I am one!';8 M0 }& ]9 t6 w; |! d/ M' O
  7.         }* v/ T2 E: i7 m9 i
  8. }8 q- v# i7 ~  k, j3 t. T& g# q

  9. 0 _( d8 ^# W2 o& k& f7 z7 s3 ]- q: W
  10. class Person{5 Z0 x) o8 {: A2 z9 K* o+ O9 h- v: o
  11.     function __construct(){
    ! u5 u3 X5 p, j+ a& @6 e8 X
  12.             echo 'I am test!';* {3 Z8 N' j$ E  q  M' f! z" f
  13.         }: Z' p% G0 H& O, l+ S1 J3 `3 M
  14. }
复制代码

/ ]; [- K8 R0 R4 _  B! v& F
无需new类,该文件就会报错:
  1. Fatal error:  Cannot redeclare class one\Person
复制代码

7 e4 H" K8 ?4 P) @
看来简单的把require理解为替换,在这里行不通。

2 d( S9 N# ^: u6.namespace里不包含类名称,即使存在与类名称同名的部分,那也不代表类。new类时,还是得将这部分带上。+ Z  `0 G6 z2 I5 ^$ u, i
  1. //name.php- {# T, n* J! r3 {+ f9 ~7 }& N% |5 e
  2. + f7 ?# e; }( B1 M1 D
  3. namespace test\person;# Q: `9 L. t+ P. O  _
  4. 2 b3 s3 L2 ^; _4 c9 N: Y' a
  5. class Person{2 `3 U* a+ f& b# ?  m" \
  6.     function __construct(){
    7 r5 M8 L9 `5 F3 O7 D
  7.             echo 'I am test!';% D1 G, ^  G! K. w
  8.         }+ s* l) p/ W3 E6 l& g% f. Y
  9. }
    / R# M" g1 `5 G) D* ~. q/ [
  10. new \test\person\Person();  //命名空间里person无法代表类名
复制代码

; H& m8 ~2 f4 i1 ~4 w
不过这样纯粹是画蛇添足,直接干脆点,namespace里不要带类名称就好。
- Z$ V- G) O, E5 N( g8 l& J+ K& v5 j
7.一个php文件中可以存在多个命名空间,第一个命名空间前不能有任何代码。
只说第一个命名空间前不能有任何代码,之后的命名空间之前可以有代码。这个自行测试即可。
  1. //name.php
    7 I& c/ p! l% }& Q

  2. * M7 P- Z% D) Z; O1 L
  3. namespace test;
    4 M# o5 _7 r, Y( f8 i
  4. echo 'zhai14';
    5 K3 F- K$ t) I+ ^1 z4 R
  5. namespace zhai;
    3 ]% B0 |. p% e
  6. require './1.php';
复制代码
* P# F4 W' T% T4 v9 d
php命名空间namespace告一段落了,接下来说说use的用途。
使用use的目的:
在命名空间字符串过长时,使用use可以相应的缩短命名空间。

  v! V$ ]% ~1 E% j8 ?; Duse的使用方法:1.new类时,最前面无需用反斜杠。此外,use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。
! A! R0 P- S  \9 t, N2 i2 t
  1. //name.php1 H8 t; @0 [( d. [! t
  2. + B" q! R: E7 M5 D) [$ W
  3. namespace animal\dog;
    # B- l  C8 A- T$ A8 q6 r2 {7 d
  4. ! N/ _3 |5 z: D  `
  5. class Life{# Y- {, i: `* F% m7 Y3 c1 ]
  6.     function __construct(){
    2 h* g7 W! f* e# _2 [
  7.             echo 'dog life!';
    0 M1 T  |) ^( w" h2 e0 w- E
  8.         }0 b, o) L3 z$ X% v# \
  9. }: O1 u1 C! {+ P% I9 \. q

  10. : z6 ?$ k' u+ ?) I% @' j. _
  11. namespace animal\cat;3 `4 O. O& M2 h1 O! v
  12. # p6 b/ P; c! R) l: ?" O
  13. class Life{
    : A+ W: z! V6 r5 t* Q1 ^# ]" G
  14.     function __construct(){6 p# d% }3 |$ i' {
  15.             echo 'cat life!';
    4 @# h% U% ~; E7 g9 E
  16.         }/ ^1 n6 e" |8 g& p% w3 m
  17. }
    & g' {9 A1 V# |
  18. " i& R& b& P2 [5 \3 p- z
  19. new Life();  //按照代码执行顺序,这里默认animal\cat这个命名空间
    ; }2 @, L* n. Y; `9 u7 n+ U
  20. new \animal\dog\Life();  //A
    6 D! R4 M; L9 q4 }: I+ z
  21.   Z  U5 H" Y' z% C- b* ]
  22. use animal\dog;  //a
    4 w/ |9 E' V+ r% Z1 B. p7 x
  23. new dog\Life();  //B
    / Q- T5 q& F/ D  n6 [

  24. + q+ `0 D6 v* e0 p- D, e
  25. use animal\dog as d;  //b
    , f9 y& Z8 |  G/ h' t9 S/ n( Y
  26. new d\Life();
复制代码

+ a/ m! l  I6 `/ z- O. s
通过A、B行代码比较,需要注意:
使用use后,new类时,最前面没有反斜杠。
没使用use时,命名空间最前面有反斜杠

' u+ ?0 m/ v$ m" _
通过a、b行代码比较,可以理解:
use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。如上的:
  1. use animal\dog;
复制代码
% _! S9 |; B2 R5 |4 S: C- B
相当于
  1. use animal\dog as dog;
复制代码
* K+ X; U, j/ s/ R7 y
2.namespace后面不建议加类名,但use后可以。
& L6 u: y4 }2 R4 E: P4 R
  1. //name.php
    3 b! F" [: Q# j) L( Z% \/ M$ B0 u

  2. ; d3 o) l: R, T6 ~) ]: F6 u1 K$ l
  3. namespace animal\dog;/ j4 ^# P! W9 n8 f" c2 e

  4. , N  C3 r' J8 I* u, b. o: f
  5. class Life{4 t8 ~; L" S( Y" T* d
  6.     function __construct(){& q3 ^; H4 V6 Q: J
  7.             echo 'dog life!';# y# v6 b7 r5 S5 @5 L7 m  V3 A
  8.         }
    $ G/ ]" ?0 z6 z% q( Q+ c. z0 @
  9. }
    # }# @; o8 ]: t- H. Q9 c0 n  u
  10. % a3 @' H# q, x$ {( Z3 X
  11. namespace animal\cat;* g; {" l$ _2 ]  L3 H$ Z

  12. 9 ?* G& H, u2 F! h
  13. class Life{5 A; S0 p: {. a: v: x5 C
  14.     function __construct(){
      P' }) I; C+ K  o# ?0 I; p! m& ]
  15.             echo 'cat life!';3 f/ W, y( n3 [3 e( I5 g
  16.         }6 f2 R! C# K, H" y
  17. }/ z% [3 v" d( M3 O8 l
  18. ' I& Y# s. Q6 R
  19. use animal\dog\Life as dog;  
    9 `2 q5 }6 ?; V" p1 o
  20. new dog();
复制代码

6 z# M, c+ [6 m, P( q, N( \# `: W
如上所示,use后加上类名后,就相当于把类改了个名称:由Life改为dog了。
上面不用as dog就会报错:
  1. Fatal error:  Cannot use animal\dog\Life as Life because the name is already in use
复制代码

0 L/ B5 z9 ~! r: S
因为cat下也有个一样名称的Life类。
可以理解为,使用use后,这个昵称对应的类只能归当前命名空间占有,其它命名空间下不允许存在该类。
  1. //name.php
    1 b5 R9 b) r8 P$ U7 Q% v/ U
  2. 5 |" ], i; J- Q/ t
  3. namespace animal\dog;
    5 B6 L. Q2 e1 R- z6 o: T

  4. 5 f  t, r# Q7 u, P0 o
  5. class Life{) z" G" ^/ @, U# O% n1 \
  6.     function __construct(){
    $ g( r# s' L8 a9 n7 f+ Y7 w$ J1 o& D
  7.             echo 'dog life!';
    : L3 T3 g6 u2 A0 c3 b+ |+ ^! U+ ~# w
  8.         }6 ^7 @, e3 m( X2 v. z
  9. }
    - }9 W) S6 X7 O7 K* f
  10. class Dog{
    - R2 |4 C6 b, S; A, E+ y$ w+ I1 J
  11.     function __construct(){
    9 r. B2 S( O# K' K7 K
  12.             echo 'dog in dog!';6 l! t6 {8 {( Q  C! W3 B0 O* X
  13.         }9 f5 w8 g0 Z" q
  14. }. [1 s/ _, E5 f: K- a+ v
  15. " F% {4 U/ K* v
  16. namespace animal\cat;$ {; C0 U1 Q, _" M& P
  17.   y. z2 F$ ^3 L& l7 ]" q
  18. // class Dog{% r  Z; [. t0 Z/ d3 n
  19. //     function __construct(){
    1 r4 G! J5 p& N* [2 Z5 Z* v
  20. //             echo 'dog in cat!';
    # e' b$ C* a% b9 S& P$ x
  21. //         }8 \! f: l" e! c1 j  C; w+ ?: q) D
  22. // }- \/ z/ S+ w1 n' L. G
  23. class Life{5 e$ v5 s/ Q, [9 \% C; U9 e# v
  24.     function __construct(){
    2 |- b# p6 y9 T; j4 C0 S2 b- L: c
  25.             echo 'cat life!';; G8 M6 g, b; @1 ?9 R9 S% C
  26.         }
    , c, F/ R: C; P& A' s7 d0 Y; d
  27. }
    6 j1 \; Y' Q% r  y' I- j  `+ ?
  28. 1 X( T- G& C/ s. M  N
  29. use animal\dog;  % h' I; Y1 E- i0 r% _
  30. new dog\Dog();
复制代码

/ D% k: s& o% L0 s
如上,使用了
  1. use animal\dog;
复制代码
/ k! d# E0 D4 n/ R% }& [
cat
通过上面代码,我想使用use的目的效果(缩短命名空间名称)就很明显了。

, `) ^2 \. g9 g. g' ^* V
简单总结一下:
namespace就是划分领域的作用,代表这些东西是属于某个命名空间下的。
use就是起小名的作用,不论写起来还是说起来都可以省不少事儿。

# e& s, N' Y$ I  X& d% d! x! [* h1 Z) C! {) z5 \

/ V2 R% ]/ C2 L  `+ `; L7 d  S8 ~  h& ^; c! v

- ?5 f4 A7 y/ }, B# U0 A
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-9-21 05:21 , Processed in 0.060439 second(s), 19 queries .

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