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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 1537|回复: 0

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

[复制链接]
发表于 2020-7-1 23:37:46 | 显示全部楼层 |阅读模式
以下皆为本人自我理解内容,如有失误之处,请多多包涵。

* C1 K2 S9 d& C
文章大纲:
使用namespace的目的
namespace的使用方法
使用use的目的
use的使用方法

7 e, C' S' J: ?8 k; Y( x
9 V* d2 X2 [  j  r' |使用namespace的目的:
团队合作项目时,避免与团队其它成员新建的类发生冲突;个人负责项目时,避免前后新建的类发生冲突;
# x3 i; w$ |- S0 l2 w3 s8 Q( j
据个人理解,用到所需要的类时,需要先require或include引入,所以会发生类重定义的错误的前提是:两个相同命名的类都有被引入。目前有些php框架会自动加载(即include)所有新建的model类,所以为了避免你新建的model类和项目框架原生的核心类发生重名冲突,采用了namespace。(想了想,与团队成员新建的类产生冲突应该通过沟通避免,即使事发后也应该重新调整类名即时维护,避免后期造成因为对类的理解混淆而带来维护上的复杂度提高)

: e& K' B: A0 e4 X/ l* Q8 i结合使用方法来进一步理解它的使用目的吧。

# h8 I2 }1 R8 A  g' h- G/ E
3 K. v/ i4 o3 l3 C) lnamespace的使用方法:
为了进行测试,我将创建3个文件:1.php和name.php(此文件用来执行测试),后面将不再说明,请自行注意代码的变化。
1.namespace后命名的定义不区分大小写
  1. namespace one;
    6 G0 a; u1 {2 o+ c+ c; T4 V: k
  2. namespace One;
    ' o8 a. r* O5 {2 K* s  W8 q
  3. namespace ONE;
复制代码

! t$ [( B0 n  k" g5 N4 T( r
如上写法都可以,选择一种作为自己的规范即可。(后面代码我采用第一种进行测试哈)
3 W" Q% C3 @9 g2 G: m, ]0 r
2. 没有定义命名空间,就理解为使用顶级命名空间。new类时,可以在类前加上反斜杠\,也可以不加。
  1. //1.php   : ~8 z1 X6 N2 G5 w8 |# V% ~+ c* b
  2. class Person{
    , `/ T. q0 t% ]1 _9 N/ d
  3.     function __construct(){
    ' \' s% S) e( u2 O( k' f1 l
  4.             echo 'I am one!';
    , d$ @1 F2 ?) B
  5.         }# S! d4 w7 B7 G0 Z* Y( s) F8 t
  6. }
复制代码
  1. //name.php
    . g) Z3 ?" h0 ~# @% V
  2. require_once './1.php';
      N; v- q" X: o; w# A
  3. 6 q* @% Z) O2 f3 w$ m+ p( w& Z6 l8 o" g
  4. new Person();     //输出 I am one!;
    / a9 m6 _( ~" k: f: i
  5. new \Person(); //输出 I am one!;
复制代码

& G3 v  F- ?# V8 z3. new类时,带上命名空间时,之间一定用反斜杠字符,而不是顺斜杠。
记忆方法:按找%中斜杠的顺序理解为顺斜杠。(有时说反斜杠,自己都不知道是哪种方向,以前按自左向右上升方向这种方向记忆,现在感觉这个太不靠谱了)
  1. //name.php
    0 E, Q8 i% E* B. q7 x. Z1 e% e
  2. require_once './1.php';: j- q( \+ L! b
  3. new /Person();  // 代码报错:Parse error: syntax error, unexpected '/'
复制代码

$ Y" r( }+ o% j1 y7 {  X+ d! C3 |5 c4.类在指定命名空间下, new类时,一定要带上指定的命名空间。
没有带上指定的命名空间,按照第2点,php就会从顶级命名空间里找这个类。切记:这里不能按照顶级命名空间包含一切其它的命名空间来理解。而应该将顶级命名空间完完全全与其他命名空间区分开。
  1. //1.php   8 w  ~" C. a( E. t8 ]% {
  2. namespace one;
    9 X/ W" W2 ~! l* P2 b1 c: u
  3. class Person{$ M- U9 L' x( N" u3 v7 B- u* M
  4.     function __construct(){
    ( h, }5 z6 b4 H+ Z5 h- |  a1 ~) O5 {
  5.             echo 'I am one!';
    . J, U! B3 h% w7 H) |' |3 n
  6.         }
    # {2 e6 d2 n/ `# k) Y
  7. }
复制代码
  1. //name.php  k2 O9 B4 E4 ?8 O; e
  2. require_once './1.php';
    1 V) m0 M$ Q! P. ^+ p% h) w
  3. new \one\Person(); //输出 I am one!;' E+ C7 o, O- _- J$ I, u
  4. new \Person(); //代码报错:Fatal error: Class 'Person' not found
复制代码

6 V# K( j& x1 L* g. O. E% W
可以举个这个通俗例子来理解:带上指定命名空间代表某人的苹果(在他手里),顶级命名空间代表苹果箱里的苹果(在箱子里)。现在要找某人的苹果,就将某人的命名空间带上,否则就会从箱子里找某人的苹果,结果当然是找不到。

, X; R4 O/ G% K8 W5.命名空间声明后的代码便属于这个命名空间,即使有include或require也不影响(重点是对后半句的理解,具体看代码)。3 P3 z9 g! I2 Y) j
  1. //1.php   
    5 K& C& o( h( w; w, G
  2. namespace one;
    ' M8 [9 j1 a9 W4 z' T/ F' b
  3. class Person{
    % n. \1 `: G/ ~8 M( c# ]5 s
  4.     function __construct(){
    0 L( W" u: P$ r5 r' Q
  5.             echo 'I am one!';( j4 k& u* ~2 a) G* ]
  6.         }
    : w) s/ A( R( j: f
  7. }
复制代码
  1. //name.php
    4 J" Q- v: |# F; g& |; s8 m# B
  2. namespace test;
    ) q2 Z9 P  D. m, }. C# Y4 A9 V% W3 v! a
  3. require './1.php'; ) i4 W2 H6 o6 m
  4. new \one\Person(); //输出 I am one!;7 X" u; Q. |( q: n- ^: f8 S( m+ s
  5. new Person();      //这里结果会是什么呢,猜猜看- M6 K4 i5 V9 h- R5 P& t
  6. 最后一行结果报错:
    8 ~/ @5 W% o# J0 R
  7. Fatal error:  Class 'test\Person' not found
复制代码

6 _# m4 D- h) c* Q$ {
$ o. e+ Q, M1 K
首先,这里与第2点比较一下:
第2点,我说,没有命名空间时,new类时,有没有反斜杠意义一样。
在这里,有了命名空间,有和没有反斜杠的意义就不一样了。
最后一行换成
  1. new \Person();
复制代码

* g! M1 c; c. V& d7 c
结果报错:
  1. Fatal error:  Class 'Person' not found
复制代码

. y1 o6 S% ~' K9 x, G
接着,就说说当前这点。
我们可以发现,最后一行代码对应的命名空间为test,并没有受到require文件里的命名空间的影响。
进一步加强验证,我修改了name.php文件如下:
  1. //name.php
    & Q- N5 f1 ?) j+ _/ m
  2. namespace test;
    & R+ ~( R6 K; f# z0 t
  3. require './1.php';
    9 d- \  r" @6 O& u% U

  4. # ?$ \. H' X4 F
  5. class Person{
    5 z" b; Y  O3 |
  6.     function __construct(){: x. g( W2 f- r# l' a0 R# Y
  7.             echo 'I am test!';
    . s  u5 w, B* s: u
  8.         }
    0 ~2 E( h) o0 v1 L
  9. }
    6 A( y- z; p# x( G

  10. % F$ |9 K5 y$ X5 o: _4 J7 D
  11. new \one\Person(); //输出 I am one!;& t" d0 ^/ N; I' u
  12. new Person();    //这里结果会是什么,自己猜猜看
复制代码

/ X$ F) }. T& {$ M, S& a
最后,这个例子刷新了我对require的认识了。
按照我以前对require的理解:PHP 程序在执行前,就会先读入 require 所指定引入的文件,使它变成 PHP 程序网页的一部分。所以我常常就简单的理解为替换,只不过把抽离出来的代码再放回原处而已。然后我试了将1.php文件内容放到name.php里:
  1. //name.php  `1 b- v6 \! T7 _( F& ?
  2. namespace test;, W" ~$ M$ z$ c; C9 d3 k
  3. namespace one;
    + f$ A: [, K7 J) Q* Y6 r/ E; B
  4. class Person{
    % F1 L6 j# k' b# s. m
  5.     function __construct(){
    . ^$ ?# c: f! C/ V5 B
  6.             echo 'I am one!';3 e( X" L: B4 y7 s) d
  7.         }5 O, ^7 g: m7 k' V+ F
  8. }
    7 H4 a# Q; r2 P0 t7 O
  9. 3 Z6 E& S0 V) g0 K$ R+ l
  10. class Person{
    ! Z6 j. ~4 L9 j7 b
  11.     function __construct(){7 L) @! {. @" m2 e& o1 r3 s
  12.             echo 'I am test!';! s& {9 ~0 u4 s0 J
  13.         }
    ( m& S; M- Q- F
  14. }
复制代码
9 k0 b/ _6 m5 t0 d3 p" j& L
无需new类,该文件就会报错:
  1. Fatal error:  Cannot redeclare class one\Person
复制代码

2 n& t% B7 f6 O9 ~& h; s5 b
看来简单的把require理解为替换,在这里行不通。

" i" ?* U2 N# A2 S/ r6.namespace里不包含类名称,即使存在与类名称同名的部分,那也不代表类。new类时,还是得将这部分带上。
* K7 i) e4 }& w+ D$ t' a  m
  1. //name.php% u, M- L* G# f
  2. 1 E: Y& k  U1 b! q, x+ Z. s
  3. namespace test\person;
    $ p& [9 ~/ ~7 E& w0 q- W8 |; z1 S" u
  4. ; O3 b( l2 }+ ?4 _3 o6 c1 J
  5. class Person{
    - x5 i, G1 e; `4 Q& S
  6.     function __construct(){- Y  @# Y% R& w6 j4 ?
  7.             echo 'I am test!';* k% K( f: C2 Z; t& u9 T
  8.         }
    * H$ s0 m; Q* E
  9. }
    1 C$ D+ d% P' A1 o& p1 S
  10. new \test\person\Person();  //命名空间里person无法代表类名
复制代码
  ~' x- L4 Z4 c! K  s
不过这样纯粹是画蛇添足,直接干脆点,namespace里不要带类名称就好。
$ ~9 I' E9 N% u
7.一个php文件中可以存在多个命名空间,第一个命名空间前不能有任何代码。
只说第一个命名空间前不能有任何代码,之后的命名空间之前可以有代码。这个自行测试即可。
  1. //name.php
    : g( w/ \, j* }
  2. - a7 `$ U' p" |
  3. namespace test;( |1 G+ v- H' z* N0 `1 G- K
  4. echo 'zhai14';4 Q/ I, L) a' o9 h% r' H$ O
  5. namespace zhai;2 A8 ?: u( O2 |% w- ]4 l4 ?
  6. require './1.php';
复制代码
; K8 B  s) r7 a! D8 L1 ]6 c
php命名空间namespace告一段落了,接下来说说use的用途。
使用use的目的:
在命名空间字符串过长时,使用use可以相应的缩短命名空间。

, |! j& i' ]7 n% ^use的使用方法:1.new类时,最前面无需用反斜杠。此外,use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。
1 ~# Y5 s, r' U: [$ B
  1. //name.php
    / n6 |- a. N& q% J
  2. 9 C- {( m3 e9 i. W) T
  3. namespace animal\dog;
    - k8 ^( ?. Y7 S. S

  4. 6 E' x& d0 v* d# E
  5. class Life{9 S) W3 l7 ^; b( n
  6.     function __construct(){9 k; }! f  I8 M/ P  X- T" Y
  7.             echo 'dog life!';
    " ], p3 @/ \' z! G
  8.         }/ z  k, M/ k$ J2 c
  9. }
    ' q9 S0 M8 j0 v
  10. 5 y, z) J  G) i+ J/ ^% }
  11. namespace animal\cat;; }/ P! C; B8 o/ r  W
  12. 6 g% m6 J( K+ F
  13. class Life{  {/ A  c+ g7 M* \3 F1 N
  14.     function __construct(){
    ; o" a% B$ w  }( p8 p
  15.             echo 'cat life!';) Z7 w1 @) i6 f8 v
  16.         }
    $ ~% f! J& V* P, {( }: }
  17. }8 M3 V. L( j2 |3 y! A% Y. @

  18. ! Z+ p5 T9 M5 F/ ^8 B9 m
  19. new Life();  //按照代码执行顺序,这里默认animal\cat这个命名空间5 e; E  T9 W) G7 M5 I
  20. new \animal\dog\Life();  //A
    : {2 G7 ], U# x6 l: P. Q

  21. # T0 G& C1 f5 J- u/ _
  22. use animal\dog;  //a
    3 n$ K$ A8 W9 [% S- N! ~" m, H3 A
  23. new dog\Life();  //B+ k0 M' @( Y  I( @, ]" g: S

  24. ! E$ j7 h# A4 j& X4 H
  25. use animal\dog as d;  //b
    : x1 |" k- S: Q) ?
  26. new d\Life();
复制代码
6 \, M3 ~" B- g3 M& X' @( E* j8 [
通过A、B行代码比较,需要注意:
使用use后,new类时,最前面没有反斜杠。
没使用use时,命名空间最前面有反斜杠
2 R  A, S% `$ |# r- b' e8 B5 @
通过a、b行代码比较,可以理解:
use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。如上的:
  1. use animal\dog;
复制代码

) h. \( g9 \$ Q/ M: \3 K5 S5 l
相当于
  1. use animal\dog as dog;
复制代码
/ l! T( ]& B  }7 K7 W
2.namespace后面不建议加类名,但use后可以。# `" f5 L" w6 W" t
  1. //name.php6 b4 Q4 T" G7 P" L% m8 x# Y

  2. * B; _# F( E! z
  3. namespace animal\dog;
    8 [# t3 P; r' x" @& u! Y+ |
  4.   h5 X: ^! b1 ^
  5. class Life{
    8 `# t7 x0 h+ W* y& i- h! r4 K- s
  6.     function __construct(){
    ' T  {. [# f, L3 a
  7.             echo 'dog life!';% ]  N1 {- k) U( T
  8.         }$ M4 g0 [5 C# q
  9. }
    " O/ C7 b; c6 v. ~+ p5 _+ |
  10. ' M0 c9 X1 L1 t6 N% Q
  11. namespace animal\cat;
    3 T  c$ Y% f5 N/ ?. w9 `5 J) r

  12. ) ^2 q1 g# `4 ]; z( G
  13. class Life{5 T6 G' H* w/ C( e( m* n
  14.     function __construct(){2 Y& E1 H" v& J( _) g
  15.             echo 'cat life!';' b) l7 j6 H$ Z- V
  16.         }! }- |7 x6 ]! L% T
  17. }2 t* N4 U9 Z2 Y. T

  18. # H- ^* e6 o$ x' g2 W/ l* I
  19. use animal\dog\Life as dog;  * H* A" q" o! |) ]& Z7 B0 K2 H
  20. new dog();
