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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 15151|回复: 0
打印 上一主题 下一主题

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

[复制链接]
跳转到指定楼层
楼主
发表于 2020-7-1 23:37:46 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
以下皆为本人自我理解内容,如有失误之处,请多多包涵。

' t8 K6 R) H( `
文章大纲:
使用namespace的目的
namespace的使用方法
使用use的目的
use的使用方法

) X0 Y3 ^" g1 g2 l# M4 J2 G5 Q5 r% d
使用namespace的目的:
团队合作项目时,避免与团队其它成员新建的类发生冲突;个人负责项目时,避免前后新建的类发生冲突;

, u+ D" V* ]# f$ u5 I
据个人理解,用到所需要的类时,需要先require或include引入,所以会发生类重定义的错误的前提是:两个相同命名的类都有被引入。目前有些php框架会自动加载(即include)所有新建的model类,所以为了避免你新建的model类和项目框架原生的核心类发生重名冲突,采用了namespace。(想了想,与团队成员新建的类产生冲突应该通过沟通避免,即使事发后也应该重新调整类名即时维护,避免后期造成因为对类的理解混淆而带来维护上的复杂度提高)
+ w9 {8 [8 Z7 A" G0 P1 V
结合使用方法来进一步理解它的使用目的吧。
3 u  }8 e8 A5 T( A! Z5 P1 @) z- u: r

: f( U. R" H6 r5 ~4 Y" F! Onamespace的使用方法:
为了进行测试,我将创建3个文件:1.php和name.php(此文件用来执行测试),后面将不再说明,请自行注意代码的变化。
1.namespace后命名的定义不区分大小写
  1. namespace one;
    3 `* e3 b! K1 t& t. I$ V
  2. namespace One;1 W0 S" D- K7 W( ?0 y2 N& p
  3. namespace ONE;
复制代码

1 c8 D/ @( H* v3 b
如上写法都可以,选择一种作为自己的规范即可。(后面代码我采用第一种进行测试哈)

% G# _' W' G( i% K4 Z* ]0 v9 y# {2. 没有定义命名空间,就理解为使用顶级命名空间。new类时,可以在类前加上反斜杠\,也可以不加。
  1. //1.php   
    + D& X: D2 f& t
  2. class Person{
    " O0 x2 |# X2 k* Q! D
  3.     function __construct(){' |+ J& t& ^2 n) m  x$ a$ `& B' ^
  4.             echo 'I am one!';
    + |2 x) }2 y& R" |" {; u1 s: }" N
  5.         }
    $ \% {7 t" S9 t" t
  6. }
复制代码
  1. //name.php0 c" C2 E% e7 U3 c6 D
  2. require_once './1.php';) D- P8 X8 L% b7 i0 J6 z

  3. : l2 l6 i" r0 {$ J( l( V; W
  4. new Person();     //输出 I am one!;, v+ R1 s: L% d# Z7 ?3 w& y
  5. new \Person(); //输出 I am one!;
复制代码

$ O. |3 ~. S, c5 Z" C1 q% o3. new类时,带上命名空间时,之间一定用反斜杠字符,而不是顺斜杠。
记忆方法:按找%中斜杠的顺序理解为顺斜杠。(有时说反斜杠,自己都不知道是哪种方向,以前按自左向右上升方向这种方向记忆,现在感觉这个太不靠谱了)
  1. //name.php+ g* S+ P5 R! P4 h) p" E  v# s2 J7 u
  2. require_once './1.php';
      n1 y* R" y+ l/ m; V
  3. new /Person();  // 代码报错:Parse error: syntax error, unexpected '/'
