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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2020-7-1 23:37:46 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
以下皆为本人自我理解内容,如有失误之处,请多多包涵。
( f. p8 Q' Y. c
文章大纲:
使用namespace的目的
namespace的使用方法
使用use的目的
use的使用方法
* J$ t8 J8 w+ `) M  f; V
! u4 O2 x3 \3 l# B/ O" G9 {
使用namespace的目的:
团队合作项目时,避免与团队其它成员新建的类发生冲突;个人负责项目时,避免前后新建的类发生冲突;
2 H# j* S- g4 l) ]8 O
据个人理解,用到所需要的类时,需要先require或include引入,所以会发生类重定义的错误的前提是:两个相同命名的类都有被引入。目前有些php框架会自动加载(即include)所有新建的model类,所以为了避免你新建的model类和项目框架原生的核心类发生重名冲突,采用了namespace。(想了想,与团队成员新建的类产生冲突应该通过沟通避免,即使事发后也应该重新调整类名即时维护,避免后期造成因为对类的理解混淆而带来维护上的复杂度提高)

+ {, N( j0 E& K8 Y. i9 l. G1 P结合使用方法来进一步理解它的使用目的吧。

8 P8 E6 T3 d& y( |
  n7 x" |; f9 v; j0 T/ Qnamespace的使用方法:
为了进行测试,我将创建3个文件:1.php和name.php(此文件用来执行测试),后面将不再说明,请自行注意代码的变化。
1.namespace后命名的定义不区分大小写
  1. namespace one;
    , F) d# O5 ]& v/ a& \" n% ^+ _
  2. namespace One;
    5 f# d; z/ K! g1 B
  3. namespace ONE;
复制代码

$ s0 n+ H- v4 ~+ X$ T  A$ E! \5 W! S+ c
如上写法都可以,选择一种作为自己的规范即可。(后面代码我采用第一种进行测试哈)

8 w- ?4 F- n; Z$ Z& L; T+ m2. 没有定义命名空间,就理解为使用顶级命名空间。new类时,可以在类前加上反斜杠\,也可以不加。
  1. //1.php   7 a5 P! \3 V, V+ E, M7 l
  2. class Person{
    9 F8 B$ p1 J: {3 ~4 U, [% z
  3.     function __construct(){+ |2 F. E* i) A1 [; ]( n% `7 `
  4.             echo 'I am one!';! [8 d/ ^- i0 G) J9 `' v
  5.         }" u0 j) Q5 l: A% l; S4 J/ a
  6. }
