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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2020-7-1 23:37:46 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
以下皆为本人自我理解内容,如有失误之处,请多多包涵。
9 X5 k! r' d9 f& S# p
文章大纲:
使用namespace的目的
namespace的使用方法
使用use的目的
use的使用方法
; r% {: W# j2 o2 i( J

' i' j1 ~3 r, B( z使用namespace的目的:
团队合作项目时,避免与团队其它成员新建的类发生冲突;个人负责项目时,避免前后新建的类发生冲突;
, ^6 h4 {! V9 J8 ~* [
据个人理解,用到所需要的类时,需要先require或include引入,所以会发生类重定义的错误的前提是:两个相同命名的类都有被引入。目前有些php框架会自动加载(即include)所有新建的model类,所以为了避免你新建的model类和项目框架原生的核心类发生重名冲突,采用了namespace。(想了想,与团队成员新建的类产生冲突应该通过沟通避免,即使事发后也应该重新调整类名即时维护,避免后期造成因为对类的理解混淆而带来维护上的复杂度提高)
5 C/ t, \) d& u; o1 e$ o
结合使用方法来进一步理解它的使用目的吧。

, U# a  r# e! P; b/ {$ J9 ?! n) Y) `  w$ m  ~# H2 z; U# f
namespace的使用方法:
为了进行测试,我将创建3个文件:1.php和name.php(此文件用来执行测试),后面将不再说明,请自行注意代码的变化。
1.namespace后命名的定义不区分大小写
  1. namespace one;* d7 [) d) K0 |# n5 z
  2. namespace One;0 G  s6 M$ ?% [6 q$ Z3 Q: e
  3. namespace ONE;
复制代码
% n* X/ s  T% s7 e9 Y, c" n
如上写法都可以,选择一种作为自己的规范即可。(后面代码我采用第一种进行测试哈)
# M" @' y: {( i9 U
2. 没有定义命名空间,就理解为使用顶级命名空间。new类时,可以在类前加上反斜杠\,也可以不加。
  1. //1.php   
    - L, q4 g) @7 B) \
  2. class Person{) x1 K. K  Q) ~
  3.     function __construct(){5 r( ?+ j9 c0 P5 ~9 k
  4.             echo 'I am one!';
    - q* B7 s* p( b4 d) W6 x$ N9 ]
  5.         }
      d$ c6 T+ B6 }- p
  6. }
复制代码
  1. //name.php
    6 s! D$ |+ e% p: [% w7 j
  2. require_once './1.php';; Z* k  }  x: X/ N% L7 R
  3. & C# h+ l: }' ^* k" K  m8 T3 l
  4. new Person();     //输出 I am one!;3 }6 l: L! b+ F/ T! g, D
  5. new \Person(); //输出 I am one!;
复制代码

4 X/ J* b1 E- M& ~9 K" m) {& I3. new类时,带上命名空间时,之间一定用反斜杠字符,而不是顺斜杠。
记忆方法:按找%中斜杠的顺序理解为顺斜杠。(有时说反斜杠,自己都不知道是哪种方向,以前按自左向右上升方向这种方向记忆,现在感觉这个太不靠谱了)
  1. //name.php8 O0 ?1 B9 ^: p  C
  2. require_once './1.php';
    4 F5 p/ y6 b: w' w; G
  3. new /Person();  // 代码报错:Parse error: syntax error, unexpected '/'