复制代码
$ ^+ m* R/ D0 y+ m8 j7 p# Y& I! h
4.类在指定命名空间下, new类时,一定要带上指定的命名空间。
没有带上指定的命名空间,按照第2点,php就会从顶级命名空间里找这个类。切记:这里不能按照顶级命名空间包含一切其它的命名空间来理解。而应该将顶级命名空间完完全全与其他命名空间区分开。
  1. //1.php   # p% ^2 u) e9 G5 S  V: l% U5 }
  2. namespace one;
    % j* E: X/ Q# p  J% o
  3. class Person{
    9 T) s; ]) V& n1 G6 g7 {8 b
  4.     function __construct(){
    : y, q* I5 x1 Z. e! r3 e
  5.             echo 'I am one!';+ y# ^2 z3 q+ Y% |/ a( t+ \
  6.         }
    $ E1 X3 @2 K) A, X6 }' w1 l
  7. }
复制代码
  1. //name.php
    8 ?: }6 @8 y5 [) u, F
  2. require_once './1.php';
    ( ]- G1 w! o# ~- P8 c% t
  3. new \one\Person(); //输出 I am one!;! d! r! j4 E! Y- X& R
  4. new \Person(); //代码报错:Fatal error: Class 'Person' not found
复制代码

) F! z  F: t1 \! q- K" |4 A1 ?
可以举个这个通俗例子来理解:带上指定命名空间代表某人的苹果(在他手里),顶级命名空间代表苹果箱里的苹果(在箱子里)。现在要找某人的苹果,就将某人的命名空间带上,否则就会从箱子里找某人的苹果,结果当然是找不到。
8 L: i; M$ L6 h, p! Q
5.命名空间声明后的代码便属于这个命名空间,即使有include或require也不影响(重点是对后半句的理解,具体看代码)。
; e% |+ O, a+ Q' B. N0 E9 a
  1. //1.php   
    - h6 t5 Y' n$ c& X
  2. namespace one;
    3 M) n/ B7 {9 t
  3. class Person{
    * [2 n0 x5 j! I. E
  4.     function __construct(){
    % M; D& F/ s/ J! O5 C3 c) r+ ?
  5.             echo 'I am one!';( S5 e. S9 O( P" R- v; i# A9 f
  6.         }! z5 U8 D8 _5 Q' c" @! G0 [
  7. }
复制代码
  1. //name.php
    4 ]7 ]8 n5 q2 O3 P9 O. s* [) Z; {
  2. namespace test;
      |# C$ T, n; I9 T- \
  3. require './1.php';   {$ I: _$ ]2 C% p; }1 p" D
  4. new \one\Person(); //输出 I am one!;
    * q& l5 d5 \- T$ `7 x. F+ n
  5. new Person();      //这里结果会是什么呢,猜猜看( l7 W; f# q: Y, L
  6. 最后一行结果报错:
    5 W5 l1 \' \/ H/ q$ u- R
  7. Fatal error:  Class 'test\Person' not found
复制代码
$ l* _$ Y+ B" u' n, C: k
5 j* P; A& v2 {
首先,这里与第2点比较一下:
第2点,我说,没有命名空间时,new类时,有没有反斜杠意义一样。
在这里,有了命名空间,有和没有反斜杠的意义就不一样了。
最后一行换成
  1. new \Person();
复制代码
7 G) B2 B; ]6 t' t+ z4 |' a
结果报错:
  1. Fatal error:  Class 'Person' not found
复制代码

) M/ W* Q/ {" t- R  t) V
接着,就说说当前这点。
我们可以发现,最后一行代码对应的命名空间为test,并没有受到require文件里的命名空间的影响。
进一步加强验证,我修改了name.php文件如下:
  1. //name.php6 X9 y0 h( s) _2 a/ Y7 Y/ M( F
  2. namespace test;3 y9 p" r  F& f
  3. require './1.php'; 3 g# N$ u/ K6 D1 Q

  4. ! |; W; ^* m, Z
  5. class Person{1 w$ }( O& ]" q& A! v9 a
  6.     function __construct(){
    $ C7 K& t& d# P( d% J1 X* Z
  7.             echo 'I am test!';+ v: z, v) Q  N9 g* I& C( x
  8.         }  o6 i% z% ~9 L% k+ k$ \
  9. }
    8 A% U5 a6 r+ }5 [8 I/ i2 W
  10. 8 j5 @" ?5 D8 V  j0 [% Z. N
  11. new \one\Person(); //输出 I am one!;, G1 k- f& P4 e, o) l1 q' S
  12. new Person();    //这里结果会是什么,自己猜猜看
复制代码
* G% L, j  L/ X4 r
最后,这个例子刷新了我对require的认识了。
按照我以前对require的理解:PHP 程序在执行前,就会先读入 require 所指定引入的文件,使它变成 PHP 程序网页的一部分。所以我常常就简单的理解为替换,只不过把抽离出来的代码再放回原处而已。然后我试了将1.php文件内容放到name.php里:
  1. //name.php3 {0 i2 r! v- _6 }" |1 a
  2. namespace test;% u% W2 F, R! ~9 L! o
  3. namespace one;
    8 z( f8 j* _" h  J( j! ~1 d. g' C
  4. class Person{
    ! @. }5 [/ ~5 J3 @- N
  5.     function __construct(){
    / d2 M$ ~$ l' D, s: r8 }
  6.             echo 'I am one!';
    4 e9 V! y; ^6 f$ i
  7.         }
    ; E$ ]+ B! Q; C
  8. }4 }( c2 @4 R; i1 U+ u+ h
  9. # R' R$ I* j" }" C
  10. class Person{
      s% D" W1 f6 B. o0 Y: p
  11.     function __construct(){: P! @) r4 ?( f0 T5 Q; D4 m9 R- z5 e9 p
  12.             echo 'I am test!';
    - n1 \# Y* D6 I& S) n  u) y
  13.         }
    8 C2 `9 F! f5 t
  14. }
