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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

: m% B. h5 }/ \/ T; h, r
文章大纲:
使用namespace的目的
namespace的使用方法
使用use的目的
use的使用方法

) M) E+ i1 G5 n3 E9 R+ ~; t1 f7 _  k0 E0 O% x
使用namespace的目的:
团队合作项目时,避免与团队其它成员新建的类发生冲突;个人负责项目时,避免前后新建的类发生冲突;
8 g6 H8 ~% l6 d# ^/ \: o& x
据个人理解,用到所需要的类时,需要先require或include引入,所以会发生类重定义的错误的前提是:两个相同命名的类都有被引入。目前有些php框架会自动加载(即include)所有新建的model类,所以为了避免你新建的model类和项目框架原生的核心类发生重名冲突,采用了namespace。(想了想,与团队成员新建的类产生冲突应该通过沟通避免,即使事发后也应该重新调整类名即时维护,避免后期造成因为对类的理解混淆而带来维护上的复杂度提高)

% O* t2 r+ q: [- G: m) i结合使用方法来进一步理解它的使用目的吧。
! h5 V6 [% H( x* u( }4 B

3 c9 n5 f' T6 R6 i6 z3 dnamespace的使用方法:
为了进行测试,我将创建3个文件:1.php和name.php(此文件用来执行测试),后面将不再说明,请自行注意代码的变化。
1.namespace后命名的定义不区分大小写
  1. namespace one;
    0 B3 Y6 J* C4 o$ M( |8 Q
  2. namespace One;% m# Q6 O' b" r* j
  3. namespace ONE;
复制代码
# i  a9 u! F& x, |+ K- @, ]* P
如上写法都可以,选择一种作为自己的规范即可。(后面代码我采用第一种进行测试哈)
% [; R3 M4 n) l" Q7 [% r
2. 没有定义命名空间,就理解为使用顶级命名空间。new类时,可以在类前加上反斜杠\,也可以不加。
  1. //1.php   : _+ B* V6 F$ r0 h% L3 g
  2. class Person{% `3 {) H, C  F4 H( Y* @, w
  3.     function __construct(){
    6 C- o6 \+ @. F
  4.             echo 'I am one!';
    ! g8 R- x! O5 r! j) {6 I3 M. `% _
  5.         }: z4 [9 G- ?- @8 b: x( l- [
  6. }
复制代码
  1. //name.php
    7 b: A2 R4 ^- c$ B- P8 D2 Z
  2. require_once './1.php';
    7 Q9 f* X1 M' j$ b: @

  3. 5 }) E* V& z) U6 O" S, K
  4. new Person();     //输出 I am one!;
    ( \1 H3 c5 T  u9 ^1 W3 S
  5. new \Person(); //输出 I am one!;
复制代码

& L; `, Z+ ^- W( C; T) t3. new类时,带上命名空间时,之间一定用反斜杠字符,而不是顺斜杠。
记忆方法:按找%中斜杠的顺序理解为顺斜杠。(有时说反斜杠,自己都不知道是哪种方向,以前按自左向右上升方向这种方向记忆,现在感觉这个太不靠谱了)
  1. //name.php; h% W3 \) R" X0 S- b
  2. require_once './1.php';
    " O/ ]; v6 e- v9 P- W4 n
  3. new /Person();  // 代码报错:Parse error: syntax error, unexpected '/'
复制代码

" Q4 Z3 ?4 x* {' |4.类在指定命名空间下, new类时,一定要带上指定的命名空间。
没有带上指定的命名空间,按照第2点,php就会从顶级命名空间里找这个类。切记:这里不能按照顶级命名空间包含一切其它的命名空间来理解。而应该将顶级命名空间完完全全与其他命名空间区分开。
  1. //1.php   3 Y+ [; q' o9 q$ ]8 c. z+ ?
  2. namespace one;: _4 V# W& x2 A, U  |
  3. class Person{1 f$ ]5 E$ w. G4 k4 {6 a  W
  4.     function __construct(){1 z. l/ M+ i. ^; Q$ q* u- S
  5.             echo 'I am one!';
    # q# B0 M# q- J$ i
  6.         }& r) [* \3 |- M$ Q, w: ^* C
  7. }
复制代码
  1. //name.php
    5 J1 ?4 k* y/ ?' p1 H" l% w+ Q) J( p
  2. require_once './1.php';
    - o9 d0 |5 o& V  ]4 U" i* g9 J
  3. new \one\Person(); //输出 I am one!;. O1 k- P' y# E4 p; u8 A' V7 }
  4. new \Person(); //代码报错:Fatal error: Class 'Person' not found
复制代码
4 ?: v) r, [' k9 u/ w
可以举个这个通俗例子来理解:带上指定命名空间代表某人的苹果(在他手里),顶级命名空间代表苹果箱里的苹果(在箱子里)。现在要找某人的苹果,就将某人的命名空间带上,否则就会从箱子里找某人的苹果,结果当然是找不到。

4 Z' b: ]: T- L" F9 T5.命名空间声明后的代码便属于这个命名空间,即使有include或require也不影响(重点是对后半句的理解,具体看代码)。
* d  o2 C- B2 U6 V  d' ^
  1. //1.php   % m4 L; K( ?2 g- ^. b% X
  2. namespace one;; H# G4 O% I. q/ l2 a' _
  3. class Person{
    ; j; u* n# U+ ]) M9 b8 q& h, P
  4.     function __construct(){
    # q3 K) B; I2 X0 o1 q9 g
  5.             echo 'I am one!';
    ) `$ V* @- u; |- ^' Z* Q" M) h
  6.         }
    * m" A0 b1 \1 l4 z; @  _+ _/ M
  7. }
复制代码
  1. //name.php- r5 Z: L( e0 b2 R8 |/ V+ m" V( {
  2. namespace test;' a; \6 G9 G- W
  3. require './1.php'; # ?! h% r2 e# M% x: \: J3 ^
  4. new \one\Person(); //输出 I am one!;
    4 a9 n( `* }& U. \0 B0 ]6 Q/ p
  5. new Person();      //这里结果会是什么呢,猜猜看2 k3 ?& K) M5 s6 |2 C
  6. 最后一行结果报错:  Y, `3 J3 N3 U  y7 g
  7. Fatal error:  Class 'test\Person' not found
复制代码

5 H6 {9 \" h% Y+ M$ w7 v" d8 N( @

$ X8 m/ p; A4 ]  ^4 M* e+ k8 ^3 H首先,这里与第2点比较一下:
第2点,我说,没有命名空间时,new类时,有没有反斜杠意义一样。
在这里,有了命名空间,有和没有反斜杠的意义就不一样了。
最后一行换成
  1. new \Person();
复制代码
* _" C+ E- \2 U- f8 l
结果报错:
  1. Fatal error:  Class 'Person' not found
复制代码

. ]& ^; N! h* T
接着,就说说当前这点。
我们可以发现,最后一行代码对应的命名空间为test,并没有受到require文件里的命名空间的影响。
进一步加强验证,我修改了name.php文件如下:
  1. //name.php0 R+ _% g) @2 F1 r# t( C
  2. namespace test;
    ! z  d( j. X; t% A+ i2 Y4 R, Y
  3. require './1.php'; * w% p4 ^( y) x9 ~3 k4 U
  4. , N$ R7 ]6 {+ R+ E& V0 b
  5. class Person{
    : \. d* F& @7 N1 o5 `( {
  6.     function __construct(){1 D2 x- a3 A4 l' n% E. b5 l' h- M3 W
  7.             echo 'I am test!';
    ) c* k  Q- H6 l, L5 }4 W
  8.         }* Z) H3 D6 W+ K( e7 q0 f# r" W
  9. }
    - p$ V3 a1 |- T( U& z( Y! u
  10. + y  q7 M" R! o% j1 O: ~
  11. new \one\Person(); //输出 I am one!;) R! I; v1 D: G( u0 L) J4 t2 i
  12. new Person();    //这里结果会是什么,自己猜猜看
复制代码
" p1 O/ X5 [% ^
最后,这个例子刷新了我对require的认识了。
按照我以前对require的理解:PHP 程序在执行前,就会先读入 require 所指定引入的文件,使它变成 PHP 程序网页的一部分。所以我常常就简单的理解为替换,只不过把抽离出来的代码再放回原处而已。然后我试了将1.php文件内容放到name.php里:
  1. //name.php7 |  ?6 P: B, a4 ~- A1 l
  2. namespace test;
    1 F" F$ q6 k. @7 v% n
  3. namespace one;+ ^) x8 \2 z: v, l$ m6 ~( D
  4. class Person{7 @: Z! H9 T% H* Z$ H* N* w7 t( ?
  5.     function __construct(){# t3 K- i+ W& \) F! U. \: B; z9 t
  6.             echo 'I am one!';
    7 h1 F' z( u7 z8 S# h
  7.         }
    5 L4 j! K: i# ?9 s; W/ W$ w
  8. }6 v/ U" `% O& n2 S
  9. 1 L/ j9 N5 Q. n7 r; g9 S; c
  10. class Person{' D9 H8 y. j. v
  11.     function __construct(){: x  @* m) w- h- l1 a0 Q5 n$ f
  12.             echo 'I am test!';
      Q% L5 k' K. }6 _4 |
  13.         }8 E! j/ ^$ F7 ^! k
  14. }
复制代码
6 R8 }3 C" i$ O
无需new类,该文件就会报错:
  1. Fatal error:  Cannot redeclare class one\Person
复制代码

$ Z! J* J5 D7 R
看来简单的把require理解为替换,在这里行不通。

4 M) U# Z; \. j  x- M6.namespace里不包含类名称,即使存在与类名称同名的部分,那也不代表类。new类时,还是得将这部分带上。
! |" o* `, i) c) R8 [
  1. //name.php" |: }( c8 Q% a  s
  2. 4 t! y; D7 O( `5 |( ^6 o
  3. namespace test\person;& V6 ]7 o* R4 o0 ^2 F9 T2 B( B: V
  4. . w5 a8 D. _# `0 L: d' ~
  5. class Person{
    $ Q$ u1 N- t: a% s, L& K9 B. J  ]' Y( A
  6.     function __construct(){
    # K' q3 J# \7 o
  7.             echo 'I am test!';
    , x# X" [7 C; T! X% E
  8.         }6 t2 d- P. J$ U: Y5 X8 y( C
  9. }7 S+ g- r# F/ `6 |1 b- p0 F9 g
  10. new \test\person\Person();  //命名空间里person无法代表类名
复制代码

; j8 ?, z1 A) S4 M
不过这样纯粹是画蛇添足,直接干脆点,namespace里不要带类名称就好。
, N' Y; R: y7 k3 f! S4 C- l
7.一个php文件中可以存在多个命名空间,第一个命名空间前不能有任何代码。
只说第一个命名空间前不能有任何代码,之后的命名空间之前可以有代码。这个自行测试即可。
  1. //name.php% S# `1 y$ c' `

  2. 7 g+ a; u" r0 c9 e  F# [/ x5 u
  3. namespace test;+ M9 U" P" I' g+ I
  4. echo 'zhai14';$ {. m. U) d. u8 z% e4 \
  5. namespace zhai;4 ]" c* Z. m! E4 P! u  a
  6. require './1.php';
