cncml手绘网

标题: PHP命令空间namespace及use的用法实践总结 [打印本页]

作者: admin    时间: 2020-7-1 23:37
标题: PHP命令空间namespace及use的用法实践总结
以下皆为本人自我理解内容,如有失误之处,请多多包涵。
% \! q7 R6 T; Q5 _
文章大纲:
使用namespace的目的
namespace的使用方法
使用use的目的
use的使用方法
  w$ h" L1 a" C7 W; D  K" L0 @8 E- q

3 u( k( |- ?! [! `. B使用namespace的目的:
团队合作项目时,避免与团队其它成员新建的类发生冲突;个人负责项目时,避免前后新建的类发生冲突;

' O) _8 u7 T: m
据个人理解,用到所需要的类时,需要先require或include引入,所以会发生类重定义的错误的前提是:两个相同命名的类都有被引入。目前有些php框架会自动加载(即include)所有新建的model类,所以为了避免你新建的model类和项目框架原生的核心类发生重名冲突,采用了namespace。(想了想,与团队成员新建的类产生冲突应该通过沟通避免,即使事发后也应该重新调整类名即时维护,避免后期造成因为对类的理解混淆而带来维护上的复杂度提高)
9 e/ J% y/ j- V$ W& q' A$ B/ z" V
结合使用方法来进一步理解它的使用目的吧。
( J5 G3 E  p3 z* d1 t

) E- @# m/ {' Z# o0 knamespace的使用方法:
为了进行测试,我将创建3个文件:1.php和name.php(此文件用来执行测试),后面将不再说明,请自行注意代码的变化。
1.namespace后命名的定义不区分大小写
  1. namespace one;- M' H% r; {9 b6 B& [) O$ V
  2. namespace One;
    : T9 B, s1 _7 V( q( _
  3. namespace ONE;
复制代码

+ x+ i: b" X6 \$ m4 ^! g
如上写法都可以,选择一种作为自己的规范即可。(后面代码我采用第一种进行测试哈)
" v1 H- u( a' }+ T
2. 没有定义命名空间,就理解为使用顶级命名空间。new类时,可以在类前加上反斜杠\,也可以不加。
  1. //1.php   $ l" M( O6 Q' b$ I  Z! G( _
  2. class Person{
      v2 [2 F. P5 N/ c
  3.     function __construct(){0 D5 D2 v8 i* J* U2 J1 W/ E' y$ @
  4.             echo 'I am one!';$ F- ]4 P8 |  Q( g; h
  5.         }7 }! J' a; ]5 s3 ^7 ~8 l- G
  6. }
复制代码
  1. //name.php, G( P5 |1 O- l8 k! J+ x6 b
  2. require_once './1.php';7 Q7 n4 \& ^1 A8 o3 R( W6 j. M

  3. ( j+ l# b6 w2 {+ W. O  E" y/ l
  4. new Person();     //输出 I am one!;: |  p2 l3 X0 o5 Q7 f2 }/ _! v
  5. new \Person(); //输出 I am one!;
复制代码

$ l& ?6 l: |/ X+ l0 M3. new类时,带上命名空间时,之间一定用反斜杠字符,而不是顺斜杠。
记忆方法:按找%中斜杠的顺序理解为顺斜杠。(有时说反斜杠,自己都不知道是哪种方向,以前按自左向右上升方向这种方向记忆,现在感觉这个太不靠谱了)
  1. //name.php* V, _. Q, Y! P
  2. require_once './1.php';
    4 \6 w: Z- y% Q7 c' e( o) h5 ]8 q
  3. new /Person();  // 代码报错:Parse error: syntax error, unexpected '/'
复制代码
" h: M* T6 b0 b1 L) }6 Q& H
4.类在指定命名空间下, new类时,一定要带上指定的命名空间。
没有带上指定的命名空间,按照第2点,php就会从顶级命名空间里找这个类。切记:这里不能按照顶级命名空间包含一切其它的命名空间来理解。而应该将顶级命名空间完完全全与其他命名空间区分开。
  1. //1.php   
    4 _- r! g6 S( G, ^- |. l
  2. namespace one;
    # A( W( B: Z( v# v( }  [9 k, |
  3. class Person{  B  J8 j- l! o7 N. D
  4.     function __construct(){
    : i0 i3 j2 t6 h- q, S0 Q6 M# s
  5.             echo 'I am one!';
    0 l% p, f$ U7 I3 ~# }9 Y3 Z. i8 E
  6.         }( z/ [( q/ m% g3 }1 h# M  I0 D9 v
  7. }
复制代码
  1. //name.php! I. K& r9 c, Q4 r2 v2 s
  2. require_once './1.php';& W- B: E/ I4 C  H
  3. new \one\Person(); //输出 I am one!;& I, z4 Q$ m0 N
  4. new \Person(); //代码报错:Fatal error: Class 'Person' not found
复制代码
) |3 V1 q% ]6 p/ a8 G
可以举个这个通俗例子来理解:带上指定命名空间代表某人的苹果(在他手里),顶级命名空间代表苹果箱里的苹果(在箱子里)。现在要找某人的苹果,就将某人的命名空间带上,否则就会从箱子里找某人的苹果,结果当然是找不到。

$ M6 O% k! ?8 l- R5 w0 Z$ z9 R5.命名空间声明后的代码便属于这个命名空间,即使有include或require也不影响(重点是对后半句的理解,具体看代码)。
) s5 Z) K! Q3 r& T
  1. //1.php   
    " D/ x( H( f+ Y' q+ r6 K
  2. namespace one;4 r- n- e% J1 c9 ^2 m8 {
  3. class Person{# s( o: ]( M/ ]9 ]
  4.     function __construct(){
    8 X. t- u9 l; l+ j) X
  5.             echo 'I am one!';! n  M; I: T& t7 ^! q$ j
  6.         }/ c3 }& V" f7 Z7 }; w
  7. }
复制代码
  1. //name.php: M5 n; z) i/ _) ^2 F
  2. namespace test;  R* y) E3 q; s5 g* }; Z1 ^
  3. require './1.php';
    , ?& f4 b  p. E7 K& ~5 N
  4. new \one\Person(); //输出 I am one!;
    2 N  \+ ~8 w3 B- \! R
  5. new Person();      //这里结果会是什么呢,猜猜看- F6 R& x/ {- t+ B" Q/ k+ c
  6. 最后一行结果报错:
    7 P' g2 C. P5 D# F+ C6 N' `5 L8 z
  7. Fatal error:  Class 'test\Person' not found
复制代码

+ C- Q) O1 ]# I4 m
$ _" R5 P6 R, \/ }
首先,这里与第2点比较一下:
第2点,我说,没有命名空间时,new类时,有没有反斜杠意义一样。
在这里,有了命名空间,有和没有反斜杠的意义就不一样了。
最后一行换成
  1. new \Person();
复制代码

3 \8 p8 y9 p4 O, P
结果报错:
  1. Fatal error:  Class 'Person' not found
复制代码

' u3 M, o4 \7 e
接着,就说说当前这点。
我们可以发现,最后一行代码对应的命名空间为test,并没有受到require文件里的命名空间的影响。
进一步加强验证,我修改了name.php文件如下:
  1. //name.php+ b6 W; V! H! \+ _# ]; d% Y4 S0 j
  2. namespace test;
    , ]! N: ?% s( S9 n1 R& ]
  3. require './1.php'; 6 Z+ `& H& L6 t9 n6 d

  4. 2 B* d8 Q3 z8 M" w
  5. class Person{
    ) Y" G' H7 Q% U
  6.     function __construct(){
    0 V# }3 @. K, q6 H# f7 p8 M% F) A  u
  7.             echo 'I am test!';  x+ E1 x" Z9 d/ `* I! _
  8.         }0 Z0 b( O+ s; M. N. E) J
  9. }
    ! G* ^* T6 y. H( e$ M' ^( r

  10. 6 a! W& S3 }) o9 ~" p/ B, f; D
  11. new \one\Person(); //输出 I am one!;$ B  ?4 O' G. V8 f
  12. new Person();    //这里结果会是什么,自己猜猜看
