cncml手绘网

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

作者: admin    时间: 2020-7-1 23:37
标题: PHP命令空间namespace及use的用法实践总结
以下皆为本人自我理解内容,如有失误之处,请多多包涵。
+ |) ?$ W+ V" [: o8 L
文章大纲:
使用namespace的目的
namespace的使用方法
使用use的目的
use的使用方法
! @# S* Q1 N3 Z' m

2 `! Y7 h$ T5 I! h8 b) ?使用namespace的目的:
团队合作项目时,避免与团队其它成员新建的类发生冲突;个人负责项目时,避免前后新建的类发生冲突;

. R9 w  y. T+ H+ E
据个人理解,用到所需要的类时,需要先require或include引入,所以会发生类重定义的错误的前提是:两个相同命名的类都有被引入。目前有些php框架会自动加载(即include)所有新建的model类,所以为了避免你新建的model类和项目框架原生的核心类发生重名冲突,采用了namespace。(想了想,与团队成员新建的类产生冲突应该通过沟通避免,即使事发后也应该重新调整类名即时维护,避免后期造成因为对类的理解混淆而带来维护上的复杂度提高)

# h3 z2 [3 ^+ l3 A. T结合使用方法来进一步理解它的使用目的吧。

# p0 k+ f( O; l# B
( W. Y9 G! U: C5 z0 Pnamespace的使用方法:
为了进行测试,我将创建3个文件:1.php和name.php(此文件用来执行测试),后面将不再说明,请自行注意代码的变化。
1.namespace后命名的定义不区分大小写
  1. namespace one;
    : S4 m9 S+ }2 ]) S# M
  2. namespace One;
    8 F, n6 ^8 }- [" S9 H3 S8 a+ s6 G0 g3 b
  3. namespace ONE;
复制代码
" _+ i- r3 Y$ [1 ^4 p
如上写法都可以,选择一种作为自己的规范即可。(后面代码我采用第一种进行测试哈)
# X) s. i% C# K( J. ?
2. 没有定义命名空间,就理解为使用顶级命名空间。new类时,可以在类前加上反斜杠\,也可以不加。
  1. //1.php   
    . d; n0 ^. ~- }" P  j3 _! l, l
  2. class Person{
    3 `. g" K3 O+ e: C
  3.     function __construct(){7 a/ z- \3 X# C0 {
  4.             echo 'I am one!';& ]# Q3 z; W+ M+ d' y: M
  5.         }- Z0 |; m0 i* [
  6. }
