cncml手绘网

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

作者: admin    时间: 2020-7-1 23:37
标题: PHP命令空间namespace及use的用法实践总结
以下皆为本人自我理解内容,如有失误之处,请多多包涵。
" Y8 C3 P$ H8 _7 M8 r
文章大纲:
使用namespace的目的
namespace的使用方法
使用use的目的
use的使用方法
, P- u9 ~. n, l& n% I
3 t! m) I1 ~  G8 Y" N* ?1 A+ x
使用namespace的目的:
团队合作项目时,避免与团队其它成员新建的类发生冲突;个人负责项目时,避免前后新建的类发生冲突;
; B, R8 K+ o; d4 {: y" ~" n* m
据个人理解,用到所需要的类时,需要先require或include引入,所以会发生类重定义的错误的前提是:两个相同命名的类都有被引入。目前有些php框架会自动加载(即include)所有新建的model类,所以为了避免你新建的model类和项目框架原生的核心类发生重名冲突,采用了namespace。(想了想,与团队成员新建的类产生冲突应该通过沟通避免,即使事发后也应该重新调整类名即时维护,避免后期造成因为对类的理解混淆而带来维护上的复杂度提高)

. J2 s9 _# ]0 u结合使用方法来进一步理解它的使用目的吧。
7 t, g, V: Q- Y+ ^; C

& G) b! R1 E  I% G* ynamespace的使用方法:
为了进行测试,我将创建3个文件:1.php和name.php(此文件用来执行测试),后面将不再说明,请自行注意代码的变化。
1.namespace后命名的定义不区分大小写
  1. namespace one;
    & h6 h* P: ?7 R, ], H
  2. namespace One;- D8 R" I5 X, }8 P5 m$ Z) q& \2 V* S
  3. namespace ONE;
复制代码
# K7 N0 N4 |( N1 p3 K" G
如上写法都可以,选择一种作为自己的规范即可。(后面代码我采用第一种进行测试哈)

: J) |; e, c8 h& e2. 没有定义命名空间,就理解为使用顶级命名空间。new类时,可以在类前加上反斜杠\,也可以不加。
  1. //1.php   3 }0 k; p- r( Z" J, o
  2. class Person{
    / C& K" S! g! k' W/ ?& e
  3.     function __construct(){
    * x$ s; t" N: G' R' ~
  4.             echo 'I am one!';5 P% A6 R1 J6 L
  5.         }
    : N. J/ ~# e- l+ {4 ?
  6. }
复制代码
  1. //name.php4 \/ s/ v) ?5 O2 t1 t) I
  2. require_once './1.php';4 i3 a0 B: ~* S( Y3 E

  3. 0 z$ ~3 s; @3 |$ T9 r& u9 O; u
  4. new Person();     //输出 I am one!;% C0 G+ w2 V  B4 o
  5. new \Person(); //输出 I am one!;
复制代码

+ ]+ V* h2 @* g7 x4 @4 z9 O4 J% ^3. new类时,带上命名空间时,之间一定用反斜杠字符,而不是顺斜杠。
记忆方法:按找%中斜杠的顺序理解为顺斜杠。(有时说反斜杠,自己都不知道是哪种方向,以前按自左向右上升方向这种方向记忆,现在感觉这个太不靠谱了)
  1. //name.php
    5 v: k/ f  j* K9 M# X
  2. require_once './1.php';6 j+ T( L: d. D! [, i
  3. new /Person();  // 代码报错:Parse error: syntax error, unexpected '/'
复制代码

$ S) l4 c9 t, C7 Y7 G' `/ L; `. S4.类在指定命名空间下, new类时,一定要带上指定的命名空间。
没有带上指定的命名空间,按照第2点,php就会从顶级命名空间里找这个类。切记:这里不能按照顶级命名空间包含一切其它的命名空间来理解。而应该将顶级命名空间完完全全与其他命名空间区分开。
  1. //1.php   
    # k" f$ K2 m0 b! f7 f7 Z
  2. namespace one;
    ' H: t( `1 i2 _  K
  3. class Person{
    ) S( A/ {& u6 D% d
  4.     function __construct(){7 U5 g- y, U2 M8 [2 F9 J. u/ j
  5.             echo 'I am one!';, a! e+ a6 d) i2 @4 _/ E" R
  6.         }6 }# c# X* W- u7 y
  7. }
复制代码
  1. //name.php8 O* \9 Q+ Z% c9 B) r
  2. require_once './1.php';; F; u0 ^6 }$ @1 ?- u! E; s, q6 ?
  3. new \one\Person(); //输出 I am one!;3 z) J0 S, a- T; X
  4. new \Person(); //代码报错:Fatal error: Class 'Person' not found