复制代码
5 f  }) B3 C7 f$ h  u
4.类在指定命名空间下, new类时,一定要带上指定的命名空间。
没有带上指定的命名空间,按照第2点,php就会从顶级命名空间里找这个类。切记:这里不能按照顶级命名空间包含一切其它的命名空间来理解。而应该将顶级命名空间完完全全与其他命名空间区分开。
  1. //1.php   
    , y  E7 A/ e+ L) F0 }# p+ H1 q
  2. namespace one;
      ?# |( x0 |% g, [* ?5 V& }
  3. class Person{2 q! W9 B7 |  q6 R; h, f- q
  4.     function __construct(){# f5 d6 G! @! `
  5.             echo 'I am one!';- {. P/ o! n2 J* k
  6.         }! J/ a3 i" L) L  a) E5 O) h
  7. }
复制代码
  1. //name.php
    , `1 a7 i. N  w7 |& E% O8 }) k( w& ~
  2. require_once './1.php';
      P; A  w; q; @, Y! T
  3. new \one\Person(); //输出 I am one!;
    : a+ |% h8 e* l" V: f2 U7 _
  4. new \Person(); //代码报错:Fatal error: Class 'Person' not found
复制代码

! \/ @; K7 g, B0 i( l6 N
可以举个这个通俗例子来理解:带上指定命名空间代表某人的苹果(在他手里),顶级命名空间代表苹果箱里的苹果(在箱子里)。现在要找某人的苹果,就将某人的命名空间带上,否则就会从箱子里找某人的苹果,结果当然是找不到。
/ v1 l5 r# }% p( b, }6 N. v
5.命名空间声明后的代码便属于这个命名空间,即使有include或require也不影响(重点是对后半句的理解,具体看代码)。! a8 o) |+ `. z! K3 ^
  1. //1.php   / ?5 j5 X5 j8 q, H! |4 R
  2. namespace one;4 D+ ?5 t+ q6 Z- ]
  3. class Person{
    % Y8 ~  _8 d/ p$ h
  4.     function __construct(){
    7 ~& U8 N0 w$ D
  5.             echo 'I am one!';( r" M9 a$ M6 a1 j8 m5 h9 {
  6.         }9 f' o9 t) l9 x7 ~/ z. g% I( ~  K
  7. }
复制代码
  1. //name.php9 C) O5 [5 A8 Q- @/ C
  2. namespace test;
    ! c3 h  ]; c( S: p6 v. m6 ^
  3. require './1.php';
    7 l" Q# I# }9 I7 v7 l; P
  4. new \one\Person(); //输出 I am one!;
    + l7 L7 a  J3 j/ p  X7 ]
  5. new Person();      //这里结果会是什么呢,猜猜看
      o( X+ z- C- V5 ?7 R0 e
  6. 最后一行结果报错:
    8 ?4 C" E% W* v3 p9 E1 z+ Z; F
  7. Fatal error:  Class 'test\Person' not found
复制代码

4 }0 D8 h% {2 x. c$ U
( q( n& e. r7 g
首先,这里与第2点比较一下:
第2点,我说,没有命名空间时,new类时,有没有反斜杠意义一样。
在这里,有了命名空间,有和没有反斜杠的意义就不一样了。
最后一行换成
  1. new \Person();
复制代码

9 \( o# f4 D! l1 s- c! p' M  f
结果报错:
  1. Fatal error:  Class 'Person' not found
复制代码
$ }' n$ E# }" d& N1 ?/ c8 i
接着,就说说当前这点。
我们可以发现,最后一行代码对应的命名空间为test,并没有受到require文件里的命名空间的影响。
进一步加强验证,我修改了name.php文件如下:
  1. //name.php
    * R2 A) R: P$ u, S+ V
  2. namespace test;' }' a: `# S) U& I4 W  \# b
  3. require './1.php'; 4 O0 q9 X: \4 B% N4 R- Q9 r
  4. 4 g5 p) z, ]% [5 r* B) M& ~$ p! X
  5. class Person{
    ! Q4 [2 ]2 t2 P
  6.     function __construct(){
    ' s# J" f# M, w: q" P5 i7 [
  7.             echo 'I am test!';
    ( G' k+ S* |" l8 G" `& H. q6 ]
  8.         }
    % j5 {6 I- @) y* W9 S
  9. }8 ]; S6 J& d- m" L

  10. ' b+ `4 M9 v: {2 l& D5 o8 C) M. _1 ?
  11. new \one\Person(); //输出 I am one!;3 C" J; R4 P* ]" [2 M9 c- p
  12. new Person();    //这里结果会是什么,自己猜猜看