复制代码
3 ?9 z& E6 F# r
最后,这个例子刷新了我对require的认识了。
按照我以前对require的理解:PHP 程序在执行前,就会先读入 require 所指定引入的文件,使它变成 PHP 程序网页的一部分。所以我常常就简单的理解为替换,只不过把抽离出来的代码再放回原处而已。然后我试了将1.php文件内容放到name.php里:
  1. //name.php
    2 t! B7 n! Q* ~) R4 N  @
  2. namespace test;  _) o* k, l7 k; v
  3. namespace one;3 o; [0 @0 j" y. K( Q& }
  4. class Person{
    8 ^  K' x8 k0 \9 ^( D, |7 t
  5.     function __construct(){6 X# r$ u& E  \" f* S/ ]# A
  6.             echo 'I am one!';
    & P! n3 D4 C" b/ c, ~
  7.         }
    ( Z/ Q5 n  }7 L; d0 y* _8 v
  8. }
    ; A7 t; d3 r( D) g$ Y# V2 a* R
  9. 4 i- n4 R4 d( x6 p& F3 y
  10. class Person{
    8 ?7 Y7 H0 A4 L  i5 c& K) @. H
  11.     function __construct(){2 G* j6 S) _% j) @2 T5 \. e% K
  12.             echo 'I am test!';  j2 J( `3 z5 ~2 Y$ R: X
  13.         }
      s& o5 Q( o1 h& Q& A& t% }
  14. }
复制代码

& k8 i% h9 m3 I0 y4 L4 V3 U
无需new类,该文件就会报错:
  1. Fatal error:  Cannot redeclare class one\Person
复制代码

" _$ U" }# j2 I* Q( y8 x
看来简单的把require理解为替换,在这里行不通。

' |+ j  H, U! A( e" N% ?6.namespace里不包含类名称,即使存在与类名称同名的部分,那也不代表类。new类时,还是得将这部分带上。0 A3 a: m0 k4 Q% R2 O8 J' t
  1. //name.php
    ( O+ A, l2 V6 O5 n" a3 B2 j6 ]# {
  2. 8 L7 e" C5 B" z' f  ^
  3. namespace test\person;$ K7 Q+ m6 U, @, t
  4. & y. z# Q! g: a- K  ?$ t
  5. class Person{( u3 }/ G- a8 m* a, h5 F; y- u; m
  6.     function __construct(){
    ! j% \5 i$ z8 ~4 N5 i) `
  7.             echo 'I am test!';
    * [1 M5 O+ u2 X
  8.         }* @, X* _* M4 Y% V  b, r
  9. }
    4 f4 [3 Q# P3 V1 R1 V: m
  10. new \test\person\Person();  //命名空间里person无法代表类名
复制代码
3 y: z  K) q% v
不过这样纯粹是画蛇添足,直接干脆点,namespace里不要带类名称就好。

# k. n) T# i% l. B" V. X7.一个php文件中可以存在多个命名空间,第一个命名空间前不能有任何代码。
只说第一个命名空间前不能有任何代码,之后的命名空间之前可以有代码。这个自行测试即可。
  1. //name.php
    ; C5 j" F4 M/ E3 L; R/ q# @

  2. : P! v" a; M8 F; r1 Y& W
  3. namespace test;, t& W3 P" V7 q  y
  4. echo 'zhai14';
    - O( r4 }' ~. v# E5 p
  5. namespace zhai;
    . y2 ^, M3 m$ b7 A- n! ~: s
  6. require './1.php';
复制代码

4 u+ E8 d/ m& D. g. f2 p, P
php命名空间namespace告一段落了,接下来说说use的用途。
使用use的目的:
在命名空间字符串过长时,使用use可以相应的缩短命名空间。
3 b9 }" k$ P4 S. B6 C2 A4 h
use的使用方法:1.new类时,最前面无需用反斜杠。此外,use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。* ]8 Q. c! {( I* ?8 f; T% I
  1. //name.php8 B. M3 N+ [( p& \
  2. : v! f0 |3 d. I* I8 m: @
  3. namespace animal\dog;
      G* N# l9 w$ s7 \4 \/ G

  4. ; q8 H( X9 i( m2 a8 ~8 \: v' z
  5. class Life{9 l! h: {4 C+ d3 u1 P* O/ d
  6.     function __construct(){8 e1 W- ~; h3 T
  7.             echo 'dog life!';
    6 T7 B- `. \' |" S* Q. t8 q
  8.         }
    1 N/ t$ V6 w6 s; Z8 p1 n
  9. }
    9 m7 O9 }0 a# i2 a
  10. 1 t4 i: L3 r7 A/ e- J
  11. namespace animal\cat;' U$ _) o6 |" m" W/ M

  12. ! t6 `+ p$ W4 u; J% d
  13. class Life{' Q9 Q5 w+ Z. t: \1 |) t3 Q
  14.     function __construct(){7 N' ?6 h; p- |% q
  15.             echo 'cat life!';
    ' n+ `1 p3 |- ~, L. I  k
  16.         }% O- Q5 w+ C2 ?/ n& o- }2 X$ u& |
  17. }
    ( d. L2 d  u+ d" R+ Z

  18. 7 H+ \  ^. _: o6 t
  19. new Life();  //按照代码执行顺序,这里默认animal\cat这个命名空间0 c, p' e/ |# R3 Q: B
  20. new \animal\dog\Life();  //A
    $ y- l$ B, p1 N9 A

  21. 8 ?- K& v* m- u0 N0 i
  22. use animal\dog;  //a& }& _/ q% M: _: O/ A4 ~; u
  23. new dog\Life();  //B: H9 {% n3 l" i$ H
  24. 2 H( S4 D! h2 ?1 x0 k& U
  25. use animal\dog as d;  //b
    ; D' O$ {  O: N7 E
  26. new d\Life();
复制代码

  E# [4 q4 S% Q  v" Y
通过A、B行代码比较,需要注意:
使用use后,new类时,最前面没有反斜杠。
没使用use时,命名空间最前面有反斜杠

' V0 ]9 P/ N6 N! g" b& ]* f
通过a、b行代码比较,可以理解:
use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。如上的:
  1. use animal\dog;
复制代码
/ A. n  ^' d* N. S8 Y  L7 E
相当于
  1. use animal\dog as dog;
复制代码

, t. R: D; i( Y2.namespace后面不建议加类名,但use后可以。
' N7 j/ A+ s( h
  1. //name.php
    : {+ W- L  x( l& ?5 H7 [) H
  2. ( [% p8 O- y; _; {; P/ X
  3. namespace animal\dog;$ V; W4 `. \6 @- D+ a6 E

  4. * f7 P% I6 @3 ?  Y$ v
  5. class Life{
    + j/ u7 H$ b2 x: ~! R1 \' F
  6.     function __construct(){
    - ~5 \3 L" Z1 f3 w7 |- ]+ D' }
  7.             echo 'dog life!';/ G, |4 r1 G" R8 v5 y
  8.         }
    - u# M4 y/ t$ C7 R; O% i+ V1 z
  9. }! V+ x+ _: Z8 L* E0 n6 w# X& F0 `
  10. ) B9 |- w' V3 B5 A7 L- v( v
  11. namespace animal\cat;
    ' m) ^' [- w5 e9 f
  12. " U& m! F. z6 q
  13. class Life{/ Z* y; U. ^4 `
  14.     function __construct(){  J$ u. `4 R8 Q1 U8 m7 ^. H; c
  15.             echo 'cat life!';
    9 \% o5 }7 }" L1 ^
  16.         }0 w, k2 H8 x* L! y6 o3 E9 G7 D5 @3 T
  17. }; v& _/ @7 u9 W) H" ]/ O7 Y& p2 Y
  18. . Y+ d, X. ]) R8 f: K( l
  19. use animal\dog\Life as dog;  ; z# Q6 x# P$ z$ n2 S
  20. new dog();
复制代码

5 I5 K8 }; L6 Q) J0 J+ N
如上所示,use后加上类名后,就相当于把类改了个名称:由Life改为dog了。
上面不用as dog就会报错:
  1. Fatal error:  Cannot use animal\dog\Life as Life because the name is already in use
复制代码

+ Z+ R, ?; T3 M' Q% J$ j$ S' g: K& w) C
因为cat下也有个一样名称的Life类。
可以理解为,使用use后,这个昵称对应的类只能归当前命名空间占有,其它命名空间下不允许存在该类。
  1. //name.php3 Y+ y+ ]; \' l) r) o  x8 v) I

  2. 2 F2 u/ X( v* a
  3. namespace animal\dog;+ [/ v; T* S! w

  4. 7 N$ z/ K8 \3 {3 g& |; G8 z
  5. class Life{' O* p' y$ w. ]! a  M. K( T
  6.     function __construct(){% H7 J9 f. b7 l
  7.             echo 'dog life!';7 p( K; s" p. {
  8.         }
    ( `% W% u. S  h+ B3 I: H7 F* H3 o
  9. }
      v6 x+ ?# v1 o7 G2 `! v
  10. class Dog{& ^. R& }% t3 z& a! O  q
  11.     function __construct(){
    6 f' z- H- O$ d0 K2 R% v: B
  12.             echo 'dog in dog!';
    7 Q$ g5 ^) o# @* t8 \
  13.         }* {- r1 R+ z& }4 Q
  14. }
    % g# X% H+ g$ C/ Z- e" U5 R$ a
  15. 8 o1 l) e) u3 O( C, |( B' p
  16. namespace animal\cat;- P6 F* y. p& P) r1 h! K; P: a
  17. ) u/ d6 X9 I+ B7 A1 ]9 s$ R
  18. // class Dog{
    & l9 V6 |6 z+ G# X6 ?
  19. //     function __construct(){
    + Z. b. H1 s" g: c$ o
  20. //             echo 'dog in cat!';
    . c9 K* V& _) n5 g! P/ W* r
  21. //         }2 o3 {; o7 J( P3 M" d7 X
  22. // }
    8 c! b5 \' Q' q- x
  23. class Life{' S: h/ y' K$ Z# r% R4 A; b  D  _0 J
  24.     function __construct(){
    3 K8 |1 e/ X1 N; r1 W# y
  25.             echo 'cat life!';/ j3 j, n' q+ Q8 _
  26.         }
    / N) P1 H, G# c, Q" d  J
  27. }
    , X% q6 }% Y) M9 W

  28. : |. E7 ?4 U9 I+ H( W5 [- Y
  29. use animal\dog;  8 o' c! F& J& ?. @. R) T
  30. new dog\Dog();
复制代码
+ O8 D8 A0 b) J1 z9 X# D/ U% ]' T
如上,使用了
  1. use animal\dog;
复制代码
5 d  A% `# w" d5 b% @+ J
cat
通过上面代码,我想使用use的目的效果(缩短命名空间名称)就很明显了。
+ g. `; U( p+ ^, ~, G# v0 C
简单总结一下:
namespace就是划分领域的作用,代表这些东西是属于某个命名空间下的。
use就是起小名的作用,不论写起来还是说起来都可以省不少事儿。

& D6 ?+ J' ^0 n. r+ D4 N% M) G" K3 M! t' V
2 ]2 F! F; q- Q( f9 p
* ?' R( G6 S& ]; J8 M! N% W
9 F! d( J6 ]2 [





欢迎光临 cncml手绘网 (http://cncml.com/) Powered by Discuz! X3.2