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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2020-7-1 23:37:46 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
以下皆为本人自我理解内容,如有失误之处,请多多包涵。
1 z7 [. D$ `% ~! Q( M' w2 B
文章大纲:
使用namespace的目的
namespace的使用方法
使用use的目的
use的使用方法
: Q& x) L! L2 Y+ N7 N3 c: C! B
! I- y- X# `1 @) c7 @
使用namespace的目的:
团队合作项目时,避免与团队其它成员新建的类发生冲突;个人负责项目时,避免前后新建的类发生冲突;

( `# a( I* n' ~1 u5 o) f
据个人理解,用到所需要的类时,需要先require或include引入,所以会发生类重定义的错误的前提是:两个相同命名的类都有被引入。目前有些php框架会自动加载(即include)所有新建的model类,所以为了避免你新建的model类和项目框架原生的核心类发生重名冲突,采用了namespace。(想了想,与团队成员新建的类产生冲突应该通过沟通避免,即使事发后也应该重新调整类名即时维护,避免后期造成因为对类的理解混淆而带来维护上的复杂度提高)
0 T# g5 C" G1 M! _' ]
结合使用方法来进一步理解它的使用目的吧。
5 z! D# v5 {& D. D

$ K# c" i3 E' h5 s* B3 I1 Dnamespace的使用方法:
为了进行测试,我将创建3个文件:1.php和name.php(此文件用来执行测试),后面将不再说明,请自行注意代码的变化。
1.namespace后命名的定义不区分大小写
  1. namespace one;
    ! ]1 X) G! ^; N! z  ~% `9 `- N
  2. namespace One;
    # K5 c/ F" A" a
  3. namespace ONE;
复制代码
8 F/ p; s. u% _& |2 A
如上写法都可以,选择一种作为自己的规范即可。(后面代码我采用第一种进行测试哈)

! s" C! a; x2 ]5 b% }+ S2. 没有定义命名空间,就理解为使用顶级命名空间。new类时,可以在类前加上反斜杠\,也可以不加。
  1. //1.php   
    ) N/ s3 e, a3 x1 U% Q* ^& U" `
  2. class Person{
    " b5 }1 T4 t% d
  3.     function __construct(){
    $ X. s0 O3 K6 `! k, h+ v% S. J
  4.             echo 'I am one!';6 e$ x( T: S( k
  5.         }
    , I" B" G! C( K' `* r! m
  6. }
复制代码
  1. //name.php
    " x8 N7 X% W' d3 ?# N
  2. require_once './1.php';( B* T6 t" C; Y- m2 f! k3 K

  3. + i" o  s: V# I: h: D* u1 L
  4. new Person();     //输出 I am one!;
    $ b. h8 C6 I+ W* }$ K
  5. new \Person(); //输出 I am one!;
复制代码

' B3 a4 Y% f3 C. N8 N1 H9 O3. new类时,带上命名空间时,之间一定用反斜杠字符,而不是顺斜杠。
记忆方法:按找%中斜杠的顺序理解为顺斜杠。(有时说反斜杠,自己都不知道是哪种方向,以前按自左向右上升方向这种方向记忆,现在感觉这个太不靠谱了)
  1. //name.php
    ! }& c4 K5 ?( k9 s6 ?  d% s
  2. require_once './1.php';; t# {4 S# g+ p' S0 D1 a7 q) e
  3. new /Person();  // 代码报错:Parse error: syntax error, unexpected '/'
复制代码
7 v. p/ _; V+ b- ^9 K5 m
4.类在指定命名空间下, new类时,一定要带上指定的命名空间。
没有带上指定的命名空间,按照第2点,php就会从顶级命名空间里找这个类。切记:这里不能按照顶级命名空间包含一切其它的命名空间来理解。而应该将顶级命名空间完完全全与其他命名空间区分开。
  1. //1.php   
    1 R; ]8 T0 K2 r% B
  2. namespace one;' Z* M  b9 ^# V9 W% f/ |# G5 A
  3. class Person{+ S: W! ]- J5 n
  4.     function __construct(){
    ; H8 E2 ~2 D- v5 ~' E# I+ b+ ]
  5.             echo 'I am one!';6 o+ J$ w# w. X. N  w: u/ `7 L. B- ?
  6.         }
    ) D+ _# I6 [: w7 U8 Y: {
  7. }