复制代码

/ ~. l6 ]# e/ m9 J
无需new类,该文件就会报错:
  1. Fatal error:  Cannot redeclare class one\Person
复制代码
) N* i7 q( y  V- y0 p) H
看来简单的把require理解为替换,在这里行不通。

) m. L' q9 c2 [+ T. ^6.namespace里不包含类名称,即使存在与类名称同名的部分,那也不代表类。new类时,还是得将这部分带上。- O/ _+ Z: Y+ I* a
  1. //name.php) O% W/ J9 {8 s! j% N$ z& U( n

  2. & t' l+ B3 v- c, ^+ t- l2 o
  3. namespace test\person;
    : G  [# \4 }+ M( a. |

  4.   D( t' H) H) J/ \4 w6 t) ^
  5. class Person{" e* f* n$ _5 N
  6.     function __construct(){1 L4 `" r- n* B5 k  x, G# z
  7.             echo 'I am test!';
    ' p1 T* K2 o# f$ A7 X& B
  8.         }
    / K7 m+ H2 P/ k! X
  9. }
    8 N! Q' ]! v: k( k7 h
  10. new \test\person\Person();  //命名空间里person无法代表类名
复制代码

. _+ r7 L7 t. K
不过这样纯粹是画蛇添足,直接干脆点,namespace里不要带类名称就好。
3 O  q( D4 ?; O/ a
7.一个php文件中可以存在多个命名空间,第一个命名空间前不能有任何代码。
只说第一个命名空间前不能有任何代码,之后的命名空间之前可以有代码。这个自行测试即可。
  1. //name.php- [4 a2 @- k( j; f& Y: d7 r
  2. : A3 [# U+ {" t8 U( x8 S3 `
  3. namespace test;
    ; H8 J& x1 i! n* r" L
  4. echo 'zhai14';: ^8 p- @0 p" t8 ~! K1 V7 ]
  5. namespace zhai;* F5 Y& v# k6 B- Y
  6. require './1.php';
复制代码

6 n  U6 l2 t* z
php命名空间namespace告一段落了,接下来说说use的用途。
使用use的目的:
在命名空间字符串过长时,使用use可以相应的缩短命名空间。
+ x9 [2 r* \5 s% J- s1 \7 B) k
use的使用方法:1.new类时,最前面无需用反斜杠。此外,use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。
& A9 ^4 h& }( V- W( t
  1. //name.php
      g3 j* f0 ?5 g

  2. 1 i+ I# K. O3 ~/ U0 ^$ g- m
  3. namespace animal\dog;
    ! N) F4 U8 `: s3 Z/ p8 U$ T
  4. # S: J9 c  c" G8 }' N
  5. class Life{3 S7 V& R" E2 Y3 h7 E' @
  6.     function __construct(){1 Z" i. u9 z% T3 d# O* ?" T( [
  7.             echo 'dog life!';
    5 a8 M* d/ ~5 M  q) z7 Y0 G
  8.         }. K, o  m  [, k1 M" p
  9. }
    ' n6 h2 g9 K$ _% p# C$ U% w

  10. - F$ |" r+ n/ g% I' m, ?
  11. namespace animal\cat;
    % D; X+ }$ R, z/ U

  12. ) K4 g8 L8 m0 e1 W1 p1 e) V3 N+ w
  13. class Life{: Y9 b# Y+ w2 s* M
  14.     function __construct(){; V0 U0 I, d$ u  j3 i
  15.             echo 'cat life!';7 v) a8 l2 k" G( |2 c9 Y
  16.         }
    2 r* r/ W, x! p2 s+ a* e
  17. }( }" m+ C2 T) ~! u( y
  18. ! u% R4 m, C, N. H  [2 _! O
  19. new Life();  //按照代码执行顺序,这里默认animal\cat这个命名空间/ N5 y* j3 B0 y5 _1 Q
  20. new \animal\dog\Life();  //A& m6 E5 w9 y9 J
  21. 1 e( {: K* b- P* H: J5 }* e3 R( l6 ^
  22. use animal\dog;  //a3 O' P* ^+ T' V7 @! j* ]# E
  23. new dog\Life();  //B
    4 P/ A- `/ Z' D4 K3 {$ w# C

  24. & x: |7 e' z4 b# {2 I: K
  25. use animal\dog as d;  //b5 s$ k* J5 L  L) @4 l) G# Y6 `: D0 L
  26. new d\Life();
复制代码
5 [( D  p+ n5 O3 P" y6 R
通过A、B行代码比较,需要注意:
使用use后,new类时,最前面没有反斜杠。
没使用use时,命名空间最前面有反斜杠

2 Z' W8 L; K5 C- n2 v
通过a、b行代码比较,可以理解:
use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。如上的:
  1. use animal\dog;
复制代码
( P! U* N+ W5 ]1 R. ^0 N
相当于
  1. use animal\dog as dog;
复制代码
. I4 a2 r" K) }) P/ p
2.namespace后面不建议加类名,但use后可以。
% G' {' |* e0 Y( g: h) s$ i
  1. //name.php
    ) v8 g& t' E& i; D
  2. ( A, }+ O( r  r2 J4 R. y
  3. namespace animal\dog;) k; P! u& P! _  t4 X" ^" p
  4. . F* Y, m1 u4 ?. W* s$ m, [) A# t0 L
  5. class Life{
    3 }* ~) P8 o- \* K
  6.     function __construct(){
    - \. k$ n- j9 B7 o' [) R0 e  X
  7.             echo 'dog life!';; d( `! y2 T- Y  X* G8 K/ |
  8.         }
    7 c& j0 Q* n& C, X; ?, m* I
  9. }
    ( w& ]( w6 ]: q
  10. # ~0 |, }6 S$ e0 s4 v6 V( }
  11. namespace animal\cat;
    $ ]0 _8 I4 U' a  l1 e$ `( S

  12. " Y" X2 ~8 Y  y+ T/ ~
  13. class Life{
    6 \5 t4 x4 D  e9 n* {/ f
  14.     function __construct(){
    ( I4 Y8 v; Z' C4 p% a/ N
  15.             echo 'cat life!';
    & _% E5 t) @% [% {! N; V
  16.         }6 M' {, p$ f% G/ \  H4 H, ?6 B( M
  17. }
    1 f7 O5 G* V1 x) q  r/ N" m# g: v
  18. 2 e* L% C4 V3 d; v# ^+ b: `# Q/ Z" J9 ]
  19. use animal\dog\Life as dog;  
    5 q, d" f2 ^$ J  U- \1 j' G9 F
  20. new dog();
复制代码
# A4 n2 p* N5 C
如上所示,use后加上类名后,就相当于把类改了个名称:由Life改为dog了。
上面不用as dog就会报错:
  1. Fatal error:  Cannot use animal\dog\Life as Life because the name is already in use
复制代码
7 L2 j; |5 V7 ~! q
因为cat下也有个一样名称的Life类。
可以理解为,使用use后,这个昵称对应的类只能归当前命名空间占有,其它命名空间下不允许存在该类。
  1. //name.php
    6 q1 @  q4 n3 }% P, L

  2. + p" A# Z( ]- i* ~1 B
  3. namespace animal\dog;
    / O  A/ u$ S  n) k; \! t' ?
  4. $ v" S3 _# _0 q+ u) G* S/ f4 ?
  5. class Life{
    # A! z& B5 z, W+ V7 I4 \
  6.     function __construct(){
    2 C+ ~9 M* t9 x2 ?  M5 R( R+ g, G
  7.             echo 'dog life!';
    4 Z" F  o3 E  l
  8.         }" S3 w8 r. {, H# M. a7 n! [9 `
  9. }. }9 C' D/ p( J7 Y
  10. class Dog{5 K; G6 k9 N- M+ L- V
  11.     function __construct(){
    6 v1 S% L' Y! s3 L
  12.             echo 'dog in dog!';
    1 v+ Z% H; L# B4 }  o
  13.         }
    : V% U: f) D: Y, Z0 e0 N* h
  14. }, n. t. X/ N5 ~; ^
  15.   L8 V; U5 W0 W" D
  16. namespace animal\cat;
    + H0 S. B. K! i  p* B6 a
  17. ; L7 v- z3 \# J, q% R
  18. // class Dog{; `$ n& c8 @( b! S
  19. //     function __construct(){
    9 b4 M* l/ ]9 [. I) h
  20. //             echo 'dog in cat!';
    3 b$ U+ m, k+ U$ X4 j  m6 U
  21. //         }
    9 U2 S- T- T7 c% g2 N: ?. n; f
  22. // }' x6 w2 U9 {' Y' |
  23. class Life{
    , Q) n9 _- e+ R2 Y  B7 V
  24.     function __construct(){
    8 t! P- T- B7 V5 H5 F, B
  25.             echo 'cat life!';
    - l5 I" `8 M5 F3 p* @
  26.         }; `0 e& |3 E5 P, w, g3 V
  27. }1 \* u1 I# T! m7 t0 A# F, s  z
  28. $ Y% Y9 V! Y, C1 ?2 t
  29. use animal\dog;  
    ; ?  [/ n; Q. W* H  v) o
  30. new dog\Dog();
复制代码
9 F8 v1 }; p/ I+ t. E* ~- d
如上,使用了
  1. use animal\dog;
复制代码
  Y$ H( i; b, g  |8 f( k
cat
通过上面代码,我想使用use的目的效果(缩短命名空间名称)就很明显了。

+ @! W" R; Z) C+ f2 ?
简单总结一下:
namespace就是划分领域的作用,代表这些东西是属于某个命名空间下的。
use就是起小名的作用,不论写起来还是说起来都可以省不少事儿。

1 @4 w4 h/ @& [
- L; w$ S! G# F
  q7 E' C- H# R. j  C7 e3 n8 X
2 y# R0 h- j2 H5 g& _  z# c5 F  P1 E
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-1-30 14:39 , Processed in 0.062818 second(s), 20 queries .

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