cncml手绘网

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

作者: admin    时间: 2020-7-1 23:37
标题: PHP命令空间namespace及use的用法实践总结
以下皆为本人自我理解内容,如有失误之处,请多多包涵。

& |1 w* V) x. K% j% p
文章大纲:
使用namespace的目的
namespace的使用方法
使用use的目的
use的使用方法
1 \  H& m$ l5 T* }9 M  V
* U( E  F. k  |* u& n
使用namespace的目的:
团队合作项目时,避免与团队其它成员新建的类发生冲突;个人负责项目时,避免前后新建的类发生冲突;
$ F# l3 L* \0 |8 \/ I! ^
据个人理解,用到所需要的类时,需要先require或include引入,所以会发生类重定义的错误的前提是:两个相同命名的类都有被引入。目前有些php框架会自动加载(即include)所有新建的model类,所以为了避免你新建的model类和项目框架原生的核心类发生重名冲突,采用了namespace。(想了想,与团队成员新建的类产生冲突应该通过沟通避免,即使事发后也应该重新调整类名即时维护,避免后期造成因为对类的理解混淆而带来维护上的复杂度提高)
* a5 n% S; e$ `" l: b
结合使用方法来进一步理解它的使用目的吧。
& p8 D% ^0 d4 O. y5 K

$ ~9 }& v. K5 t" x9 x1 Inamespace的使用方法:
为了进行测试,我将创建3个文件:1.php和name.php(此文件用来执行测试),后面将不再说明,请自行注意代码的变化。
1.namespace后命名的定义不区分大小写
  1. namespace one;
    9 k5 i! V- H# [1 z; ?5 d
  2. namespace One;5 G4 ^1 p% T0 t) s) y: _5 ?' F
  3. namespace ONE;
复制代码

7 b8 h8 d9 J; k
如上写法都可以,选择一种作为自己的规范即可。(后面代码我采用第一种进行测试哈)

  ?* h' J) H" J2. 没有定义命名空间,就理解为使用顶级命名空间。new类时,可以在类前加上反斜杠\,也可以不加。
  1. //1.php   
    , ^; {! R/ j+ z) l' p
  2. class Person{
    9 z) m: I2 S6 N
  3.     function __construct(){
    ; l0 ?2 {( B! s1 S8 [, n3 Y; g
  4.             echo 'I am one!';
    % E$ h( @3 G/ `/ p9 r
  5.         }
    : Y) I5 u- K4 O3 k/ U) l
  6. }