复制代码
  1. //name.php
    & z* b+ \% A+ r
  2. require_once './1.php';6 {1 |% X5 F, J$ T, A
  3. . `3 _3 {2 f) O- }& @* M- a) k
  4. new Person();     //输出 I am one!;6 ]( |! B4 ^+ i8 _  L1 `! T
  5. new \Person(); //输出 I am one!;
复制代码

7 d! L, ~( ?8 {4 Z: b$ @4 d/ Z$ w3. new类时,带上命名空间时,之间一定用反斜杠字符,而不是顺斜杠。
记忆方法:按找%中斜杠的顺序理解为顺斜杠。(有时说反斜杠,自己都不知道是哪种方向,以前按自左向右上升方向这种方向记忆,现在感觉这个太不靠谱了)
  1. //name.php+ {; L# _  o' A4 S1 w+ d: E: i
  2. require_once './1.php';- h3 s0 V" h" X& j4 {
  3. new /Person();  // 代码报错:Parse error: syntax error, unexpected '/'
复制代码

( J' I- D7 x  {7 n4.类在指定命名空间下, new类时,一定要带上指定的命名空间。
没有带上指定的命名空间,按照第2点,php就会从顶级命名空间里找这个类。切记:这里不能按照顶级命名空间包含一切其它的命名空间来理解。而应该将顶级命名空间完完全全与其他命名空间区分开。
  1. //1.php   
    . b) z! Q4 }, x- s: q3 k9 ]0 W6 p+ G& j8 r
  2. namespace one;4 o+ |$ S' k& }
  3. class Person{+ ~3 M# Y" `& b3 K
  4.     function __construct(){6 R! s9 K: G4 A9 c( I0 {% j
  5.             echo 'I am one!';
    ; a6 d0 P2 D. I! `: i3 Z
  6.         }
    ) y' }1 [9 g0 t2 [
  7. }
复制代码
  1. //name.php( ~& v5 t# Z  K9 C  C
  2. require_once './1.php';
    , o8 s' r! L8 C, ~: L& `9 L
  3. new \one\Person(); //输出 I am one!;
    , V9 V+ m6 g" {* w+ ]0 Q7 N/ H4 C7 a
  4. new \Person(); //代码报错:Fatal error: Class 'Person' not found
复制代码
3 R3 g2 T# Z+ m1 {
可以举个这个通俗例子来理解:带上指定命名空间代表某人的苹果(在他手里),顶级命名空间代表苹果箱里的苹果(在箱子里)。现在要找某人的苹果,就将某人的命名空间带上,否则就会从箱子里找某人的苹果,结果当然是找不到。

( D, a' j2 B7 h5.命名空间声明后的代码便属于这个命名空间,即使有include或require也不影响(重点是对后半句的理解,具体看代码)。
9 D* b: R5 R- t% f6 E& f- D+ v
  1. //1.php   2 j  M5 f' Q* Y6 A; f+ [2 q! X) V
  2. namespace one;
    $ s. _/ [% N$ a9 N9 a
  3. class Person{
    6 s, n/ p% D) `8 v1 ~
  4.     function __construct(){2 `9 _2 k5 K# G+ N1 E  X: G3 F& P
  5.             echo 'I am one!';
    + p+ N" t) a) a: g
  6.         }
    1 J4 T! I8 {3 R% w- I
  7. }
复制代码
  1. //name.php6 a! q  R  g" A/ t0 e8 p' t
  2. namespace test;
    8 Y8 L2 \1 ~# o+ \
  3. require './1.php';
    : \; s- t0 `6 O. d" [' l# I0 |
  4. new \one\Person(); //输出 I am one!;
    - f9 ^7 V$ j5 \3 [0 e+ ]" ^& s
  5. new Person();      //这里结果会是什么呢,猜猜看% e8 M- g  ?: p! A* S% G2 Q: a
  6. 最后一行结果报错:2 t: g; _2 Y* |# R5 s. q
  7. Fatal error:  Class 'test\Person' not found
复制代码
1 j% T5 \$ A" z. b% Z
# R& X. {" R" Y! X
首先,这里与第2点比较一下:
第2点,我说,没有命名空间时,new类时,有没有反斜杠意义一样。
在这里,有了命名空间,有和没有反斜杠的意义就不一样了。
最后一行换成
  1. new \Person();
复制代码
. {% B7 v# G" p1 ?; C0 j
结果报错:
  1. Fatal error:  Class 'Person' not found
复制代码

! b! w; h9 _8 @( B9 e+ [; |
接着,就说说当前这点。
我们可以发现,最后一行代码对应的命名空间为test,并没有受到require文件里的命名空间的影响。
进一步加强验证,我修改了name.php文件如下:
  1. //name.php
    & ?7 r) Y* X3 P0 W/ W
  2. namespace test;$ o5 w$ x  v3 ~  a$ ~. b
  3. require './1.php';
    : ?: F/ v3 u2 m. J4 p* t
  4. 0 K: {1 N, i1 H. ^
  5. class Person{
    & h" o8 i7 _4 F- Q, a) b
  6.     function __construct(){
    6 J; ^2 R. A% r8 s
  7.             echo 'I am test!';' o% c' ]  ]3 X, v8 l4 ]5 Q
  8.         }; ~* H5 `/ o1 i) O% e
  9. }
    / F6 y; t2 f# f0 o( c3 \; f/ y

  10. : s- E% H* s8 Z3 i  Z
  11. new \one\Person(); //输出 I am one!;
    ; b" _2 d/ w) f3 b" T
  12. new Person();    //这里结果会是什么,自己猜猜看
复制代码

7 x' s/ Y9 g! ~0 M) b: m* ]8 B
最后,这个例子刷新了我对require的认识了。
按照我以前对require的理解:PHP 程序在执行前,就会先读入 require 所指定引入的文件,使它变成 PHP 程序网页的一部分。所以我常常就简单的理解为替换,只不过把抽离出来的代码再放回原处而已。然后我试了将1.php文件内容放到name.php里:
  1. //name.php9 l& [" l# n/ \! {! [
  2. namespace test;
    ' {1 T4 Z. f! G* w9 J
  3. namespace one;
    + u0 {5 M# {& `( d5 H& z; X7 M
  4. class Person{  h) u' ]3 o) y: \# B5 J
  5.     function __construct(){
    6 M  V- z; ~$ X  j% H
  6.             echo 'I am one!';6 e' {  \$ O, L+ P# W+ V- p, {
  7.         }9 v* f. Y8 i" C4 y9 ~; f; @
  8. }
    " q* x0 p8 p# S% Q0 W

  9. - S9 q3 A& ^; H( Y+ z: J
  10. class Person{
    3 Z& E0 E3 G* u0 d
  11.     function __construct(){' K) Q5 z, n: n- h$ j
  12.             echo 'I am test!';
    7 C/ a8 P7 u/ u9 e/ r( n  H8 _, d+ C
  13.         }
    0 R0 b( E7 p( }8 b" c- M( Z
  14. }
复制代码

- h* t+ f( U+ `% f1 Q, n
无需new类,该文件就会报错:
  1. Fatal error:  Cannot redeclare class one\Person
复制代码

4 N' n- u  X( C5 `" E) w2 X
看来简单的把require理解为替换,在这里行不通。

1 D: P' v. G6 ~8 k: h6.namespace里不包含类名称,即使存在与类名称同名的部分,那也不代表类。new类时,还是得将这部分带上。
* i5 ~) q) @: V, h4 u0 e: ]
  1. //name.php7 g% ?, w! u+ r& b  V' v, Z) u
  2. 2 ?- _2 Q* u2 k
  3. namespace test\person;6 @. i9 G; j' o. C, ?) z( c3 r

  4. ; |; Z7 f% }+ H9 k
  5. class Person{
    0 \$ m3 ?9 I) X* H0 z
  6.     function __construct(){
    , U7 d2 `9 J/ F) K8 R  h
  7.             echo 'I am test!';% b; a4 m) w+ N, E, P, c8 u
  8.         }6 m6 j$ f# k. ?
  9. }
    # g0 R4 A) D4 W( \
  10. new \test\person\Person();  //命名空间里person无法代表类名
复制代码

$ V5 ~' Z2 x) t1 A4 u
不过这样纯粹是画蛇添足,直接干脆点,namespace里不要带类名称就好。

* U5 _7 I  N  v( S7.一个php文件中可以存在多个命名空间,第一个命名空间前不能有任何代码。
只说第一个命名空间前不能有任何代码,之后的命名空间之前可以有代码。这个自行测试即可。
  1. //name.php
    . g# I. A, ^- i8 ~7 }) s
  2.   f! R  M. f. U& \
  3. namespace test;
    , w+ N$ ?+ T# k5 F1 Y. [
  4. echo 'zhai14';, M& x1 ?1 b* J5 O- v! o
  5. namespace zhai;" m; P- j; }8 f! _2 X3 l/ q8 i& a
  6. require './1.php';
复制代码

) B# b5 J* Q/ |' D8 k* {
php命名空间namespace告一段落了,接下来说说use的用途。
使用use的目的:
在命名空间字符串过长时,使用use可以相应的缩短命名空间。
( i3 M, p6 |% s# m+ V
use的使用方法:1.new类时,最前面无需用反斜杠。此外,use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。2 m1 x+ s; |) w* U
  1. //name.php1 S5 x( N+ ?; s+ t
  2. 9 ~: O' h7 L" O  m: S7 \
  3. namespace animal\dog;
    % t0 `% u+ E+ _! G

  4. 7 f, X. y, J/ O' m' k8 d
  5. class Life{
    1 ^- s8 j/ A2 `  y
  6.     function __construct(){8 z1 B9 D, C- m
  7.             echo 'dog life!';
    / s6 `0 @3 l2 t( S4 F
  8.         }
    / F! C) n) j4 o9 x
  9. }
    * T2 H, _: m) m9 C! ]' E

  10. & h; C! _" f0 G; ~, {$ Q+ E
  11. namespace animal\cat;3 m" m: r4 J" e1 g
  12. 9 X8 p- Z- o, p
  13. class Life{* G; k/ D) v: y$ P- x
  14.     function __construct(){
    ; v; I6 ?! I8 W4 z
  15.             echo 'cat life!';% H8 E8 ?! O9 O
  16.         }: E* {" P3 |/ }+ H+ W3 d4 s
  17. }9 c* I: q6 A2 ~% U5 ~& Y/ S

  18. ' _& S  ^1 x( o8 h* O! n
  19. new Life();  //按照代码执行顺序,这里默认animal\cat这个命名空间
    : e1 v- e* A& ]. ^/ ]* q* |1 w9 k
  20. new \animal\dog\Life();  //A  B3 X" f; o% e- e: D

  21. 3 W% t% R) N+ D; z+ P
  22. use animal\dog;  //a  g; ?! r9 j, v$ f, U4 ]; j- \
  23. new dog\Life();  //B
    & `" @" {2 K4 n- t8 V# h
  24. $ `/ {3 U6 F; n% y5 [! }
  25. use animal\dog as d;  //b1 n! b9 M9 S6 d, K% \
  26. new d\Life();
复制代码

% l" r- x8 U/ {# Q$ A
通过A、B行代码比较,需要注意:
使用use后,new类时,最前面没有反斜杠。
没使用use时,命名空间最前面有反斜杠

+ z) j( L5 c9 t: ^* _8 u& a
通过a、b行代码比较,可以理解:
use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。如上的:
  1. use animal\dog;
复制代码

5 ?& X! ]2 ]6 r$ L# C3 O4 B0 ~
相当于
  1. use animal\dog as dog;