复制代码
  1. //name.php
    * S+ C# O# y2 P$ ]2 I$ W6 \
  2. require_once './1.php';$ N. p8 [* V$ |5 {1 E
  3. new \one\Person(); //输出 I am one!;. a5 @4 G, O0 i5 P
  4. new \Person(); //代码报错:Fatal error: Class 'Person' not found
复制代码
) r5 Z  F" {/ O0 R9 m: f' X
可以举个这个通俗例子来理解:带上指定命名空间代表某人的苹果(在他手里),顶级命名空间代表苹果箱里的苹果(在箱子里)。现在要找某人的苹果,就将某人的命名空间带上,否则就会从箱子里找某人的苹果,结果当然是找不到。
4 W; A; s5 ~& S
5.命名空间声明后的代码便属于这个命名空间,即使有include或require也不影响(重点是对后半句的理解,具体看代码)。% X2 x. o) a1 x2 J# K
  1. //1.php   . {9 ?7 ^* g1 x& F
  2. namespace one;4 ?$ _4 K# U/ r. K5 Q# I  R) S& z
  3. class Person{9 i+ _% j3 D# j0 W1 r
  4.     function __construct(){3 |4 D( R2 p0 h3 d1 K! l
  5.             echo 'I am one!';
    + D2 m# `  o$ P8 d
  6.         }
    5 I7 M# V; u* I9 P( b
  7. }
复制代码
  1. //name.php
    * m  r0 p0 b( @. d0 I
  2. namespace test;" l! Q6 V5 f3 A1 d8 g8 k& m9 u" I
  3. require './1.php'; 2 l/ I- E1 g6 n% O( q  n
  4. new \one\Person(); //输出 I am one!;
    / q% J1 c) K# t8 B/ r
  5. new Person();      //这里结果会是什么呢,猜猜看
    0 e0 K4 y- F; b$ b& f# p& {
  6. 最后一行结果报错:' \8 d1 C- w" X5 N$ n" k7 ^! n9 ?
  7. Fatal error:  Class 'test\Person' not found
复制代码

# A9 N6 u9 F3 z5 o

& [$ Z% C' W/ j$ b0 i' y& i4 {首先,这里与第2点比较一下:
第2点,我说,没有命名空间时,new类时,有没有反斜杠意义一样。
在这里,有了命名空间,有和没有反斜杠的意义就不一样了。
最后一行换成
  1. new \Person();
复制代码

! H1 r. l7 N4 p- x% [
结果报错:
  1. Fatal error:  Class 'Person' not found
复制代码
5 h! z* Y" k0 g+ D. ]
接着,就说说当前这点。
我们可以发现,最后一行代码对应的命名空间为test,并没有受到require文件里的命名空间的影响。
进一步加强验证,我修改了name.php文件如下:
  1. //name.php
    6 c0 ]/ @, c- x5 x1 e; v
  2. namespace test;2 Z3 |% V: V/ n  f- u
  3. require './1.php'; : Q! g# T) {$ _/ T' M

  4.   K3 \) d  f9 S# j/ B
  5. class Person{
    ' i5 V( R8 S3 F) ~0 D5 x
  6.     function __construct(){+ ^2 @: g5 s' `4 s- Q
  7.             echo 'I am test!';8 ?" D' s% N. A: j1 i3 d
  8.         }& d5 Y/ d$ M: Z* B8 f. v) c  p
  9. }
    , Y/ V, U! t+ g9 t; v, e  K% W
  10. % c* U9 X, D8 C" G' _
  11. new \one\Person(); //输出 I am one!;
    ) R: r, {% k1 [% Y
  12. new Person();    //这里结果会是什么,自己猜猜看
复制代码
: f2 v  b" }1 z. x6 e& H
最后,这个例子刷新了我对require的认识了。
按照我以前对require的理解:PHP 程序在执行前,就会先读入 require 所指定引入的文件,使它变成 PHP 程序网页的一部分。所以我常常就简单的理解为替换,只不过把抽离出来的代码再放回原处而已。然后我试了将1.php文件内容放到name.php里:
  1. //name.php+ u% z9 \* w( h* _1 Y! U
  2. namespace test;
    ) c  w# u8 |5 ^' Y1 g4 g
  3. namespace one;
    8 [& H4 {! Z' D) S% O
  4. class Person{) b, T/ W: Z0 b$ C$ w1 \& q
  5.     function __construct(){- z6 P1 U" }# I! g
  6.             echo 'I am one!';, f" f+ q$ N& C
  7.         }
    # A. O6 _) e9 |' V
  8. }4 u% [7 v( h# N2 }
  9. # Y9 t% C+ n" d% |
  10. class Person{1 v$ I' g+ r. Z: L7 J8 G
  11.     function __construct(){
    # O' g! R6 T0 |4 x' F3 U2 o, M, B
  12.             echo 'I am test!';
    2 _: C- s) x& h
  13.         }' K! C9 F8 E3 s6 L  j' B1 N
  14. }
复制代码
( j3 e0 Z& ^2 U3 C
无需new类,该文件就会报错:
  1. Fatal error:  Cannot redeclare class one\Person
复制代码

, `9 ^) \5 v  |0 ?* _5 F) t6 B
看来简单的把require理解为替换,在这里行不通。

6 T6 T( {: v; a6 r6.namespace里不包含类名称,即使存在与类名称同名的部分,那也不代表类。new类时,还是得将这部分带上。
4 u0 {0 N8 \: e7 h* k
  1. //name.php
    $ Z% |% p. e( u4 B% _* P1 y
  2. : S* z( W& M9 o% o& s1 [# H
  3. namespace test\person;
    ) S0 m$ S! [- S; K
  4. . E# g5 s/ {! t: B1 c" t/ |4 \
  5. class Person{
    & I+ G; S& Q% ^
  6.     function __construct(){' ~/ W, Y9 _* ^. Y+ s. c
  7.             echo 'I am test!';# z' V; Y7 v! L! Y. O( Y+ p
  8.         }
    ( l7 {/ y/ G5 j3 |( Q
  9. }
    2 u7 t/ C$ ~. f4 N
  10. new \test\person\Person();  //命名空间里person无法代表类名
复制代码
! u/ v6 k& \7 d. w2 p1 p
不过这样纯粹是画蛇添足,直接干脆点,namespace里不要带类名称就好。

6 z% _" a0 |& u7 x$ \7.一个php文件中可以存在多个命名空间,第一个命名空间前不能有任何代码。
只说第一个命名空间前不能有任何代码,之后的命名空间之前可以有代码。这个自行测试即可。
  1. //name.php
    $ p( ^( k4 B( Y/ M
  2. 4 C6 W8 |8 N# m, P" Z
  3. namespace test;
    ) A/ u5 p. U' g' |% W) J
  4. echo 'zhai14';
    ( Z& k$ L: [7 \* \3 h
  5. namespace zhai;  f. t/ ~6 J  ]; X2 p
  6. require './1.php';
复制代码

- i$ k, `7 K$ z8 |+ Z
php命名空间namespace告一段落了,接下来说说use的用途。
使用use的目的:
在命名空间字符串过长时,使用use可以相应的缩短命名空间。

- F7 ~: B# n: A" Uuse的使用方法:1.new类时,最前面无需用反斜杠。此外,use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。% C' I" n& _8 T
  1. //name.php9 _4 j$ u( M  D+ q' C/ v3 B% v1 `% h

  2. . G( V! _# N+ \( B* `0 e
  3. namespace animal\dog;2 i0 G  V& n# N" ]
  4. : X. b/ S* P/ H
  5. class Life{! K  E8 l8 L! P6 C3 T
  6.     function __construct(){" H1 ?! s* Q& t0 I" }% C
  7.             echo 'dog life!';9 W3 r# M0 t9 u% y$ s& c' ^3 ~0 n
  8.         }
    ' P( f' ?! |5 r: G
  9. }
    ! X9 Q7 R# R' r. F! W/ k, m. g

  10. / E% }* W$ G/ D4 N- P( q; Z% l
  11. namespace animal\cat;( F2 {7 f- R: N$ o! {; Q
  12. 4 u! T0 k$ i! w
  13. class Life{5 Z, m3 Y+ \, V( c. q! ]
  14.     function __construct(){, \1 T1 O: C  V: y; P' e( r
  15.             echo 'cat life!';
    + g9 t6 _1 u8 z- B& _
  16.         }; ]5 |( E! N5 I9 S9 q  Y
  17. }
    & k/ y" E7 s. F% U: v
  18. & j4 Y# q1 K* d0 H1 l+ ~1 q: I$ L5 T6 N
  19. new Life();  //按照代码执行顺序,这里默认animal\cat这个命名空间
    8 D5 T/ d) p1 _$ m0 P- _
  20. new \animal\dog\Life();  //A
    9 ~5 ]: A" _6 H

  21. 9 ^" @" o; _" _/ `  @
  22. use animal\dog;  //a
    ' K$ j) U  x6 {/ w$ H
  23. new dog\Life();  //B
    2 k" ^; R  |% l  p' {

  24. 3 T$ u( B. e0 J, x
  25. use animal\dog as d;  //b/ q' \! K2 m& ^! p
  26. new d\Life();
复制代码
0 q5 T. r; Z6 [; b6 p& J
通过A、B行代码比较,需要注意:
使用use后,new类时,最前面没有反斜杠。
没使用use时,命名空间最前面有反斜杠
. [6 {" R" J1 p6 z% o
通过a、b行代码比较,可以理解:
use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。如上的:
  1. use animal\dog;
复制代码
9 }+ D# K. R1 @+ F. c! f8 S6 c
相当于
  1. use animal\dog as dog;
复制代码
. m) m: y, r# o5 y
2.namespace后面不建议加类名,但use后可以。
3 y/ S* [" P: l7 v) L: P4 r0 [
  1. //name.php
    6 p0 Q$ g2 i3 Y' W' G4 ~  r

  2. 8 J: ?/ f! c1 s
  3. namespace animal\dog;' D7 v0 B; K  J" P/ q# A
  4. / o& m  D! X3 B2 u7 w6 J) u
  5. class Life{  \6 G' O# U& V
  6.     function __construct(){
    0 W# d5 D0 A  _6 @' W
  7.             echo 'dog life!';9 O! q; @* z# S
  8.         }
    6 `% @1 X" C' g) C3 A# {# t. q
  9. }
    5 `7 j( I. P& f
  10. % {0 O. a; \, l: y6 o
  11. namespace animal\cat;
    ) l6 T, e+ M1 `4 f
  12. ' |; N+ r$ u; c
  13. class Life{0 h* I* m3 {6 ]
  14.     function __construct(){9 l' n6 C9 p" C8 X
  15.             echo 'cat life!';" J" Y% E: H- a( A0 Q: C. r
  16.         }3 r4 q/ I/ H4 P2 q
  17. }2 G' X- g/ C/ O
  18. & [- ~+ j, z- l5 W
  19. use animal\dog\Life as dog;  
    # @3 o$ w  F- l# I; i1 {
  20. new dog();
复制代码
. j9 _3 `& p5 n
如上所示,use后加上类名后,就相当于把类改了个名称:由Life改为dog了。
上面不用as dog就会报错:
  1. Fatal error:  Cannot use animal\dog\Life as Life because the name is already in use
复制代码
7 |' x( V# [6 c0 e
因为cat下也有个一样名称的Life类。
可以理解为,使用use后,这个昵称对应的类只能归当前命名空间占有,其它命名空间下不允许存在该类。
  1. //name.php# M9 ^# H* ]8 L3 f

  2. * P0 K- v/ n1 c& n1 Z" `
  3. namespace animal\dog;$ d- i8 T# N5 ?$ }: @- g

  4. $ [5 I& ]* \0 H$ s8 o
  5. class Life{
    6 u3 j- r4 v! k% ?# c
  6.     function __construct(){0 S) }& e/ d9 B. v
  7.             echo 'dog life!';
    0 `5 F# E( }3 w( ~
  8.         }1 y5 I, ^7 a6 U5 f+ E; [
  9. }6 X7 U/ i% n& f3 E4 t  A, S7 H
  10. class Dog{
    5 u. h/ ?5 e4 n# Y) K2 ~  W
  11.     function __construct(){  u  T* s- y& G- I% F2 F5 Y1 j
  12.             echo 'dog in dog!';( d9 x2 u" M  i7 q  T! O% e
  13.         }- i! [3 g) g. l! R4 U1 H# P
  14. }
    % G( b; ]$ m7 a3 _7 K$ C
  15. / @. J! s/ S% V* b
  16. namespace animal\cat;
    5 T9 ~- q% Z  T

  17. . Q" w+ l- }" L& B7 s# e! s
  18. // class Dog{
    ) H* A" a6 e1 A& c" A6 m) l* [
  19. //     function __construct(){
      Z6 }5 E* v1 }* @' J2 c( s
  20. //             echo 'dog in cat!';
    8 b; |" K( |" M1 a5 c
  21. //         }  T8 E& o# w$ N' O# Y% X/ l
  22. // }+ W6 J8 r3 R. D, n' K
  23. class Life{
    & f+ J* V% t/ t: L: [
  24.     function __construct(){6 r5 _0 v, E! U7 Q( ?
  25.             echo 'cat life!';1 @, g! N) b" x3 @7 W
  26.         }7 J( M7 e% t; R' S
  27. }
    . T# m0 B$ s; f+ d- z% n' X

  28. 6 S  W+ n. _4 ]/ }3 ]( h& u# T1 [
  29. use animal\dog;  
    * @2 }: {" V* P6 M, b7 A
  30. new dog\Dog();
复制代码
2 ]+ j7 X* O  w0 W7 ]) L8 k
如上,使用了
  1. use animal\dog;
复制代码

& j2 N: G$ f3 {  K
cat
通过上面代码,我想使用use的目的效果(缩短命名空间名称)就很明显了。
! N; w% R. Z: A: Q
简单总结一下:
namespace就是划分领域的作用,代表这些东西是属于某个命名空间下的。
use就是起小名的作用,不论写起来还是说起来都可以省不少事儿。
0 G+ D8 u2 t# Q; o+ K

+ L3 F6 W! [9 l! T+ d$ F: Q. H# O# d9 f/ u- @7 [/ m

+ X+ O$ }6 [8 _  c  U% X# Z( L3 _" m8 K4 M% s; j% q
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-6-19 22:31 , Processed in 0.053816 second(s), 20 queries .

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