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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

/ S7 }" X$ Y) N3 H0 l/ g" Z
文章大纲:
使用namespace的目的
namespace的使用方法
使用use的目的
use的使用方法

0 d- k3 T( M2 N0 d+ v+ k5 q4 H/ F) _9 e
使用namespace的目的:
团队合作项目时,避免与团队其它成员新建的类发生冲突;个人负责项目时,避免前后新建的类发生冲突;

) D8 C$ {" A- ]5 }; e* u
据个人理解,用到所需要的类时,需要先require或include引入,所以会发生类重定义的错误的前提是:两个相同命名的类都有被引入。目前有些php框架会自动加载(即include)所有新建的model类,所以为了避免你新建的model类和项目框架原生的核心类发生重名冲突,采用了namespace。(想了想,与团队成员新建的类产生冲突应该通过沟通避免,即使事发后也应该重新调整类名即时维护,避免后期造成因为对类的理解混淆而带来维护上的复杂度提高)
0 o& ^8 z) [* p4 o- i% d
结合使用方法来进一步理解它的使用目的吧。
  c& P6 v# U5 h9 X  ~- _8 M. @
9 ^! h$ ?6 P7 E
namespace的使用方法:
为了进行测试,我将创建3个文件:1.php和name.php(此文件用来执行测试),后面将不再说明,请自行注意代码的变化。
1.namespace后命名的定义不区分大小写
  1. namespace one;
    ) D! a. j# \, E7 k. q% e+ k
  2. namespace One;
    7 J" h- T4 j6 P. W3 V. f- C. n' ~
  3. namespace ONE;
复制代码

+ M( M$ \( W/ j1 S: ?
如上写法都可以,选择一种作为自己的规范即可。(后面代码我采用第一种进行测试哈)

  y! E8 @) r  G  h3 d* O9 c' G; Y2. 没有定义命名空间,就理解为使用顶级命名空间。new类时,可以在类前加上反斜杠\,也可以不加。
  1. //1.php   
    9 S( G% J1 x8 f" \) U, E
  2. class Person{
    ' L: _% z2 B  S' O$ m# Y/ F
  3.     function __construct(){
    . d) W: m. j5 H
  4.             echo 'I am one!';
    # H; f, Z, `9 }" C( ]9 N4 T" x
  5.         }
    2 \5 v, \, H- L* c
  6. }
复制代码
  1. //name.php
    ( L7 G8 ]4 S- R9 j2 B5 v: ?
  2. require_once './1.php';
    3 u$ b" x$ j+ {" @0 I- a" H

  3. ) n) k$ W- E% c% V- K% l
  4. new Person();     //输出 I am one!;, q6 v' I( T  q6 b
  5. new \Person(); //输出 I am one!;
复制代码
. b7 l: w. c: k, }2 A
3. new类时,带上命名空间时,之间一定用反斜杠字符,而不是顺斜杠。
记忆方法:按找%中斜杠的顺序理解为顺斜杠。(有时说反斜杠,自己都不知道是哪种方向,以前按自左向右上升方向这种方向记忆,现在感觉这个太不靠谱了)
  1. //name.php, x& C$ n8 k* n- ~$ |
  2. require_once './1.php';9 E  h: q( v9 D& G9 v4 ^6 b2 @
  3. new /Person();  // 代码报错:Parse error: syntax error, unexpected '/'
复制代码
1 q% R8 A3 D: e7 P! D& M- Z) w4 r
4.类在指定命名空间下, new类时,一定要带上指定的命名空间。
没有带上指定的命名空间,按照第2点,php就会从顶级命名空间里找这个类。切记:这里不能按照顶级命名空间包含一切其它的命名空间来理解。而应该将顶级命名空间完完全全与其他命名空间区分开。
  1. //1.php   $ [1 [+ h, c) ?
  2. namespace one;
    ' n% S0 b9 n9 z- c2 V
  3. class Person{
    # R6 O% O6 Q% E! E* X- g# Z
  4.     function __construct(){
    ; n$ ^" B7 z, I/ K. w
  5.             echo 'I am one!';/ o3 E+ ?1 z$ K& ], H! X% n7 D! V8 Y
  6.         }
    * m$ c' S4 P0 k- R
  7. }