复制代码

4 P: I, w9 A+ c- _5 e0 C4 K7 {+ |/ o
可以举个这个通俗例子来理解:带上指定命名空间代表某人的苹果(在他手里),顶级命名空间代表苹果箱里的苹果(在箱子里)。现在要找某人的苹果,就将某人的命名空间带上,否则就会从箱子里找某人的苹果,结果当然是找不到。
' N9 M' k; o1 A$ I1 C3 C8 _6 B" [
5.命名空间声明后的代码便属于这个命名空间,即使有include或require也不影响(重点是对后半句的理解,具体看代码)。3 g2 J) |& D1 h- W2 {
  1. //1.php   9 X! \* `, _# o1 N8 E6 Z2 i
  2. namespace one;8 S! N- I+ H2 K7 A4 D
  3. class Person{
    ! R5 c- R3 F9 |( G8 `" d
  4.     function __construct(){2 e1 E8 M9 b6 P, O! f4 C
  5.             echo 'I am one!';# i; q8 x4 B# u8 F
  6.         }
    5 ?) U* A! F; {6 |) w% W; l( ~8 N
  7. }
复制代码
  1. //name.php& l' V  c, W( ]8 A5 Q+ u  y- X
  2. namespace test;
    5 Y$ X0 `2 z; S* W
  3. require './1.php'; 1 L" j9 c4 c$ C6 J
  4. new \one\Person(); //输出 I am one!;$ j) n. S0 ]' u5 l% \* \/ n7 }1 m, m
  5. new Person();      //这里结果会是什么呢,猜猜看
    ; h# U: |- w  o3 m5 |9 t3 c5 ~1 M
  6. 最后一行结果报错:- J5 S4 j1 N8 W! T3 S
  7. Fatal error:  Class 'test\Person' not found
复制代码

4 z: R2 E9 b% @# K6 T4 \: v; ?
/ W" t  R( ]0 ]' Q  S6 p0 I
首先,这里与第2点比较一下:
第2点,我说,没有命名空间时,new类时,有没有反斜杠意义一样。
在这里,有了命名空间,有和没有反斜杠的意义就不一样了。
最后一行换成
  1. new \Person();
复制代码

' e) T1 L( H' s0 s6 O! |
结果报错:
  1. Fatal error:  Class 'Person' not found
复制代码
0 `* `* F% T& N5 o$ m; p
接着,就说说当前这点。
我们可以发现,最后一行代码对应的命名空间为test,并没有受到require文件里的命名空间的影响。
进一步加强验证,我修改了name.php文件如下:
  1. //name.php
    : V; z, @: H, V# I! ~
  2. namespace test;
    1 Y! m) J! O+ G# W  b4 p
  3. require './1.php';
    ! X7 k- d3 o" b, U
  4. - }; G+ Z: ?1 p* M4 f; s. a+ ]6 Q1 E" E
  5. class Person{
    : B4 Q: i- _; d
  6.     function __construct(){( `, H7 Z( i9 j* \9 ^. i
  7.             echo 'I am test!';
    2 C! h1 V3 C  y3 R
  8.         }; [; p& |4 V/ {, i
  9. }
    8 m  D9 k) j" Y9 v( a% t0 Y# h$ j
  10. 2 u2 Q# ?1 x7 |$ s, v
  11. new \one\Person(); //输出 I am one!;
    ' X( K) G5 ~  g: w: ~: `' M
  12. new Person();    //这里结果会是什么,自己猜猜看
复制代码
1 r2 N" s# J. ~" l  @) L# `
最后,这个例子刷新了我对require的认识了。
按照我以前对require的理解:PHP 程序在执行前,就会先读入 require 所指定引入的文件,使它变成 PHP 程序网页的一部分。所以我常常就简单的理解为替换,只不过把抽离出来的代码再放回原处而已。然后我试了将1.php文件内容放到name.php里:
  1. //name.php5 V4 k0 G$ H) W& g
  2. namespace test;) ~) g8 w: I* ~! s
  3. namespace one;
    + x( S2 u8 N) K! y4 O% O
  4. class Person{9 R1 G7 C) Y$ R6 t/ ?6 F
  5.     function __construct(){
    ! r& `) L, I( e9 e
  6.             echo 'I am one!';
    2 m2 _$ g9 ^$ }, M$ z
  7.         }
    / f, S. P! ]% O* U
  8. }0 `3 x- J$ z: t9 ], I8 m# `4 ^
  9. % C! H( h1 K8 o0 T+ E/ F1 f
  10. class Person{
      B& p5 `, s- L
  11.     function __construct(){( U2 O8 o9 z5 ~) U# U" [+ E
  12.             echo 'I am test!';
    5 y% }: E0 _! w; i: P' G* y
  13.         }4 o4 [4 g  l* ^! _8 J( c8 k4 K
  14. }
复制代码

( L; t) k* p3 E* W0 o5 g/ I
无需new类,该文件就会报错:
  1. Fatal error:  Cannot redeclare class one\Person
复制代码
' v7 w7 Q; `. c$ [4 H0 A- [
看来简单的把require理解为替换,在这里行不通。

3 ^; Z+ |! W8 h) _( R6.namespace里不包含类名称,即使存在与类名称同名的部分,那也不代表类。new类时,还是得将这部分带上。
2 P, L9 K, j6 m+ k8 z' A" I( A
  1. //name.php
    ' s- y# q7 @% R* j* M

  2. ! [, z4 e3 L$ Z
  3. namespace test\person;% L6 r$ ?0 D! q% _# D

  4. ; @( p# Q  X9 r# F9 \: _
  5. class Person{
    : _3 B% M, R# }6 v7 W4 V) k
  6.     function __construct(){
    6 v/ L( q9 D6 `; d
  7.             echo 'I am test!';
    0 @# U1 k5 r$ B, J0 J; }
  8.         }5 m; _/ g! h7 W( [9 T# [* h) e
  9. }8 n" D8 j: Y0 h7 L
  10. new \test\person\Person();  //命名空间里person无法代表类名
复制代码
" Q8 s# e. o1 _" F! V- {' Q
不过这样纯粹是画蛇添足,直接干脆点,namespace里不要带类名称就好。
5 c  ?, r& x& W
7.一个php文件中可以存在多个命名空间,第一个命名空间前不能有任何代码。
只说第一个命名空间前不能有任何代码,之后的命名空间之前可以有代码。这个自行测试即可。
  1. //name.php
    1 a1 Z: }# r$ j) X& k4 {, m+ \

  2. ! u8 G+ |  ~1 t0 c4 a2 d7 K
  3. namespace test;7 _! |* Z: K7 P  p0 ~
  4. echo 'zhai14';
    ) s' W) ]9 ^9 `0 J6 V  f/ Z
  5. namespace zhai;: i# L) V: l4 n9 b% o* ~8 ^2 O/ |3 s
  6. require './1.php';
复制代码

6 h% T- H9 _! |# G
php命名空间namespace告一段落了,接下来说说use的用途。
使用use的目的:
在命名空间字符串过长时,使用use可以相应的缩短命名空间。

. E' y, i1 e  w: _" B/ D" {# ]use的使用方法:1.new类时,最前面无需用反斜杠。此外,use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。
8 t( m% _7 S+ X2 ]3 P& {* Q
  1. //name.php: c# M& v% [& D* e) Y2 o
  2. ( I1 Y) d* v% y+ Z9 y8 M0 Y0 C
  3. namespace animal\dog;( o0 w) H4 w( z. @! \5 p
  4. 0 I4 @: f5 H5 L  E
  5. class Life{! s+ h5 b- F9 J6 ]3 t
  6.     function __construct(){
    , g7 Y; l3 W: H6 U
  7.             echo 'dog life!';
    ) k" n- u# h' j. c6 ]6 v% s) A0 y5 g
  8.         }
    , f+ _1 d& D6 y5 ], b7 {, d& _, Q
  9. }6 i* G; x3 C3 c% K+ }8 \0 Y* I
  10. 0 h7 i, [+ R8 O  I1 ~- [6 H
  11. namespace animal\cat;5 W3 V4 z* J, w& U

  12. - z5 e2 ^/ j+ ]# x" B
  13. class Life{
    2 Q7 I7 t' a, p' X  U7 S. V
  14.     function __construct(){
    ; N) I+ s% {' E8 B- a( H  i, x5 J
  15.             echo 'cat life!';3 s5 B& ]* O( D
  16.         }2 U5 e+ v0 l! e* O( P0 `* U8 B1 O
  17. }
    3 d; O& J7 u8 _. a0 {' ^

  18. 7 Q9 `0 z0 ~1 a# ]) T' a
  19. new Life();  //按照代码执行顺序,这里默认animal\cat这个命名空间
    4 S0 y" t( Q7 c2 D- i
  20. new \animal\dog\Life();  //A& R3 {$ O# \, F5 P! U6 _
  21. 4 H7 g% X" w' c/ r+ u
  22. use animal\dog;  //a
    0 V5 G2 T7 [3 e; }3 d
  23. new dog\Life();  //B
    * g* T, x; R  C1 p7 m& n6 @2 {' O

  24. 7 Q6 V/ c& b6 D( `
  25. use animal\dog as d;  //b
    2 w& d. J6 c9 E( b! m  L# A
  26. new d\Life();
复制代码

0 N; k" e! k- _( @! b8 A) w1 O. W, p
通过A、B行代码比较,需要注意:
使用use后,new类时,最前面没有反斜杠。
没使用use时,命名空间最前面有反斜杠
8 U/ u! O. V) V4 b
通过a、b行代码比较,可以理解:
use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。如上的:
  1. use animal\dog;
复制代码
  Y$ P0 p. I4 z; R
相当于
  1. use animal\dog as dog;
复制代码
2 s# b/ [# y# @% ]
2.namespace后面不建议加类名,但use后可以。
* m9 P; T6 |2 \4 h5 ?. j+ n
  1. //name.php
    ( k! O# o7 H( W" n; w" c( x# [- Q( Y! w

  2. 9 n0 p" x7 |, ~' x
  3. namespace animal\dog;
    / O( P5 \9 a* V9 N$ x8 d$ {
  4. * U5 x9 g% U9 e
  5. class Life{
    / I+ W' v. i8 ~: I* Y5 ~8 y
  6.     function __construct(){
    + a5 i( A8 x. ]
  7.             echo 'dog life!';
    , C, F6 o( m: p
  8.         }
    0 l8 d8 c* V$ f% ^6 |7 _
  9. }1 d: H( F3 s) h2 D0 n. s

  10. ; b2 q8 R/ D& A1 h, c
  11. namespace animal\cat;
    : Z. H* Q$ d# ^& r
  12.   A- s1 f$ M. D$ X( a+ {" a) m
  13. class Life{) M9 [6 F' `$ ?5 N9 J' L/ D
  14.     function __construct(){; h  F# X. {4 M- V. v# `
  15.             echo 'cat life!';
    ; w; k- n% y0 r# u* S$ X& F( q
  16.         }: O( r) J4 k5 e  A
  17. }
    ! A4 C" b$ V' q8 ?5 W+ P0 a

  18. ' C) Q! c- ?) _  N# f4 _( I
  19. use animal\dog\Life as dog;  5 ~9 l  M7 _7 S
  20. new dog();
复制代码
& A& V4 G2 s7 `, ^7 I
如上所示,use后加上类名后,就相当于把类改了个名称:由Life改为dog了。
上面不用as dog就会报错:
  1. Fatal error:  Cannot use animal\dog\Life as Life because the name is already in use
复制代码

- q8 |6 F% _# l* }
因为cat下也有个一样名称的Life类。
可以理解为,使用use后,这个昵称对应的类只能归当前命名空间占有,其它命名空间下不允许存在该类。
  1. //name.php
    ( `8 |) r- M; o1 ]. ?# u

  2. ' z, C& L5 @" N! L9 |. @
  3. namespace animal\dog;
    # a+ B% n: s, u3 V7 R! S
  4. " _! a/ Q5 ?1 {- Q* [: s) U. L: f/ J
  5. class Life{
    9 A/ r  R9 E/ t9 J! g2 `) D- y
  6.     function __construct(){. h; w' T! \, A
  7.             echo 'dog life!';
    % F) q2 q! ?6 Q# Y& @) F0 ?. H6 O
  8.         }
    ' p6 h/ ~1 S$ o6 u" u) M6 `6 g
  9. }5 t8 F% l9 M' \4 y$ J# o- Z, m2 B# L
  10. class Dog{
    6 D7 v0 h( R0 `/ g2 b% t
  11.     function __construct(){9 a# d" S8 k( s: l- i) D# v
  12.             echo 'dog in dog!';
    & v+ \% Z7 ^) z( r
  13.         }
    ! s! U$ g( L! L; w- U4 ~" c
  14. }
    # m* G' R1 R* }- _% N

  15. & t5 d% g$ H" x9 m
  16. namespace animal\cat;
    0 R# G4 N; z( U2 G

  17. : t+ Q5 b4 }" b% z% B$ h
  18. // class Dog{( e) _; R1 D7 `) C1 p% b
  19. //     function __construct(){8 p, W! f; ?5 j) x
  20. //             echo 'dog in cat!';
    * m' o4 U- M, _6 @& @6 p
  21. //         }- [5 C) C; r' E" f3 I$ ^* k
  22. // }1 ~2 E0 _2 c4 {2 u4 H1 H
  23. class Life{& c  F0 u3 g8 H1 W2 ]' {
  24.     function __construct(){& ?2 e' z8 _- i- U7 T, H- u! y
  25.             echo 'cat life!';
    + T; C, o. [* y. I, V
  26.         }' j4 I7 W* Z' r+ T
  27. }
    ' w( N0 d  Y, N) k1 c# P. u" y
  28. 7 ]' Z8 F+ c  j6 p  W
  29. use animal\dog;  
    # b6 ~- r' h- `6 `' d
  30. new dog\Dog();
复制代码

- w# |. Q( P2 e3 Y& g2 X5 S
如上,使用了
  1. use animal\dog;
复制代码

7 Y  r9 b+ v$ X& w
cat
通过上面代码,我想使用use的目的效果(缩短命名空间名称)就很明显了。

8 Q2 n4 P' a0 |1 y8 l7 a) a4 K9 l
简单总结一下:
namespace就是划分领域的作用,代表这些东西是属于某个命名空间下的。
use就是起小名的作用,不论写起来还是说起来都可以省不少事儿。
8 k% G8 F1 I% W7 V* ?$ f. ?
3 d, k* r, O0 b. h- _. E# O8 w/ x

3 ^* i0 V8 _" R1 }! T+ a! l. f( B* y, |

* R  i' V# v8 i7 d/ S* |




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