复制代码
  1. //name.php
    % x! s6 i9 [- L* J0 z4 Y. j/ m
  2. require_once './1.php';* [. |/ a9 M: a) \" y1 [
  3. . m: P' I5 d! j- s3 P: O. d
  4. new Person();     //输出 I am one!;+ ^7 M% g# s4 v4 K0 u" R" t
  5. new \Person(); //输出 I am one!;
复制代码

9 a8 Z# t5 V# o3. new类时,带上命名空间时,之间一定用反斜杠字符,而不是顺斜杠。
记忆方法:按找%中斜杠的顺序理解为顺斜杠。(有时说反斜杠,自己都不知道是哪种方向,以前按自左向右上升方向这种方向记忆,现在感觉这个太不靠谱了)
  1. //name.php1 [: c$ ?: Z; ^: H
  2. require_once './1.php';! e8 Q8 _& C3 K7 H/ f8 T' P0 [9 [
  3. new /Person();  // 代码报错:Parse error: syntax error, unexpected '/'
复制代码
# D3 G* m5 S9 T8 {5 H
4.类在指定命名空间下, new类时,一定要带上指定的命名空间。
没有带上指定的命名空间,按照第2点,php就会从顶级命名空间里找这个类。切记:这里不能按照顶级命名空间包含一切其它的命名空间来理解。而应该将顶级命名空间完完全全与其他命名空间区分开。
  1. //1.php   
    5 l% e$ i9 N+ E3 v
  2. namespace one;8 a* \; ~2 w6 M, `9 ^* Y3 ~/ M4 p- ^
  3. class Person{
    & Y  K1 W+ [2 J
  4.     function __construct(){: g) W0 @) B! a, S1 D
  5.             echo 'I am one!';
    , a6 @5 e; x6 B  Y3 J2 W0 ]
  6.         }
    ; a* `$ s/ {% s# @: L
  7. }
复制代码
  1. //name.php
    9 |4 f+ ~0 R6 x; f
  2. require_once './1.php';9 R; f8 @& a5 ?
  3. new \one\Person(); //输出 I am one!;; F8 x7 P# X( q8 A
  4. new \Person(); //代码报错:Fatal error: Class 'Person' not found
复制代码

+ H8 K, N2 y8 H  u+ g  ~/ `
可以举个这个通俗例子来理解:带上指定命名空间代表某人的苹果(在他手里),顶级命名空间代表苹果箱里的苹果(在箱子里)。现在要找某人的苹果,就将某人的命名空间带上,否则就会从箱子里找某人的苹果,结果当然是找不到。

- b$ B6 o' j: Y; b! I# x& Z4 D5.命名空间声明后的代码便属于这个命名空间,即使有include或require也不影响(重点是对后半句的理解,具体看代码)。
) n& e5 k) b; A  }, U
  1. //1.php   
    5 G1 P8 b; b3 D' ~+ P5 r
  2. namespace one;
    % }5 _% S& @4 |. g  }4 [
  3. class Person{- G9 S8 \3 o2 @4 ?# b
  4.     function __construct(){
    9 L" |4 x4 h6 {/ Y- y/ B3 t; x
  5.             echo 'I am one!';
    ! H# K/ l( ^( N/ P# [8 o0 n
  6.         }7 i4 p! {# D( Y. C
  7. }
复制代码
  1. //name.php
    % ~) e5 g4 t  \( q6 f; r
  2. namespace test;9 c9 C( H; A2 o; E
  3. require './1.php';
    # ], S4 j. v/ W1 w4 D. _
  4. new \one\Person(); //输出 I am one!;7 j7 P6 K: s! [8 h: v
  5. new Person();      //这里结果会是什么呢,猜猜看
    7 |4 V) x. j& M: d' Y+ t% |
  6. 最后一行结果报错:: s7 a* G: Q; y! Z- A. p" ^# a9 D) ]
  7. Fatal error:  Class 'test\Person' not found
复制代码

' Q- I  [6 v& J. a; k' _3 V
3 A$ A9 q. F- D( ?! L" a$ X
首先,这里与第2点比较一下:
第2点,我说,没有命名空间时,new类时,有没有反斜杠意义一样。
在这里,有了命名空间,有和没有反斜杠的意义就不一样了。
最后一行换成
  1. new \Person();
复制代码

2 `/ ?3 H* t/ _! C( y% ^+ V3 [
结果报错:
  1. Fatal error:  Class 'Person' not found
复制代码
) U: I2 O7 j, U- d3 \! F# v
接着,就说说当前这点。
我们可以发现,最后一行代码对应的命名空间为test,并没有受到require文件里的命名空间的影响。
进一步加强验证,我修改了name.php文件如下:
  1. //name.php
    3 k: d$ A3 Z. _; ~! P) _  W
  2. namespace test;7 C1 V6 Y! ?. N6 f. G8 ]
  3. require './1.php';
    & s7 J4 P7 c. }; X
  4. * n( ]2 ]4 H9 `, `
  5. class Person{
    . v2 V, d8 Q3 q1 O2 |, {
  6.     function __construct(){
    % t4 ]; V& I8 ^8 z7 O0 d
  7.             echo 'I am test!';- {* S4 Q7 |; s) e2 ~6 B2 ^
  8.         }
    9 N! W4 u* y/ l9 V% r. `0 e
  9. }$ U" j+ x3 F' d* W
  10. # X% `+ S+ V/ v2 T0 V
  11. new \one\Person(); //输出 I am one!;: x" s  O. D+ ]7 i
  12. new Person();    //这里结果会是什么,自己猜猜看
复制代码

" k! Y/ ?0 C7 T. D* ]  k- f
最后,这个例子刷新了我对require的认识了。
按照我以前对require的理解:PHP 程序在执行前,就会先读入 require 所指定引入的文件,使它变成 PHP 程序网页的一部分。所以我常常就简单的理解为替换,只不过把抽离出来的代码再放回原处而已。然后我试了将1.php文件内容放到name.php里:
  1. //name.php3 i6 Q* ~; J, Y0 Y) |
  2. namespace test;
    6 m/ j9 s' d# D1 I0 E# u
  3. namespace one;
    8 D2 b+ ?9 e  w( i: }. g2 U
  4. class Person{  {8 o) a! c& X8 C' _
  5.     function __construct(){
      n' p+ v% J( l2 {
  6.             echo 'I am one!';# k) U3 g6 Z% G
  7.         }/ ]% e" [9 C8 o& y/ Z) [
  8. }
    8 O# p* e& J/ i

  9. 6 K( H- a$ |$ d; Y
  10. class Person{
    $ K6 w7 ]5 v9 A6 `
  11.     function __construct(){. A2 N0 [% _) i; E
  12.             echo 'I am test!';
    0 j  W# J) u1 L  k, R, |
  13.         }
    * I+ w& v2 I0 ?4 @0 E, c6 R
  14. }
复制代码

3 @; V5 Y' Y* y5 \, D
无需new类,该文件就会报错:
  1. Fatal error:  Cannot redeclare class one\Person
复制代码

& Y3 r2 U$ z( l9 F# t! z4 O
看来简单的把require理解为替换,在这里行不通。

, f+ B0 g1 \5 ]  [& E( K6.namespace里不包含类名称,即使存在与类名称同名的部分,那也不代表类。new类时,还是得将这部分带上。/ }9 G- i, _* |2 Z* _  |! t2 \1 ^
  1. //name.php% |0 v; B0 F7 k! s+ U$ [8 I& B3 J

  2. : I# A8 o6 U" ^6 W! z
  3. namespace test\person;
    . [- e4 B. o1 M

  4. 8 G, {/ W5 ?/ E3 Y3 _6 {
  5. class Person{" ~8 y& m, g1 k# ~1 {1 V1 z' ?7 H
  6.     function __construct(){
    * L, F" R! j7 {( F3 E- M% v6 `; m
  7.             echo 'I am test!';6 u3 I5 D" `  ?7 a" c( V
  8.         }
    7 x+ w# t3 M0 h
  9. }" ~* M& v7 V0 ]7 I
  10. new \test\person\Person();  //命名空间里person无法代表类名