复制代码
  1. //name.php
    / a2 f$ {  U( W$ x
  2. require_once './1.php';* v# W' }! g/ \
  3. new \one\Person(); //输出 I am one!;
    2 Y9 \8 R. q, z, R* Q
  4. new \Person(); //代码报错:Fatal error: Class 'Person' not found
复制代码

( s$ \2 l  |1 k0 o
可以举个这个通俗例子来理解:带上指定命名空间代表某人的苹果(在他手里),顶级命名空间代表苹果箱里的苹果(在箱子里)。现在要找某人的苹果,就将某人的命名空间带上,否则就会从箱子里找某人的苹果,结果当然是找不到。
% J9 ~$ G4 C8 e5 _0 P. o- l
5.命名空间声明后的代码便属于这个命名空间,即使有include或require也不影响(重点是对后半句的理解,具体看代码)。
& ]# Z( U7 z! g1 _& t5 d. E
  1. //1.php   ; T& z  X( @/ E1 B6 @1 H% r
  2. namespace one;
    , r+ z/ b3 G: ~4 G; |7 k
  3. class Person{
    - Q5 V5 m4 c: {/ U1 z: u
  4.     function __construct(){
      q- H9 r! ^3 \% J- N; ^% G$ Z1 n* o
  5.             echo 'I am one!';
    ' E$ }/ \% l% A. C
  6.         }
    8 _) F2 q( L) y* h. J* f
  7. }
复制代码
  1. //name.php
    2 {& |5 u: _' b- W: ~
  2. namespace test;& b* G4 W+ x8 O  R4 x1 k$ g
  3. require './1.php'; 7 ^$ W9 j  ?3 v* k4 v
  4. new \one\Person(); //输出 I am one!;
    9 H  l" P3 ~" `6 H& ^9 u8 S
  5. new Person();      //这里结果会是什么呢,猜猜看* q2 k' |4 `# S% z( i! u+ m7 t
  6. 最后一行结果报错:  r/ g. P& A5 B2 G
  7. Fatal error:  Class 'test\Person' not found
复制代码

: u( a5 B2 k% H% M* G

0 R& ^, `4 Q9 i; P首先,这里与第2点比较一下:
第2点,我说,没有命名空间时,new类时,有没有反斜杠意义一样。
在这里,有了命名空间,有和没有反斜杠的意义就不一样了。
最后一行换成
  1. new \Person();
复制代码
' d+ |/ G6 l$ ^  ?) L# `
结果报错:
  1. Fatal error:  Class 'Person' not found
复制代码
4 [* g# u/ `0 y+ N; W% J' j6 }  [
接着,就说说当前这点。
我们可以发现,最后一行代码对应的命名空间为test,并没有受到require文件里的命名空间的影响。
进一步加强验证,我修改了name.php文件如下:
  1. //name.php
    4 `/ n. ^2 t0 x3 q1 [6 |/ N
  2. namespace test;
    ! N* b" \8 z- U3 ?/ L# z6 s6 u( }
  3. require './1.php'; " V9 t) H+ A3 T! n% b1 n3 _
  4. % \5 J9 u5 v8 r& z5 b4 f
  5. class Person{7 G: J, a& }" C" Z* D
  6.     function __construct(){! M8 C$ x- c3 Y3 G# ~# n
  7.             echo 'I am test!';! G' _# T2 q9 f; n/ H0 R* x5 E" M
  8.         }
    2 K) d( g& R9 Z2 C& M9 w3 M
  9. }' ?6 o9 o) Z2 j1 t* T! f- b1 g& C

  10. 5 A0 a; m! p3 u5 {; S
  11. new \one\Person(); //输出 I am one!;$ Q& Y3 Y5 P( Z- a( [9 z
  12. new Person();    //这里结果会是什么,自己猜猜看
复制代码

( t8 u- ?! D8 L
最后,这个例子刷新了我对require的认识了。
按照我以前对require的理解:PHP 程序在执行前,就会先读入 require 所指定引入的文件,使它变成 PHP 程序网页的一部分。所以我常常就简单的理解为替换,只不过把抽离出来的代码再放回原处而已。然后我试了将1.php文件内容放到name.php里:
  1. //name.php
    : K/ h, p  o' ?
  2. namespace test;
    ; _: n/ w3 L) m! E9 @
  3. namespace one;
    ! G2 }1 i3 h' x& J
  4. class Person{
    4 }2 U4 l8 @3 W
  5.     function __construct(){
    % R& c$ v1 Z  `, M4 ^0 _  X0 Q
  6.             echo 'I am one!';3 R( ]. f; m' m9 U8 X2 f
  7.         }
    2 ^7 e- b+ L" w
  8. }
    " h# \3 D  `  |/ B  k1 W

  9. 7 @+ ^( M, H7 _, K0 U
  10. class Person{
    % G8 ?) s$ u) f. d5 @# a  t
  11.     function __construct(){
    " P& h. {- u7 i4 ]. A
  12.             echo 'I am test!';
    8 V. `; o2 s9 J; V
  13.         }
    8 v  @, q( z* n- a& W* L* f7 M
  14. }
复制代码

" Q/ T- e% D% F4 |
无需new类,该文件就会报错:
  1. Fatal error:  Cannot redeclare class one\Person
复制代码
6 W* s9 m- K% U) i
看来简单的把require理解为替换,在这里行不通。
7 k+ }# r# f  @, }9 c
6.namespace里不包含类名称,即使存在与类名称同名的部分,那也不代表类。new类时,还是得将这部分带上。7 q* E) a% z# R
  1. //name.php1 a) o, n( @/ v$ L& Y' Y: e
  2. - |% T  @' R/ h. W6 T6 }
  3. namespace test\person;5 m2 ~0 s( j  m3 U2 }- m6 }

  4.   `) P+ I, w+ Q  ~2 C; \5 ]
  5. class Person{
    , O! B! G# w0 ~5 O( o9 s& G- A
  6.     function __construct(){
    ) r9 z: M# A* ?: D# }
  7.             echo 'I am test!';
    ) v; Q4 `% s2 f( W& Y
  8.         }& N1 ~2 e2 W! ^5 W4 @
  9. }
    ' d; z5 Z+ j) g( N$ s# N
  10. new \test\person\Person();  //命名空间里person无法代表类名
复制代码

4 o( @7 U$ h( I+ n9 Y7 ]' n
不过这样纯粹是画蛇添足,直接干脆点,namespace里不要带类名称就好。
4 t  j7 o# O/ B& n/ r
7.一个php文件中可以存在多个命名空间,第一个命名空间前不能有任何代码。
只说第一个命名空间前不能有任何代码,之后的命名空间之前可以有代码。这个自行测试即可。
  1. //name.php
    % X9 p8 s, B/ P3 J& ?
  2. 0 W( u' v4 `6 }, p
  3. namespace test;
    ' D" d  r: W$ Q: y, |
  4. echo 'zhai14';! u: M9 E, q; d& F" I5 j# S6 w) f
  5. namespace zhai;" l! [) g; j- ~: f
  6. require './1.php';
复制代码

; r0 H; v& v* d/ D: |% K2 }3 Q
php命名空间namespace告一段落了,接下来说说use的用途。
使用use的目的:
在命名空间字符串过长时,使用use可以相应的缩短命名空间。