复制代码
; x2 d+ W( x( V
如上所示,use后加上类名后,就相当于把类改了个名称:由Life改为dog了。
上面不用as dog就会报错:
  1. Fatal error:  Cannot use animal\dog\Life as Life because the name is already in use
复制代码

6 n5 h# S& F- }8 r5 h
因为cat下也有个一样名称的Life类。
可以理解为,使用use后,这个昵称对应的类只能归当前命名空间占有,其它命名空间下不允许存在该类。
  1. //name.php. _- q' w, G1 b; o& ^
  2. 3 {" a* F+ \8 P; w. h" v" `
  3. namespace animal\dog;* w& |6 U" f6 e. h

  4. + N7 G8 p& u" _$ |3 E1 `0 e6 x$ ]
  5. class Life{
    , R  X) ]% b# Z" v( w
  6.     function __construct(){
    ) T, g* l+ S  A$ {
  7.             echo 'dog life!';
    " c$ l" @4 t$ q! |  g  i3 U
  8.         }9 ], D# D' {& @9 r# |
  9. }
    & k0 Z  O$ I( M3 V1 C
  10. class Dog{" d' _# i# g* L& k1 d
  11.     function __construct(){
    / b& h0 |+ r  m" N8 c
  12.             echo 'dog in dog!';3 l* I+ e. y% J
  13.         }7 j& o5 W* J% H; w
  14. }
    6 b. ~) }( }7 n0 K! n3 d8 @

  15. 8 ~' }) ]3 I0 F! v* I) @7 t
  16. namespace animal\cat;" h  r. F2 f: [- a% Z; @

  17. 4 G! ~1 y" @5 k* ]3 X9 ~
  18. // class Dog{
    $ @# x8 i) g% [0 F
  19. //     function __construct(){" c; E7 p$ r5 T
  20. //             echo 'dog in cat!';
    # \* G2 E. {) e
  21. //         }: q1 z! B; o  u. Y# w
  22. // }
    - U; V. M" B# Y9 @6 q+ N
  23. class Life{
    " [& n4 ~: v  I( ?7 C  T
  24.     function __construct(){5 l* `6 P" Z1 h* c% U
  25.             echo 'cat life!';. n+ ]* C0 V- U. M$ O& D* g
  26.         }
    ( I& \" y# e3 z7 u# I
  27. }7 A/ O! E, v; Y4 ]3 N

  28. : }7 T- F$ ~. p( E9 \% ?2 N6 G- P+ x
  29. use animal\dog;  4 v) t) n* M  q+ A! v
  30. new dog\Dog();
复制代码

! e! ~$ I6 q% {$ ^" C
如上,使用了
  1. use animal\dog;
复制代码
& f2 R  g" L3 \" I% t$ D2 c
cat
通过上面代码,我想使用use的目的效果(缩短命名空间名称)就很明显了。

% y1 r$ X& s* J
简单总结一下:
namespace就是划分领域的作用,代表这些东西是属于某个命名空间下的。
use就是起小名的作用,不论写起来还是说起来都可以省不少事儿。
0 |5 U$ [/ X( L

* ~$ {1 W; W7 H" r! {
& O; i* Q" Z5 L( ?! |# J
/ X3 V: I1 W1 a5 q: k: e7 F: `# ~2 _7 Y3 M8 U# {
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2021-9-17 14:42 , Processed in 0.114323 second(s), 22 queries .

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