复制代码
* C4 C' T9 Z& g7 Z
最后,这个例子刷新了我对require的认识了。
按照我以前对require的理解:PHP 程序在执行前,就会先读入 require 所指定引入的文件,使它变成 PHP 程序网页的一部分。所以我常常就简单的理解为替换,只不过把抽离出来的代码再放回原处而已。然后我试了将1.php文件内容放到name.php里:
  1. //name.php
    / G( S" Y# P: |8 @0 ~2 v
  2. namespace test;0 d0 ?% _1 e0 f! d$ j; w: ^
  3. namespace one;
    " h8 q" _2 r5 p2 U$ u
  4. class Person{
    ; P$ G- |% f9 U' M4 g) n" G
  5.     function __construct(){
    # c8 s9 E9 g% F1 J4 |, [! u# h
  6.             echo 'I am one!';
    2 K7 q  }- x: [# u
  7.         }3 ]( ?  @* |" ?5 p. F6 k  M
  8. }
    2 U  S0 T3 i+ g6 z9 \2 ]2 i
  9. ) q3 N& x; ~+ ]9 F7 K' I* m: r
  10. class Person{
    3 U# X$ t2 K" a: S0 D
  11.     function __construct(){% U! j/ }* `& k; v
  12.             echo 'I am test!';
    ! w  n2 W2 h; f) S5 y1 J! e
  13.         }
    8 o; ]2 \, K3 q( q
  14. }
复制代码

- I0 j! b6 [% @
无需new类,该文件就会报错:
  1. Fatal error:  Cannot redeclare class one\Person
复制代码
2 {$ Y* s% x: q3 e; F$ s
看来简单的把require理解为替换,在这里行不通。

7 }, s+ ], |, @5 S1 g* @  I$ F8 q6.namespace里不包含类名称,即使存在与类名称同名的部分,那也不代表类。new类时,还是得将这部分带上。, T: }- R9 b5 [4 g& ~9 {3 o4 _1 |
  1. //name.php/ E& t( e- ^1 j" H
  2. $ U( d4 _0 D! t7 }' t- s" {; q3 C
  3. namespace test\person;8 [* F& o) E$ |( I& Q4 S/ x
  4.   N: r/ y2 ?% }1 @4 H- m7 R+ F+ d
  5. class Person{
      t- d. M8 ?6 Q" p, j
  6.     function __construct(){  j0 N  [5 C/ [' K: M5 X; N9 C
  7.             echo 'I am test!';, n* W# U1 z1 H& ?* j2 [/ _7 U
  8.         }
    $ J+ O3 c' |/ P* x( _: S
  9. }
    : {5 J, s1 \1 c& F
  10. new \test\person\Person();  //命名空间里person无法代表类名
复制代码
3 d+ @7 j2 }6 H" q* k2 d7 g
不过这样纯粹是画蛇添足,直接干脆点,namespace里不要带类名称就好。

5 ]! t/ M8 K" D7.一个php文件中可以存在多个命名空间,第一个命名空间前不能有任何代码。
只说第一个命名空间前不能有任何代码,之后的命名空间之前可以有代码。这个自行测试即可。
  1. //name.php
    : O5 [- @. w- Z( p- P& Z

  2. ! W9 }8 z! E- ^, ?- v
  3. namespace test;6 ?4 w) u1 K! [4 @" r! o
  4. echo 'zhai14';
    ! \- B# P* h0 X: K3 d; s- G1 z- N* l
  5. namespace zhai;
    ) n8 F$ B; d8 L8 e! f
  6. require './1.php';
复制代码
4 e& ?- h* x' ?' R/ z' y) c
php命名空间namespace告一段落了,接下来说说use的用途。
使用use的目的:
在命名空间字符串过长时,使用use可以相应的缩短命名空间。
1 r1 f- _: [4 p. }: ]7 F
use的使用方法:1.new类时,最前面无需用反斜杠。此外,use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。
$ ]$ g: w% T( N6 @
  1. //name.php
    8 q; s/ c" N7 `
  2. + F, b1 C8 j: u0 A3 H
  3. namespace animal\dog;  k1 [2 A# S. s% j: k$ M5 U
  4. ( u/ y( M: ]3 p* U! F
  5. class Life{4 O( w- @" C# `6 i6 G$ e/ w
  6.     function __construct(){
    & B% B& K3 }6 c6 x* N" L# p
  7.             echo 'dog life!';
    0 C% ]  x0 `6 t5 ?6 O
  8.         }
    2 P) R$ A) f. B# n1 C1 J
  9. }
    7 O- L1 r; Y& ~) F" n. _
  10. 9 Q& i! D; C( O) h
  11. namespace animal\cat;
    ( Y: F3 t* I) `1 H1 [9 p

  12. 6 {- C0 ~* o0 m& }6 f
  13. class Life{
    2 [2 `% J2 A: y& j" {7 t- K
  14.     function __construct(){
    " U, Y# l8 o: @5 w+ A, l
  15.             echo 'cat life!';3 [# H0 K" E$ r6 }- r# N  V
  16.         }) T0 {4 T0 W! W* P) n
  17. }
    3 V/ `! O3 R6 p4 o6 E
  18. 7 j, s; B1 m# @: N
  19. new Life();  //按照代码执行顺序,这里默认animal\cat这个命名空间
    5 I. I: L3 _6 Z$ x; I3 c  B7 J. F
  20. new \animal\dog\Life();  //A3 @9 [) x* a( G; p& o' q

  21. 0 M, S2 K# T! w  r0 C4 \. f
  22. use animal\dog;  //a+ ]8 S2 [" y4 }# ?
  23. new dog\Life();  //B- Q3 F# {: x  I# b7 ?

  24. 6 D4 M# B1 Y$ J
  25. use animal\dog as d;  //b( o  x: G; g2 r: Z' v0 m
  26. new d\Life();
复制代码

% r5 |* d" F$ U' P6 a
通过A、B行代码比较,需要注意:
使用use后,new类时,最前面没有反斜杠。
没使用use时,命名空间最前面有反斜杠

, f1 p& [: ]! e7 M# G
通过a、b行代码比较,可以理解:
use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。如上的:
  1. use animal\dog;
复制代码

  U  b! ~8 T8 z, V0 f
相当于
  1. use animal\dog as dog;
复制代码
2 U5 W2 c: g2 Y& K* I
2.namespace后面不建议加类名,但use后可以。. \- ~- f4 o' U8 e8 [% A1 Q
  1. //name.php
    ; O; P4 F1 D: G/ M+ H$ [
  2.   n# g, L2 u$ M! y
  3. namespace animal\dog;: ]; O. g1 `/ M  {( \. s6 C
  4. $ l3 Z/ ]+ Z- Q5 \/ B$ W
  5. class Life{; j: P2 y  J/ k; _1 P8 n7 [: A
  6.     function __construct(){; R& B. l4 i5 h% \6 c
  7.             echo 'dog life!';
    9 {3 |5 S+ A4 \
  8.         }
    5 H* U7 l$ l6 W/ m0 f
  9. }0 ?' P1 r5 @: P  c
  10. 8 a; `% B4 q6 e$ }5 U
  11. namespace animal\cat;; o- }. _1 a9 G5 n% U/ b
  12. # {/ \" K0 d7 K6 h! _4 g
  13. class Life{
    # q8 q( g' Q' f3 {/ h: h+ r
  14.     function __construct(){
    : k$ V# O, r$ y. u
  15.             echo 'cat life!';: e) u1 g. [3 r( u
  16.         }
    " s" h; K4 I8 w0 o
  17. }
    8 l4 K! S. u+ C

  18. . a: j$ `# @, _8 d: m
  19. use animal\dog\Life as dog;  
    4 [) o6 h+ a5 N1 S) z
  20. new dog();
复制代码

" ?/ E# J" f  ^6 m5 }
如上所示,use后加上类名后,就相当于把类改了个名称:由Life改为dog了。
上面不用as dog就会报错:
  1. Fatal error:  Cannot use animal\dog\Life as Life because the name is already in use
复制代码

$ D# f- v8 m; W$ U8 T( L
因为cat下也有个一样名称的Life类。
可以理解为,使用use后,这个昵称对应的类只能归当前命名空间占有,其它命名空间下不允许存在该类。
  1. //name.php) G( ?7 E% s1 N
  2. ) U% F- Q) g2 Q) y9 b
  3. namespace animal\dog;
    3 `2 z6 u1 w! s. W1 Q

  4. * U, U1 t* o4 W" ~4 a
  5. class Life{
      G1 \! ~& ^5 \& d
  6.     function __construct(){
    1 M8 a) [+ r) G1 m% E
  7.             echo 'dog life!';
    6 t# F, K2 w3 K3 M
  8.         }3 ^7 C) @: e8 e( I. `
  9. }
    + V1 r$ @& C& f/ n0 L0 }
  10. class Dog{
    % G1 V7 Y8 k7 g! V, u& o4 x7 |
  11.     function __construct(){
    2 g/ T5 k* r9 c% V- T
  12.             echo 'dog in dog!';  F+ _" H4 p; |* z
  13.         }: u6 t5 @  Z2 c/ X) z" X0 }( [
  14. }
    , X  M1 Z- l$ O+ Y- t$ \
  15. # y: {% M  L, v2 K6 e' n1 f
  16. namespace animal\cat;
    1 \3 ?: d  f) W  I$ n& ^

  17. 3 o9 Q! x; X. a0 w, J- w/ m3 z
  18. // class Dog{
    2 S- W, a/ z# o; _5 B
  19. //     function __construct(){  }  \( b5 D0 |: P& S2 `) Q# R
  20. //             echo 'dog in cat!';
    * s# i9 |! }) l$ T9 \$ e4 D
  21. //         }( H: [& M$ d% u1 s/ m
  22. // }
    7 g1 g3 y/ i4 q' `
  23. class Life{  D* D! h; F! `/ W* D& ?7 S
  24.     function __construct(){
    + m  O  j+ X7 E* z
  25.             echo 'cat life!';
    1 b9 ~8 A" Q- Y" l+ K/ A! t. n/ Y  R
  26.         }
    : |5 E1 U( ?+ ]) c2 ?) Y+ Q
  27. }% w0 d4 O% q2 P2 I5 E' c
  28. / Q# I2 j9 x1 R
  29. use animal\dog;  2 A* u% P& e& s' {4 C# n6 M4 O
  30. new dog\Dog();
复制代码
+ x/ x7 ^; j' H
如上,使用了
  1. use animal\dog;
复制代码

8 s- g' E7 j+ l% y
cat
通过上面代码,我想使用use的目的效果(缩短命名空间名称)就很明显了。
! e) D5 c' @, i" e
简单总结一下:
namespace就是划分领域的作用,代表这些东西是属于某个命名空间下的。
use就是起小名的作用,不论写起来还是说起来都可以省不少事儿。

- x1 X  {! M- K, C9 C( }' ^9 I: N; `9 |4 L9 c3 {1 v

1 C7 ]7 G9 T( O+ ~3 z7 e
5 z8 S1 s2 Y2 J- \8 q
! @1 i* |! r+ B4 \) Q- J) m1 Y
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-9-21 02:07 , Processed in 0.055720 second(s), 19 queries .

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