2 W; U  j, C0 v/ O, e) kuse的使用方法:1.new类时,最前面无需用反斜杠。此外,use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。8 X! R, O) S" G7 M( n/ k# u7 }
  1. //name.php
    & K5 L( [) ]3 M/ z7 x

  2. / w. [+ U& x, K+ E. b
  3. namespace animal\dog;6 p% f2 w8 R8 u1 U3 {
  4. 4 S6 X1 p/ k2 f5 T
  5. class Life{
    , W2 d4 ?# b1 m' n- ~
  6.     function __construct(){, e! m3 S; T- r) d
  7.             echo 'dog life!';  M1 S' }1 b8 k  j; x* A# w' ]6 h$ `
  8.         }
    . N6 c' ~; V; q2 Q5 ~
  9. }
    $ v5 ?8 d  k' G$ z
  10. , W3 W- S" s1 P# m  V6 q7 r+ o% N
  11. namespace animal\cat;5 i3 Y+ P  J7 W4 Q

  12. 5 X3 E' {) Q7 E9 t. R# o- Q% k9 `
  13. class Life{! G; `) m7 X' r2 {4 E
  14.     function __construct(){' i: l5 t# @( R) a0 y
  15.             echo 'cat life!';
    5 W& t4 ^, V8 S/ t+ |3 X! A+ n
  16.         }
    ' H) C. ?& z) E% v8 E8 I3 r) p
  17. }( k% e; k% G( N" K$ e

  18. 1 V' V0 H6 \: D! q7 A* p) J
  19. new Life();  //按照代码执行顺序,这里默认animal\cat这个命名空间+ ~* x9 L9 g1 P! M  F
  20. new \animal\dog\Life();  //A
    , j& r0 Z8 B: @) f
  21. - o  E  u! l7 E3 {: ], \3 B: I8 n" r
  22. use animal\dog;  //a: G" Z8 e0 t2 h' Y5 k4 w( |" E( V4 k
  23. new dog\Life();  //B
    " T: i' d) ?; V. z8 O- q

  24. 3 o- s9 T6 T$ _1 d. i0 `
  25. use animal\dog as d;  //b
    : u4 z/ M  v) l6 e+ G* R* g
  26. new d\Life();
复制代码

' E, N/ o4 u) Z( {9 b! G+ m
通过A、B行代码比较,需要注意:
使用use后,new类时,最前面没有反斜杠。
没使用use时,命名空间最前面有反斜杠

) `8 t- t/ O! m( J, V. P$ B4 F4 v
通过a、b行代码比较,可以理解:
use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。如上的:
  1. use animal\dog;
复制代码
7 Z- k& Y$ s. ]% E) y  J3 ]
相当于
  1. use animal\dog as dog;
复制代码

( ~- _2 g7 `) {5 c( T1 h) i  _2.namespace后面不建议加类名,但use后可以。
" B% b! Z' s! \3 A7 C4 a
  1. //name.php
    + o' Q2 f5 H: `) x3 d& t5 h* C  Y- l
  2. , z( e# g! w: J5 B' P$ Z0 x
  3. namespace animal\dog;/ B6 H1 [" G2 @$ N
  4. $ O% Y- y' U0 V6 t: V: r+ I
  5. class Life{
    ) d4 Y' N: ~" e" I% R- n9 J
  6.     function __construct(){( O$ T' Y0 `5 ~4 m7 s( ^% G
  7.             echo 'dog life!';$ ?6 j3 O0 z/ d' S! Q) {7 g1 F: I
  8.         }6 j' m. ~6 R7 S  L% U, e
  9. }
    4 |0 w4 S& ]: R3 _0 ?* j# C% C

  10. 4 z8 k" l- R# W5 _/ S" ?2 g
  11. namespace animal\cat;. [+ _: E" r# D. P0 Y1 H8 V6 ~

  12. 7 Z. I, D# m/ O/ B! \( c. ^& f
  13. class Life{
    ; Y9 `4 N; x- }
  14.     function __construct(){
    ; {( U, F; U" Y$ P0 b
  15.             echo 'cat life!';' d. l  Q8 `  G7 `% q
  16.         }
    9 n2 m0 y1 ?. h$ t3 T7 c8 r
  17. }
    2 U$ @6 O, L- G3 O& }8 W( m; c  s; m
  18. ! S6 Q4 a, _, r3 \1 I
  19. use animal\dog\Life as dog;  
    7 X5 x  S$ W$ D/ K7 h( A' u
  20. new dog();
复制代码
2 r9 [8 `3 @( Y! f
如上所示,use后加上类名后,就相当于把类改了个名称:由Life改为dog了。
上面不用as dog就会报错:
  1. Fatal error:  Cannot use animal\dog\Life as Life because the name is already in use
复制代码
9 \- S& m; u% |( a% K5 p2 }3 G
因为cat下也有个一样名称的Life类。
可以理解为,使用use后,这个昵称对应的类只能归当前命名空间占有,其它命名空间下不允许存在该类。
  1. //name.php* p' q! M1 D5 X+ o& h5 B& Y

  2. 8 _8 s$ j; i1 `/ d- b) e
  3. namespace animal\dog;
    * i, M# d0 x  @" d$ c( d
  4. 0 s6 a. w7 ^6 v7 [8 \6 |' x6 m
  5. class Life{& j* c. h# m* N5 B: M
  6.     function __construct(){
    & q! c& a2 u6 B
  7.             echo 'dog life!';
    - H5 x: t$ W6 }0 J) `5 f! a; T7 R
  8.         }( k( q6 e9 g. G' O) M
  9. }
      Q+ N7 p1 w+ c" x, Z4 q/ \
  10. class Dog{
    4 B+ Y& D) B& ]* I  \# `  v: \9 I
  11.     function __construct(){/ d& B  {8 E/ {, p5 l3 Z3 n7 H! Q
  12.             echo 'dog in dog!';
    ; V" U9 o" F" @/ F- I. u( C
  13.         }
    1 Q- Z+ F3 A1 H! o, T, o( a
  14. }8 A6 \5 q9 x9 m* B/ q
  15. ( X$ t) B* x/ \4 {+ T& E
  16. namespace animal\cat;
    9 @$ K3 n$ Q+ R6 Y

  17. 3 T2 Q  s, h7 r, @$ p" D. g! ?
  18. // class Dog{
    , E! v& z6 l( G' z
  19. //     function __construct(){' {# {& i3 e0 u$ K
  20. //             echo 'dog in cat!';
    3 a, F7 ~! n4 b# x: Z" J: a
  21. //         }5 M, F0 W- S$ A) V4 E- o1 e) q
  22. // }4 ^2 C2 `9 M  V$ k$ \# G* b6 r
  23. class Life{& |* J1 h8 q3 G) q( x. a7 F: d" p
  24.     function __construct(){
    9 a% L( `: N$ x3 X- h4 v
  25.             echo 'cat life!';3 ]  W5 O. G9 K/ `: E
  26.         }7 U; _& W0 b1 O3 h
  27. }
    3 e  e8 c9 ?* D6 @5 ^& o& B3 c

  28. ! @3 o3 D: r9 l' B) S! Z2 Z
  29. use animal\dog;  
    7 _6 G$ p( ~$ A8 F9 K2 q9 h
  30. new dog\Dog();
复制代码

9 }+ l3 ^9 E' q& H" r) Q
如上,使用了
  1. use animal\dog;
复制代码

5 b! D- {- V+ i1 k$ B* C5 D" f& b/ v
cat
通过上面代码,我想使用use的目的效果(缩短命名空间名称)就很明显了。
; w* a  O/ N. ?5 ~  c7 Q! C
简单总结一下:
namespace就是划分领域的作用,代表这些东西是属于某个命名空间下的。
use就是起小名的作用,不论写起来还是说起来都可以省不少事儿。
* U6 Q+ `3 Y1 s

5 Y( q6 E1 O2 m% u! d- @. H
& E  _) {1 X6 Y6 t. o5 Y4 n+ R0 r9 q
  m! D1 O) h8 y, V1 A1 I
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-6-19 22:23 , Processed in 0.053183 second(s), 19 queries .

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