复制代码
  1. //name.php
    , y) y/ g/ Y0 R9 M- y3 I$ f
  2. require_once './1.php';2 G9 x. p! `& g& V$ z2 v
  3. , {/ C) X2 r& m. E5 t. e  N7 ~
  4. new Person();     //输出 I am one!;
    4 R+ k% O3 r# A/ M& a
  5. new \Person(); //输出 I am one!;
复制代码

6 g- ^- _! @; p) p' M( e# {3. new类时,带上命名空间时,之间一定用反斜杠字符,而不是顺斜杠。
记忆方法:按找%中斜杠的顺序理解为顺斜杠。(有时说反斜杠,自己都不知道是哪种方向,以前按自左向右上升方向这种方向记忆,现在感觉这个太不靠谱了)
  1. //name.php4 I$ G! G" t1 i6 ^& {( G+ R8 b4 q
  2. require_once './1.php';
    ; Q$ J) n7 A' t& k. A
  3. new /Person();  // 代码报错:Parse error: syntax error, unexpected '/'
复制代码

( F, f7 D  u7 c. G  B4.类在指定命名空间下, new类时,一定要带上指定的命名空间。
没有带上指定的命名空间,按照第2点,php就会从顶级命名空间里找这个类。切记:这里不能按照顶级命名空间包含一切其它的命名空间来理解。而应该将顶级命名空间完完全全与其他命名空间区分开。
  1. //1.php   8 c3 w0 A9 f# \5 D! @& e' {
  2. namespace one;
    - Y7 ?  `2 G0 W4 }& P+ T
  3. class Person{( O5 }; h6 [6 v/ n6 l0 q
  4.     function __construct(){( ^! h2 A3 y; Y0 Y6 I
  5.             echo 'I am one!';
    % r7 R+ V0 J6 h. I1 o/ z
  6.         }
    0 [9 y/ R  \; Z. E% ]2 h
  7. }
复制代码
  1. //name.php
    " H% ]4 Z% |6 m3 u
  2. require_once './1.php';
    $ M0 w8 k0 z5 l  w8 p& B
  3. new \one\Person(); //输出 I am one!;' u* y& r5 ?( ?2 b, a/ [
  4. new \Person(); //代码报错:Fatal error: Class 'Person' not found
复制代码
: Q6 `# }5 ]$ n  h1 j. s* \
可以举个这个通俗例子来理解:带上指定命名空间代表某人的苹果(在他手里),顶级命名空间代表苹果箱里的苹果(在箱子里)。现在要找某人的苹果,就将某人的命名空间带上,否则就会从箱子里找某人的苹果,结果当然是找不到。

% E, F6 k- I- X' t+ |5.命名空间声明后的代码便属于这个命名空间,即使有include或require也不影响(重点是对后半句的理解,具体看代码)。6 `3 U$ a8 I, L1 L
  1. //1.php   # u2 \/ {6 u, K1 P/ D" w! h
  2. namespace one;  o4 ^$ P* Y" x
  3. class Person{* d8 }. h/ Y6 U  s' C5 U
  4.     function __construct(){# h5 S9 F+ H) \$ O1 K
  5.             echo 'I am one!';* r/ ^# D' U0 U% T
  6.         }
    8 B0 |& W6 P% R3 r9 m5 X% @+ [4 S7 D
  7. }
复制代码
  1. //name.php
    ( m6 D, t- D" N( E, v
  2. namespace test;
    4 g  ?6 E8 O* q- |  |$ f+ \  E
  3. require './1.php';
    ( q9 u. J8 D2 ^# j0 n3 q+ {
  4. new \one\Person(); //输出 I am one!;
    " m- Q; C: p9 f
  5. new Person();      //这里结果会是什么呢,猜猜看
    / ?' \+ u. k2 L! g2 P
  6. 最后一行结果报错:
    8 R9 i7 Q7 F/ x
  7. Fatal error:  Class 'test\Person' not found
复制代码

0 `2 w# `" c5 i' ^$ D2 @
, M1 M* r+ C5 p3 Z! H3 Q
首先,这里与第2点比较一下:
第2点,我说,没有命名空间时,new类时,有没有反斜杠意义一样。
在这里,有了命名空间,有和没有反斜杠的意义就不一样了。
最后一行换成
  1. new \Person();
复制代码
' b  I3 w1 c$ _7 F6 M  n9 M- r$ h4 F
结果报错:
  1. Fatal error:  Class 'Person' not found
复制代码

7 ?% j9 F  ~# P' o
接着,就说说当前这点。
我们可以发现,最后一行代码对应的命名空间为test,并没有受到require文件里的命名空间的影响。
进一步加强验证,我修改了name.php文件如下:
  1. //name.php
    ' O' ]* `# H/ x! r
  2. namespace test;) J! H/ I# U: z, ]2 C; Z
  3. require './1.php'; : ^9 L0 w( o: s) j  h7 |0 U! f
  4. 4 C2 i$ i+ x$ J. A; H* P) o
  5. class Person{; b+ C9 a8 u; Z4 S
  6.     function __construct(){
    * q' c' P# n7 |$ a4 b
  7.             echo 'I am test!';
    & }/ ^0 B3 S1 J! p
  8.         }/ P4 y- M" \$ ?: H' @4 j/ X
  9. }2 E! H2 M6 @8 n! E. H8 t5 f- J

  10. . R9 f1 S. m( r1 \: T2 x
  11. new \one\Person(); //输出 I am one!;' x. ]* _; Q$ D! u% _, g
  12. new Person();    //这里结果会是什么,自己猜猜看
复制代码

" p) s( J, l  A, L9 n6 O
最后,这个例子刷新了我对require的认识了。
按照我以前对require的理解:PHP 程序在执行前,就会先读入 require 所指定引入的文件,使它变成 PHP 程序网页的一部分。所以我常常就简单的理解为替换,只不过把抽离出来的代码再放回原处而已。然后我试了将1.php文件内容放到name.php里:
  1. //name.php
    0 k8 Z1 _) t' X, {
  2. namespace test;
    * ]* M4 y5 C6 E9 S
  3. namespace one;
      h3 H+ q, _& \* F& r
  4. class Person{
    , |6 {2 _, y* I; ^
  5.     function __construct(){. f/ S  P. b) _; E9 p% q1 H
  6.             echo 'I am one!';9 U0 J- r7 |6 H, R' S  B* f: M
  7.         }8 |/ }2 l, X' r9 A+ D* y
  8. }
    7 R% f; }) ]7 j, z8 c4 Y0 T  _
  9. $ C8 N& l- v( ~; {4 L
  10. class Person{
    3 U+ W7 K+ m6 X2 c
  11.     function __construct(){
    : ]$ z; \! m) z" b/ U
  12.             echo 'I am test!';! L) q: t8 n4 g2 v1 |, i
  13.         }1 W  A7 ?7 ?3 Q3 o
  14. }
复制代码

, p! U( M9 h( Q. J! k0 W9 n
无需new类,该文件就会报错:
  1. Fatal error:  Cannot redeclare class one\Person
复制代码
, X$ |! m, e$ ^
看来简单的把require理解为替换,在这里行不通。

5 f% E  Q% g) Q; M4 X0 i- D0 U- o6.namespace里不包含类名称,即使存在与类名称同名的部分,那也不代表类。new类时,还是得将这部分带上。& U) l& P3 b* V! v
  1. //name.php
    # V& z: s9 v4 Z
  2. . G( Z2 j* q+ [' ^
  3. namespace test\person;5 h* C3 [  r1 f: x( w: i
  4. ! \, G( f. k- Q
  5. class Person{
    ' d- O+ R% g- _2 [) c
  6.     function __construct(){
    . i; @' s" R+ H- I: n2 [2 q2 y
  7.             echo 'I am test!';+ a5 y  Y  J+ a3 ^7 o% X2 D  P3 y
  8.         }7 s, w" _; f0 j, r# I) d
  9. }
    2 W# A) {! b" ]* r9 ~1 y
  10. new \test\person\Person();  //命名空间里person无法代表类名
复制代码

2 g  s4 ^% ^* Y' N2 C
不过这样纯粹是画蛇添足,直接干脆点,namespace里不要带类名称就好。
1 R! Z& d8 A0 Z' h2 c  F  i2 X
7.一个php文件中可以存在多个命名空间,第一个命名空间前不能有任何代码。
只说第一个命名空间前不能有任何代码,之后的命名空间之前可以有代码。这个自行测试即可。
  1. //name.php0 x, n$ d7 S6 Z( a# w( I3 R
  2. * |. i. F: Y: b* p
  3. namespace test;, k- _/ W/ J3 ?, Q9 b
  4. echo 'zhai14';
    9 r5 z/ m- q0 p' j& Z7 s, T
  5. namespace zhai;
    : U+ ^/ p' u2 T: D( Y$ M( B
  6. require './1.php';
复制代码
* \9 Q! t4 E& d3 n  v" f3 v
php命名空间namespace告一段落了,接下来说说use的用途。
使用use的目的:
在命名空间字符串过长时,使用use可以相应的缩短命名空间。

! n5 I( M) e. b9 S/ Euse的使用方法:1.new类时,最前面无需用反斜杠。此外,use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。
6 ?1 U3 G7 I! O3 W. Y
  1. //name.php
    9 h2 T% V. q: \  @1 p, U

  2. + i5 Z7 K( _7 Y0 @
  3. namespace animal\dog;
    * g1 `. w/ T1 ~5 n
  4. . a- f  z6 d" g& C3 Z4 M- ^6 o! j
  5. class Life{
    + L* O1 K7 D" h9 h$ E' Z0 s: M
  6.     function __construct(){
    % G1 N) a6 S! ?4 p" ]/ V
  7.             echo 'dog life!';2 C4 C! J! w8 a1 g" R2 t
  8.         }
    5 W4 \0 H1 U3 v0 h4 D$ u  g
  9. }% Q6 O+ k; z7 Q4 l5 ~  b
  10. $ X1 E7 _+ O2 k& f/ s
  11. namespace animal\cat;
    4 @8 @: k& L& ]: z  S
  12. * N7 W% T5 |: _
  13. class Life{
    7 Z. ~$ e) D: z) S9 Q  m
  14.     function __construct(){
    $ t& j8 o7 |1 L3 H4 l' R/ ]
  15.             echo 'cat life!';8 O/ P. w# ^" Z$ e" ]: Q2 `5 w
  16.         }, J4 A( Q1 Y! R6 L
  17. }
    ) T8 ?' L4 R1 U5 b' E5 W
  18. 9 D% e4 s$ R- R8 a# o
  19. new Life();  //按照代码执行顺序,这里默认animal\cat这个命名空间' }5 z3 P& @5 ]# M9 Y
  20. new \animal\dog\Life();  //A
    4 P+ z' ^$ ~% c3 N

  21. 9 Q# o  h& L: i2 L
  22. use animal\dog;  //a
    , `2 }( Z5 s; `; X& Z
  23. new dog\Life();  //B; @( O; W* b) g, O. z4 y% t0 {
  24. 7 `8 w9 x& r  ]( E: K2 U) J
  25. use animal\dog as d;  //b+ k0 N$ p! h) k6 i8 H
  26. new d\Life();
复制代码

4 a: @! G/ \0 C- |3 Z
通过A、B行代码比较,需要注意:
使用use后,new类时,最前面没有反斜杠。
没使用use时,命名空间最前面有反斜杠

* w- C# v7 p" Y
通过a、b行代码比较,可以理解:
use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。如上的:
  1. use animal\dog;
复制代码
6 r# c8 \8 |8 k3 h" P( u  w7 t
相当于
  1. use animal\dog as dog;
复制代码

& g% F& h5 V: n  |; L0 M2.namespace后面不建议加类名,但use后可以。& Y. ?/ p2 u* y9 L0 u
  1. //name.php
    # d# b7 N7 L5 ^6 E7 P

  2. 5 [: O& P6 B- |" ~1 P
  3. namespace animal\dog;
    1 A" X- i2 [6 O) W
  4. 2 M' L- d* L( p, B
  5. class Life{; I6 {' h$ J0 k; }: c; P7 V$ }
  6.     function __construct(){5 n4 L3 k* A9 e6 o7 W
  7.             echo 'dog life!';6 c/ [3 j% H8 ]1 }1 E
  8.         }* B# {+ ~2 d4 y. l8 h+ T
  9. }  A  {7 j8 n4 t$ O

  10. . W5 Q7 l1 {% U0 ]
  11. namespace animal\cat;( z+ j4 @. ^- K& y

  12. 0 r6 C) u/ E- V( U' e) Z
  13. class Life{
    # ^2 M. W; Q) D
  14.     function __construct(){' f/ U! M7 f% y6 x5 b. `& m
  15.             echo 'cat life!';
    ' ]% d9 O' j& [: k5 X, R( u
  16.         }
    ! u7 z( l$ w! H' G% K7 L
  17. }% i+ b( P9 H( d* @4 d: X6 T4 v0 u

  18. ! A6 x' o, \3 b& P& d1 H
  19. use animal\dog\Life as dog;  
    0 n, |1 f. E% ^' b9 o
  20. new dog();
复制代码

; S5 d; O1 z/ u2 @3 ^0 a
如上所示,use后加上类名后,就相当于把类改了个名称:由Life改为dog了。
上面不用as dog就会报错:
  1. Fatal error:  Cannot use animal\dog\Life as Life because the name is already in use
复制代码

& g* ^# R% Y$ {5 N# d* c* m. d( j
因为cat下也有个一样名称的Life类。
可以理解为,使用use后,这个昵称对应的类只能归当前命名空间占有,其它命名空间下不允许存在该类。
  1. //name.php: e: D# s, \1 `* w
  2. ( C) V+ J+ b2 g$ \- [/ G8 l
  3. namespace animal\dog;
    6 \! u2 S- i8 t7 S0 K
  4. ) M% r3 N2 T/ ]. A9 s& o
  5. class Life{
      L5 u( }6 _0 E
  6.     function __construct(){/ l) p' L+ Z! x& ?7 S; q
  7.             echo 'dog life!';
    ( ]1 R. Z7 w' H, J% ^
  8.         }
    / R5 f3 G. U4 }- ~$ M
  9. }
    ! m- `8 M' a% K, c$ j2 ]* Z+ c
  10. class Dog{. T% Y6 f! |7 k
  11.     function __construct(){$ r4 }/ H* }5 V% J+ I1 a3 q, u
  12.             echo 'dog in dog!';
    # w5 c' C( j9 {- r) d5 S
  13.         }
    0 K8 N* l* X' N9 ?# ^+ ]
  14. }
    - I& d- `% q4 f. n/ ^! Q! _

  15. . {) a9 n2 ]( d' @8 G- r
  16. namespace animal\cat;' g  `8 x& O3 u7 w' c# t
  17. 0 K! @3 u* w4 W0 @$ n
  18. // class Dog{
    " r, ~% V# U* R* t2 X
  19. //     function __construct(){& W/ u- q: P" @% O  X! R( ~2 t
  20. //             echo 'dog in cat!';
    2 z' i  Z- X% o2 F8 [5 }
  21. //         }( z% s! z9 _: @$ s% @* [/ S" c+ d
  22. // }5 n$ ?* W* ^. w! I/ X- N7 x: v7 ~) b
  23. class Life{
    : X9 V; D, |3 K# {$ ~' ?: n
  24.     function __construct(){$ v0 S4 q+ I' ~# u* m6 N( w. ?% l
  25.             echo 'cat life!';
    + }+ \' b: s1 T; X! F# [
  26.         }# o( y! y  `, _7 b9 N6 G9 _% `3 d% m8 X
  27. }+ x: c1 X! R, R6 `  e  e

  28. # M2 k0 y  p) T) W
  29. use animal\dog;  4 i1 U* M2 m- I, J! o' |
  30. new dog\Dog();
复制代码
3 L& w* t7 K# p- {; D
如上,使用了
  1. use animal\dog;
复制代码

. Q. c8 ~5 z: f
cat
通过上面代码,我想使用use的目的效果(缩短命名空间名称)就很明显了。
8 B: T* f6 t' Q: Z
简单总结一下:
namespace就是划分领域的作用,代表这些东西是属于某个命名空间下的。
use就是起小名的作用,不论写起来还是说起来都可以省不少事儿。
0 a8 v3 _2 g& ?) I5 G' s
/ H7 t7 f8 D6 E9 P, s. Q( r8 D5 ?; a7 W

* n" ^- w, i6 D! y) M4 I3 z
1 K& ]& P3 Z  F- d9 [- o$ F& b" P/ h) I$ h4 c





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