复制代码

7 w6 w7 o* N6 J# E+ ^4 S! K
不过这样纯粹是画蛇添足,直接干脆点,namespace里不要带类名称就好。
( ]4 X# s9 b1 |# F; _; K. e# I
7.一个php文件中可以存在多个命名空间,第一个命名空间前不能有任何代码。
只说第一个命名空间前不能有任何代码,之后的命名空间之前可以有代码。这个自行测试即可。
  1. //name.php
    5 A" ^5 p( H# E. s) a
  2. 9 m0 D! n1 a/ M1 u, ~2 T, i
  3. namespace test;2 Y3 a/ Q4 B* d* _/ F
  4. echo 'zhai14';+ p( j8 X. }- @- Z$ c  ~
  5. namespace zhai;
    : q0 j1 Y+ e+ I
  6. require './1.php';
复制代码
+ K6 h5 x1 Q4 s5 k. [
php命名空间namespace告一段落了,接下来说说use的用途。
使用use的目的:
在命名空间字符串过长时,使用use可以相应的缩短命名空间。

3 j' {8 p! ~# ~use的使用方法:1.new类时,最前面无需用反斜杠。此外,use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。
/ j" Q% X3 K# ^1 U
  1. //name.php
    7 f* G  w, \" O3 P+ b+ n
  2. / p) ^6 @6 R( Y
  3. namespace animal\dog;
    " `% X4 J3 P) g7 @$ @& A3 Z

  4. : Q* V/ ~# \5 F/ H. c" i
  5. class Life{
    ' ?( T$ P  U0 W
  6.     function __construct(){
    # b0 y# t) @' I1 D; e; B
  7.             echo 'dog life!';% Y6 D1 @9 n, L! ]5 W
  8.         }
    6 D+ t. q! G: \) E
  9. }
    ) R6 E% R! C4 D+ r
  10. % e% K- ~4 x3 K: Z
  11. namespace animal\cat;1 i' l% U! ?' Y, n) f% F
  12. 6 v" e" V( f/ ?
  13. class Life{
    & _% F' y& e3 o% T3 n4 p0 }  q9 Y
  14.     function __construct(){
      ^  F' Y: n& x$ ^
  15.             echo 'cat life!';
    1 G3 u2 _7 q1 K* Q/ v- T, ~0 y
  16.         }
    . r2 d. E: t3 g, a
  17. }9 l: S$ Q) ?, `3 d
  18. * R7 x% I! t3 P, m4 d/ G$ w
  19. new Life();  //按照代码执行顺序,这里默认animal\cat这个命名空间/ W- e+ v0 O& q6 @2 Y, A* d
  20. new \animal\dog\Life();  //A: }: Y0 H8 O  Y8 z* H2 m! I, x" I

  21. # y  `% y5 @$ r, ~8 ^. ?! ]* y4 T
  22. use animal\dog;  //a3 K5 O2 G1 M4 ?
  23. new dog\Life();  //B8 V# s4 {# z$ F' b: d

  24. ( ?+ m# M0 {. z# `
  25. use animal\dog as d;  //b5 w9 ~3 V3 j: a: u
  26. new d\Life();
复制代码

( V) m6 ^2 p/ f0 t* z  p+ O
通过A、B行代码比较,需要注意:
使用use后,new类时,最前面没有反斜杠。
没使用use时,命名空间最前面有反斜杠

$ C7 D7 a: L( ^- e$ h3 m
通过a、b行代码比较,可以理解:
use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。如上的:
  1. use animal\dog;
复制代码
9 t. f5 m& r& ?  w
相当于
  1. use animal\dog as dog;
复制代码

" ?# z; k# y5 w8 G  s5 y8 C" \2.namespace后面不建议加类名,但use后可以。
$ p! o0 C% p3 P" D- E' d+ Q1 t9 ^
  1. //name.php
    3 O4 P4 k$ @9 |- Z3 K+ l7 l+ }' n

  2. . t: D* V( O0 _) |
  3. namespace animal\dog;$ V2 P4 Z* S+ u! K% t- O  O4 v

  4. 6 s: n3 i1 ?. ?, Z7 o
  5. class Life{4 Q+ t$ X) W1 n- e* b
  6.     function __construct(){# C3 |( c  Y' c4 \8 |$ v* K
  7.             echo 'dog life!';* c. |8 J, I* b" D( S7 z. C* r
  8.         }
    & `& a- I5 b/ H. r4 M5 |2 p
  9. }
    # t! f9 A# T( k7 _/ q) b+ h
  10. + }7 S# @. C2 Q0 |
  11. namespace animal\cat;3 l3 @7 Q5 w7 c3 b

  12. , I6 G1 o; C. E9 N) d$ S5 a
  13. class Life{% f, k) h3 C, s, B2 L, p
  14.     function __construct(){  V: E' H# [6 g0 x# O# O* d( a
  15.             echo 'cat life!';* q; @! u" P/ E- p$ ?9 _$ Z2 W: G
  16.         }
    9 T  X( T. |/ Z- c- N1 a$ z
  17. }
    + G( f: J( ?1 }3 y1 _0 k

  18. ) ]* C5 ]! h3 ~* v
  19. use animal\dog\Life as dog;  
    4 \* s1 _. A0 }3 G3 [' v( J+ V
  20. new dog();
复制代码
; l- `% J1 D9 h
如上所示,use后加上类名后,就相当于把类改了个名称:由Life改为dog了。
上面不用as dog就会报错:
  1. Fatal error:  Cannot use animal\dog\Life as Life because the name is already in use
复制代码

$ _8 `5 p- y( C! `' G
因为cat下也有个一样名称的Life类。
可以理解为,使用use后,这个昵称对应的类只能归当前命名空间占有,其它命名空间下不允许存在该类。
  1. //name.php
      q; b- d+ G$ n' \/ Q; g
  2. ! z( a4 t  W8 ^! x
  3. namespace animal\dog;2 }. o7 P9 ^% E0 F: I& C
  4. ; g/ \+ n9 |" T8 E7 j$ e2 L5 ^. y
  5. class Life{3 G, L0 D" n* N: Z+ @7 O: E
  6.     function __construct(){
    . w* n4 @0 @) z/ X7 Z* ~; n
  7.             echo 'dog life!';
    " D9 y9 X: h$ l+ G. I  @
  8.         }+ M) C! h# {; A2 H3 b# P1 H
  9. }3 s) Q! W+ J" e; q6 C0 b
  10. class Dog{
    0 Y& x7 h4 i& _5 Z
  11.     function __construct(){7 P5 |7 v2 y" o' l' s
  12.             echo 'dog in dog!';
    5 ?8 C7 g% g3 a3 _1 t
  13.         }; G: i$ D8 Z8 S5 b
  14. }
    ( \* |' {4 h4 Z% [( d/ z
  15. + m% a$ B- X2 k& V
  16. namespace animal\cat;
    ; Z# z) H- a& q  b3 V: l

  17. * H) P3 F& h2 S+ E. G9 p- Y9 }
  18. // class Dog{4 \' ~& S" P% X. t
  19. //     function __construct(){" B8 {2 c7 J4 Z$ l5 {+ O. C
  20. //             echo 'dog in cat!';( P- m. P" J3 T' g3 l$ B" c
  21. //         }" t; y  W2 e8 F4 o1 e
  22. // }
      B2 f  T# F- e2 p6 f6 W& p7 N, `% {
  23. class Life{
    0 {; P1 _8 C; z9 M- F# H
  24.     function __construct(){
    4 t7 i" V& Z' L5 B4 H3 V! M" {
  25.             echo 'cat life!';% `0 @' b  o" d- z
  26.         }
    $ a! f- a( [7 V; O. n7 V
  27. }
    : N: X8 }5 i+ G2 U" a
  28. $ f! w0 m- s8 }2 n* [2 Q
  29. use animal\dog;  
    $ e$ U; |( X" ^, s1 O
  30. new dog\Dog();
复制代码
1 F* D4 D+ z" A2 \' U4 k8 L
如上,使用了
  1. use animal\dog;
复制代码

1 y- S. _% Y9 U, ~, Y
cat
通过上面代码,我想使用use的目的效果(缩短命名空间名称)就很明显了。

  T/ Z5 M2 w$ w
简单总结一下:
namespace就是划分领域的作用,代表这些东西是属于某个命名空间下的。
use就是起小名的作用,不论写起来还是说起来都可以省不少事儿。
' z* Z0 `. L3 c2 J& I6 O
& M  n7 L+ [8 O* o
& `9 ?; ^0 r/ o. h6 L, C

4 I0 o) n+ \0 S4 T1 |. S# f9 f, o# R5 [1 \$ a+ }8 d' Y3 [8 \: T8 _





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