复制代码
* P, J; ?1 J% W9 t# l% {6 s8 \& `
php命名空间namespace告一段落了,接下来说说use的用途。
使用use的目的:
在命名空间字符串过长时,使用use可以相应的缩短命名空间。

% C! f+ v2 b+ U: N& T- guse的使用方法:1.new类时,最前面无需用反斜杠。此外,use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。* H8 b, F. `$ Z5 `! i/ v" ^
  1. //name.php) B" J8 |1 r) U! B3 U) Z1 T, t' G) [

  2. 1 d+ @( s& c# g( P) }
  3. namespace animal\dog;/ A, N: r4 R6 `
  4.   R2 l1 B% R$ v; O, g, s) k
  5. class Life{
      F4 H) \2 ^9 p& a" g
  6.     function __construct(){  H2 T! O. n9 j( t+ C, u
  7.             echo 'dog life!';) P4 P" c% Y  e& }- l; a/ ]2 ^
  8.         }) }8 s8 f% U% I2 S! o3 D
  9. }: E- o  F4 a5 C& J9 P/ l+ H$ B
  10. & k1 N. F2 y. V5 o- M
  11. namespace animal\cat;
    4 w# e1 t2 O9 F+ z$ M* f# J

  12. / A/ x- O) T& H* t$ x; i
  13. class Life{
    ) ^; W" A; t: h, n* v0 y  d
  14.     function __construct(){  j7 C! E6 Z" q2 N
  15.             echo 'cat life!';; s0 h2 ^$ `3 v7 v' _
  16.         }0 f( x' V& l! X' \4 F  U( n4 m
  17. }
    , W1 Q% N- e# Y& `: Q
  18. : N% R4 `7 i2 e5 x% a; ]
  19. new Life();  //按照代码执行顺序,这里默认animal\cat这个命名空间
    ; q) w8 F7 b! C. f* T  q
  20. new \animal\dog\Life();  //A& d( b% T. ?1 \2 ?! m6 X8 Z; J

  21. " q& i# C" H' L& B/ j
  22. use animal\dog;  //a
    ; D  [3 Y# R2 |6 P
  23. new dog\Life();  //B6 g: a$ H3 S+ W( h1 L

  24. 7 b/ ~: {/ I7 W- p
  25. use animal\dog as d;  //b5 W' \8 e% ~' w/ c' V  H
  26. new d\Life();
复制代码
$ t/ V) A2 F* e
通过A、B行代码比较,需要注意:
使用use后,new类时,最前面没有反斜杠。
没使用use时,命名空间最前面有反斜杠

5 Z1 r; T( _8 v6 z! I- `% {
通过a、b行代码比较,可以理解:
use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。如上的:
  1. use animal\dog;
复制代码

% m4 Y6 H% h9 i. L8 ?  r/ W% L
相当于
  1. use animal\dog as dog;
复制代码
! Q  S. U- b. q1 K
2.namespace后面不建议加类名,但use后可以。) R2 V) {  l# P2 y% t, p+ b) s1 n
  1. //name.php. A7 z7 S+ w; ?

  2. % J* k: t0 B4 S5 z  z
  3. namespace animal\dog;$ d7 A7 v" a7 ~' T1 ?2 }

  4. 9 a! w# }8 i8 N4 M/ |) |
  5. class Life{! t) j% f5 r  I3 V6 B# A! ^+ q
  6.     function __construct(){) b5 ^3 }' u$ z5 _4 c! o
  7.             echo 'dog life!';
    4 b) y! I3 r: g9 r; M. n. {
  8.         }! f* Z: z; g( ^6 a5 c1 e
  9. }
    # P0 J, U- `0 Z0 [% e$ r
  10. , |3 j4 ?% U8 J2 C9 G
  11. namespace animal\cat;, S* J1 z$ s- z6 n+ u; q
  12. $ Q& ~% t* ]$ D
  13. class Life{0 p4 R) i& v0 n% ]5 e: F  K
  14.     function __construct(){2 M$ W+ E5 }- x* z/ {1 ^* S3 }. T" O
  15.             echo 'cat life!';
    * o$ F0 W+ ]( J) j0 q+ y0 V
  16.         }
    ! X; i1 [9 j. j% z5 {$ |
  17. }
    1 B# N1 o, K, c- j) l5 |8 u

  18. ' |" \) _7 q: Y- c  m" F5 s7 `
  19. use animal\dog\Life as dog;  ( g5 M9 S  R# [1 a
  20. new dog();
复制代码

2 ?% }% B6 k* b- D" Y' }! [
如上所示,use后加上类名后,就相当于把类改了个名称:由Life改为dog了。
上面不用as dog就会报错:
  1. Fatal error:  Cannot use animal\dog\Life as Life because the name is already in use
复制代码
- k% B  q. q. g% y
因为cat下也有个一样名称的Life类。
可以理解为,使用use后,这个昵称对应的类只能归当前命名空间占有,其它命名空间下不允许存在该类。
  1. //name.php9 V. o6 i  O( B" Y( q

  2. 6 m4 i) }- J' V! {: z; d1 @
  3. namespace animal\dog;0 `) K$ r/ c9 P' }, A

  4. % @5 N- y) f0 X5 S, V/ K
  5. class Life{: \. P7 T0 o1 ?8 P# J- U/ |
  6.     function __construct(){
    ( w7 K; r+ h% k4 g5 v
  7.             echo 'dog life!';( k% d( h. Y9 |4 I6 y  A6 {2 C
  8.         }
    & l5 V- A3 B$ [2 p0 w" Y. d
  9. }
    7 B3 a( g% X  u1 f$ B$ P5 X
  10. class Dog{; @9 U' C% g+ r( J4 L
  11.     function __construct(){" ?9 d" k  ^. k; h% [
  12.             echo 'dog in dog!';
    7 a& ~2 o1 ~- B& J+ R
  13.         }
    ( S! [$ K9 b$ D. c- s
  14. }, S! y, r% o, n0 v3 ?* n, e% o

  15. + D) I: P. a3 Z4 L/ Z0 y$ k
  16. namespace animal\cat;
    ! I" c' a2 J9 X: @- J9 L4 F7 k. ?
  17. 8 o. I  u- r/ z. e$ Q
  18. // class Dog{
    8 K9 L7 u4 F. Y, x6 [! X( H6 @
  19. //     function __construct(){% p( U* m# A4 F& `: f1 v( F9 L! v
  20. //             echo 'dog in cat!';
    $ Y6 v8 r6 N/ s' H
  21. //         }
    ! u2 i) I7 n: Z2 V
  22. // }' I, d8 Y6 ?* Z- F( ~
  23. class Life{
    0 x$ ?5 Q  ~, f4 W! |& b
  24.     function __construct(){+ {4 o7 i8 z' Z' e) ~
  25.             echo 'cat life!';
    , |' f* d# ~& |% z* P' ~
  26.         }
    4 k1 o2 Q6 N/ ]2 R
  27. }
    : i. _/ t  m9 I& V: B+ U
  28. + |" v) `" M' \4 p! u$ J
  29. use animal\dog;  ( @8 L7 Y' z+ S- }, [# M* t
  30. new dog\Dog();
复制代码
% U6 _8 V. _0 K4 ?( b
如上,使用了
  1. use animal\dog;
复制代码
! j( L" X2 }& J6 p; G
cat
通过上面代码,我想使用use的目的效果(缩短命名空间名称)就很明显了。
2 w0 e3 C  }5 h' |3 G9 L4 [
简单总结一下:
namespace就是划分领域的作用,代表这些东西是属于某个命名空间下的。
use就是起小名的作用,不论写起来还是说起来都可以省不少事儿。
5 g( w( e7 B+ S. B( l- B5 T
$ _- @  O2 B6 l, O0 Z+ |. E
- L! w0 n: c0 ~& w0 o
9 F- W. L" C- V# d7 L# P2 w
0 X+ V: U6 O0 U2 r/ O) B1 }% G
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-1-30 14:31 , Processed in 0.059406 second(s), 19 queries .

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