复制代码

" o3 q) G0 f( Q  T- p2.namespace后面不建议加类名,但use后可以。! n7 Q0 }, C, ]: E" }# G& v
  1. //name.php; f, {+ V7 |  D3 {% K1 [1 n* H
  2. # S3 _0 }- u5 f! \7 S4 _
  3. namespace animal\dog;0 X- P  g* D, g  t8 c

  4. , A  s) E9 p6 Y4 W
  5. class Life{
    0 i" Q% ^( i# W4 }' O& w  A
  6.     function __construct(){
    8 j: t, o3 Q' C: S; X' s5 e& ?
  7.             echo 'dog life!';
    ; M0 ^& K( r  l3 X. \9 ]
  8.         }9 Z" b. O& V. U1 c! I7 G. x
  9. }
    ' k. r, y! R1 F

  10. 2 F: Y( i; J9 {& ?
  11. namespace animal\cat;
    4 D8 K+ j: q0 x/ ?" y
  12. 6 g0 r7 l/ f: U; T- m! J: b
  13. class Life{
    . f  R3 }  ^- t/ M! d. |  _
  14.     function __construct(){7 z+ Y5 _6 e9 q7 V1 U0 V
  15.             echo 'cat life!';
    0 V7 M$ e; f4 n/ z! M# T" G9 f6 |
  16.         }
    ; _( D! Y( O6 O( c- Y
  17. }
    9 k& a( m# \" w% \

  18. # [- k0 t8 l/ ^
  19. use animal\dog\Life as dog;  
    9 N/ w- P+ z" T
  20. new dog();
复制代码
1 g+ g5 X6 }2 i: A7 V& a
如上所示,use后加上类名后,就相当于把类改了个名称:由Life改为dog了。
上面不用as dog就会报错:
  1. Fatal error:  Cannot use animal\dog\Life as Life because the name is already in use
复制代码

" O5 b0 ^2 L4 ]- v0 i
因为cat下也有个一样名称的Life类。
可以理解为,使用use后,这个昵称对应的类只能归当前命名空间占有,其它命名空间下不允许存在该类。
  1. //name.php
    , w" O4 U' u. _/ A3 }

  2. 2 S" N0 _! H0 `+ {! G+ U
  3. namespace animal\dog;! H9 F6 v) e+ M( L& `
  4. % d6 r' r) h# t
  5. class Life{' H, i2 C/ M) ?4 I1 \
  6.     function __construct(){6 v* D1 ^9 U. G9 F) ]# E
  7.             echo 'dog life!';, O: S# _; H* E
  8.         }: S/ U: ^/ {% U# w; j" d4 m% Q+ x
  9. }: P( n& P7 h+ @( i5 K
  10. class Dog{
    : V  Z/ |2 p. Y* {2 w
  11.     function __construct(){$ {0 J# I- N' L  s6 C( `
  12.             echo 'dog in dog!';9 `/ p& o6 R+ M5 r- m* c" @1 T
  13.         }
    1 J% S/ R8 i) M6 c- N8 J3 B. u
  14. }
    , ]' u5 V2 Y3 N! X. C+ P
  15. 2 C4 L$ {( H0 Y- C
  16. namespace animal\cat;
    ! i. N* f. Q3 p+ I: R

  17. - h/ x# v: |9 h4 I- V/ o" Q  y
  18. // class Dog{
    ' I  Z/ t/ Q. F: N/ l" m
  19. //     function __construct(){
    ; e! v6 e. [; g( S
  20. //             echo 'dog in cat!';- `/ T5 t: k# {  H9 @$ m
  21. //         }$ d4 w* g$ W% Q  Y3 F7 x* P* X
  22. // }  G  l7 ^6 [1 o9 u5 u9 A0 k& T
  23. class Life{
    ' L9 ]3 [% k6 q, ]3 M3 G
  24.     function __construct(){/ h% f: K$ M$ ~1 A! \& k
  25.             echo 'cat life!';1 S' m! m" K# l# T
  26.         }" v# W% x) B1 w
  27. }
    & M) f" N4 a8 {- ~9 _

  28. * f) ~/ E7 l" X1 r7 ^, F
  29. use animal\dog;  
    / z) n, i$ ?* k2 E7 r
  30. new dog\Dog();
复制代码
, Y( N  }- l, l# L, D0 W
如上,使用了
  1. use animal\dog;
复制代码
, D) ~  q" {! t& R" O1 Y3 B4 [
cat
通过上面代码,我想使用use的目的效果(缩短命名空间名称)就很明显了。
! g7 e+ s4 `0 ^2 D/ b0 Y
简单总结一下:
namespace就是划分领域的作用,代表这些东西是属于某个命名空间下的。
use就是起小名的作用,不论写起来还是说起来都可以省不少事儿。
% _) g; G0 Z' n6 p- _
' ?8 ]) I5 p5 o4 F7 o  g
' @8 X3 l* Y2 t9 @* k2 p* z& ~
( l) U0 U; `6 ]; o' n  g$ i

/ b7 o' G, }! h: t4 h& q
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-6-19 21:02 , Processed in 0.080364 second(s), 20 queries .

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