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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

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

1 \; I6 G* s" m) Z6 t" m" L  T
文章大纲:
使用namespace的目的
namespace的使用方法
使用use的目的
use的使用方法

, S6 ]: i0 V! \, x
$ f- p. U; g: W2 h: U0 j, o使用namespace的目的:
团队合作项目时,避免与团队其它成员新建的类发生冲突;个人负责项目时,避免前后新建的类发生冲突;
! Q, @1 p3 f$ `8 N
据个人理解,用到所需要的类时,需要先require或include引入,所以会发生类重定义的错误的前提是:两个相同命名的类都有被引入。目前有些php框架会自动加载(即include)所有新建的model类,所以为了避免你新建的model类和项目框架原生的核心类发生重名冲突,采用了namespace。(想了想,与团队成员新建的类产生冲突应该通过沟通避免,即使事发后也应该重新调整类名即时维护,避免后期造成因为对类的理解混淆而带来维护上的复杂度提高)
% x1 L+ Y" p$ O% ~. w
结合使用方法来进一步理解它的使用目的吧。

) n7 }( r4 l: [' g9 W" C1 Z6 a3 |8 {# p  F8 ^
namespace的使用方法:
为了进行测试,我将创建3个文件:1.php和name.php(此文件用来执行测试),后面将不再说明,请自行注意代码的变化。
1.namespace后命名的定义不区分大小写
  1. namespace one;; D" q# U9 Q/ F, y! Q: A! R! m( J
  2. namespace One;4 N; X/ t2 Y5 S" e
  3. namespace ONE;
复制代码

* V9 u  B. j& c* G# Q' U  {0 d
如上写法都可以,选择一种作为自己的规范即可。(后面代码我采用第一种进行测试哈)

4 r6 B7 g. B: P2. 没有定义命名空间,就理解为使用顶级命名空间。new类时,可以在类前加上反斜杠\,也可以不加。
  1. //1.php   4 p2 c7 E  k) q2 S/ N+ ], P2 T: v5 S( u
  2. class Person{* D" _" a8 H0 q* `! a- H
  3.     function __construct(){4 x7 p% Q& Z6 P" J2 w3 c) U
  4.             echo 'I am one!';
    7 |; u% b2 e- i) `  `
  5.         }# d- e1 h: E3 @0 ]( W8 d4 i: k
  6. }
复制代码
  1. //name.php
    1 J! ]0 ?+ c1 w6 }, }4 M
  2. require_once './1.php';
    % h' t' {) g6 _5 u5 ~* s

  3. 2 h# v5 e+ J8 z0 Z2 W" f( h3 _3 N
  4. new Person();     //输出 I am one!;- j& I7 k( }5 s( w, f0 c
  5. new \Person(); //输出 I am one!;
复制代码

9 U) \  X3 h* l4 L7 W3. new类时,带上命名空间时,之间一定用反斜杠字符,而不是顺斜杠。
记忆方法:按找%中斜杠的顺序理解为顺斜杠。(有时说反斜杠,自己都不知道是哪种方向,以前按自左向右上升方向这种方向记忆,现在感觉这个太不靠谱了)
  1. //name.php4 c3 t5 C9 E  |& Z6 z/ v9 F
  2. require_once './1.php';
    0 z& T: x9 j, `. N5 ~. _9 C& F& S
  3. new /Person();  // 代码报错:Parse error: syntax error, unexpected '/'
复制代码
! u0 w" W, M& \: b
4.类在指定命名空间下, new类时,一定要带上指定的命名空间。
没有带上指定的命名空间,按照第2点,php就会从顶级命名空间里找这个类。切记:这里不能按照顶级命名空间包含一切其它的命名空间来理解。而应该将顶级命名空间完完全全与其他命名空间区分开。
  1. //1.php   2 m6 [* h- h# s
  2. namespace one;
    9 N8 I6 ], u* N, e! A; ?
  3. class Person{; u6 }# c$ i" w' O
  4.     function __construct(){
    3 f# H% R; p1 D! V; U( G
  5.             echo 'I am one!';
    : m: H" j  k7 c$ N; }
  6.         }
    & D! i2 R+ q: c
  7. }
复制代码
  1. //name.php9 W3 e! K0 {8 H; a4 Y9 x& E+ _
  2. require_once './1.php';( h& I& u! V0 W& f8 z( J7 F/ l
  3. new \one\Person(); //输出 I am one!;
    ) w1 G5 k6 c9 k9 u4 k
  4. new \Person(); //代码报错:Fatal error: Class 'Person' not found
复制代码

0 z/ T7 \: e' X4 s) @! j* e
可以举个这个通俗例子来理解:带上指定命名空间代表某人的苹果(在他手里),顶级命名空间代表苹果箱里的苹果(在箱子里)。现在要找某人的苹果,就将某人的命名空间带上,否则就会从箱子里找某人的苹果,结果当然是找不到。
. |/ e* {/ K( u& Z/ k4 t
5.命名空间声明后的代码便属于这个命名空间,即使有include或require也不影响(重点是对后半句的理解,具体看代码)。
8 {3 Y0 u; j8 r5 b# t3 z
  1. //1.php   
    1 {( I8 a" o6 N! a, B
  2. namespace one;# ]; `& a7 [7 R7 H, i! [. ]  \
  3. class Person{
    * g; |7 g; m* {
  4.     function __construct(){9 m0 C; N& e- h8 t) ^
  5.             echo 'I am one!';; u& f+ g' z# ]6 b+ `
  6.         }. |0 e' V" H' M" ?; A5 Y
  7. }
复制代码
  1. //name.php' r! S0 d8 q) l& y
  2. namespace test;
    8 O- s& D, y7 _- \. @
  3. require './1.php'; 3 v6 }7 X5 F2 f3 M4 u  q% ~
  4. new \one\Person(); //输出 I am one!;% t& q- ^3 q( U( D5 U7 H& J: \4 N
  5. new Person();      //这里结果会是什么呢,猜猜看6 y% X9 Y+ }: U
  6. 最后一行结果报错:
    ' A. ]: C5 H1 Q$ u2 D- k
  7. Fatal error:  Class 'test\Person' not found
复制代码
0 G- i# S, Y& Y6 T
1 n  b: a0 c6 X! ?8 J$ Q5 X
首先,这里与第2点比较一下:
第2点,我说,没有命名空间时,new类时,有没有反斜杠意义一样。
在这里,有了命名空间,有和没有反斜杠的意义就不一样了。
最后一行换成
  1. new \Person();
复制代码

7 }  K/ f9 W  ^/ C: R
结果报错:
  1. Fatal error:  Class 'Person' not found
复制代码
- h8 @" v/ O" F. \! [7 J: u2 y
接着,就说说当前这点。
我们可以发现,最后一行代码对应的命名空间为test,并没有受到require文件里的命名空间的影响。
进一步加强验证,我修改了name.php文件如下:
  1. //name.php9 U8 r: g0 Y, U) h- ^3 q/ m; `
  2. namespace test;) B( ^, T3 I9 m
  3. require './1.php';
    ' w) \( r/ S: J4 D- ?6 p
  4. - V; u5 w; l& h- F; Q6 {5 ]
  5. class Person{
    , O0 K6 o4 J' M6 u6 @- ~( H# u
  6.     function __construct(){
    8 {$ @+ `7 L" L" U# ]
  7.             echo 'I am test!';8 A& C( G) H. c8 A; L+ W5 g
  8.         }
    8 {5 C* M7 X2 j7 S* n6 c% G
  9. }
    ; _+ }: ~% f# ]

  10. / H* B5 N, i9 i- l' B4 L3 Y' k
  11. new \one\Person(); //输出 I am one!;
    4 b$ d1 X  E1 t/ O+ H' W
  12. new Person();    //这里结果会是什么,自己猜猜看
复制代码
/ H; k% L- W$ o: I
最后,这个例子刷新了我对require的认识了。
按照我以前对require的理解:PHP 程序在执行前,就会先读入 require 所指定引入的文件,使它变成 PHP 程序网页的一部分。所以我常常就简单的理解为替换,只不过把抽离出来的代码再放回原处而已。然后我试了将1.php文件内容放到name.php里:
  1. //name.php6 k2 L8 W5 F: C0 |+ s. r! l. ?" h
  2. namespace test;
    8 b* T7 ?" i# Y  e: v% [- @, Q
  3. namespace one;
    3 N* d3 y* o1 G. Y: p8 ]1 [( h
  4. class Person{5 l% {0 G4 R4 W; y9 E" I( Z
  5.     function __construct(){
    # x3 _: ~5 l$ g1 [0 q6 N$ u8 X
  6.             echo 'I am one!';1 q9 K% [4 u; ^# O- m" _
  7.         }
    ( u  R5 Y2 r7 d; e' W9 j% l. j
  8. }+ z! o2 a' h; E/ W
  9. + \, G) `# |( J3 e5 p. A
  10. class Person{5 m0 d& [9 K+ v$ Y
  11.     function __construct(){
    3 @: j- }* P7 O3 y/ c. H9 _" p, `
  12.             echo 'I am test!';- ~& m8 P" I! g/ Q6 d7 I
  13.         }
    6 S  V4 F. L0 \7 i( p2 N! L; f6 V$ p
  14. }
复制代码
( O. D# D# O( M' X+ V* d/ D
无需new类,该文件就会报错:
  1. Fatal error:  Cannot redeclare class one\Person
复制代码

9 d8 f/ ?5 `3 B5 U3 V7 j. w0 Z
看来简单的把require理解为替换,在这里行不通。

9 c3 K( b& [8 }9 T: {# Q+ O6.namespace里不包含类名称,即使存在与类名称同名的部分,那也不代表类。new类时,还是得将这部分带上。& v) s+ e: x8 `, S
  1. //name.php- k4 `6 C9 i* `9 c7 a
  2. & o2 T& h/ G% N
  3. namespace test\person;  w+ m; G8 o/ A& M9 h9 P$ ~

  4. " S7 t" s" d  Z; q& {
  5. class Person{4 [- k4 c: O& z- d
  6.     function __construct(){
    2 o4 O$ F+ p1 B5 s2 g
  7.             echo 'I am test!';8 [1 C2 v+ ~4 l) E2 b3 R; X* e
  8.         }
    7 ^# ~1 _; b$ Q, K
  9. }
    # ]; A, v  x7 T6 r
  10. new \test\person\Person();  //命名空间里person无法代表类名
复制代码

, {! p" Z" c/ c$ Q
不过这样纯粹是画蛇添足,直接干脆点,namespace里不要带类名称就好。
- L2 }, q% f+ A/ h; X) c/ e
7.一个php文件中可以存在多个命名空间,第一个命名空间前不能有任何代码。
只说第一个命名空间前不能有任何代码,之后的命名空间之前可以有代码。这个自行测试即可。
  1. //name.php8 Z, A+ q# z% f7 q

  2. 8 l( F0 P% D) u3 U6 W: u
  3. namespace test;
    6 m: g& i4 X( X) U3 h( F! p' a
  4. echo 'zhai14';
    - F. V( u: F8 W9 ?
  5. namespace zhai;
      o- P) @' s6 m! z
  6. require './1.php';
复制代码
9 o2 b2 G! Y+ D$ y, {' Y) b
php命名空间namespace告一段落了,接下来说说use的用途。
使用use的目的:
在命名空间字符串过长时,使用use可以相应的缩短命名空间。

- O$ D" f  Z# W3 o7 ^8 ~use的使用方法:1.new类时,最前面无需用反斜杠。此外,use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。7 w( ]% v5 Z4 h; o% M( L2 |% h
  1. //name.php
    5 T. g& f1 d; u! y3 l% a5 ?

  2. " l$ I/ p% f1 a; Q; }
  3. namespace animal\dog;
    6 L& I; s6 X& C* n' K3 u2 D' V' P7 E
  4. 4 R0 L7 Z) _: X6 _2 |% n* \% a, {3 |
  5. class Life{
    : f0 G6 S$ D( n% ?8 l% B: E+ N/ r
  6.     function __construct(){8 w' }& G8 x$ }
  7.             echo 'dog life!';9 [: }0 v  H1 b: _
  8.         }1 J. B4 D+ H! k$ X0 @7 P
  9. }
    ) U) E# Y% J  {" o& W

  10. 2 O/ D7 B  m. m( u% T' J
  11. namespace animal\cat;
    6 Q6 ^4 s, X3 G/ u" r* @

  12. . \: G3 E2 ^" k+ A, E3 e
  13. class Life{# }9 r: Y( Z6 R1 W: \0 v# t( r
  14.     function __construct(){7 M8 \; p5 d/ b& E
  15.             echo 'cat life!';9 x  \! H/ h$ p3 [
  16.         }. o" v8 n  s+ F5 R  A$ g
  17. }
    $ ]4 M5 u- s4 _
  18. * a. Z+ `9 \8 o
  19. new Life();  //按照代码执行顺序,这里默认animal\cat这个命名空间$ {; V: C4 j3 c- U& D
  20. new \animal\dog\Life();  //A
      z+ c! [5 p9 R+ E' M* H

  21. % e! \5 y% V( g/ O: a2 T- ?
  22. use animal\dog;  //a' J* _( B  a7 O9 {) H. p+ b8 y& m
  23. new dog\Life();  //B
    9 l0 \% A* j/ Y9 d* ~, @1 t

  24. * O  {2 u2 t# y2 I- }7 Q# X6 |0 ^6 H  ]
  25. use animal\dog as d;  //b
    ' Z" E. {9 U) D9 k# j  W# B
  26. new d\Life();
复制代码

# z* {) B$ t) d5 F" [/ E1 [
通过A、B行代码比较,需要注意:
使用use后,new类时,最前面没有反斜杠。
没使用use时,命名空间最前面有反斜杠

9 K; [7 [- d$ \( {0 R, s
通过a、b行代码比较,可以理解:
use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。如上的:
  1. use animal\dog;
复制代码
  ^$ y" q1 W* U5 i
相当于
  1. use animal\dog as dog;
复制代码

9 V. X( m  a# h' r2.namespace后面不建议加类名,但use后可以。% r. z# W' e6 W& L9 d  g
  1. //name.php
    ' z% M4 ?2 H* h5 V) j3 E4 L( n
  2. / [9 C1 C/ A. K, _, i/ R
  3. namespace animal\dog;
    . r  ]- g; f9 k' G: J

  4. ' b; s% z8 r; Z5 n  G4 R
  5. class Life{
    / G: W. B6 r% r' U' B, k- q4 q
  6.     function __construct(){3 d0 }- l; X8 {# `$ U2 x+ {+ }
  7.             echo 'dog life!';
    ) x) E# y8 I! o6 e% f  h
  8.         }& l3 p7 D1 L, D
  9. }
    % M0 Z  A8 i: K9 ~3 {
  10. # z/ Z6 R; s% W  G" A
  11. namespace animal\cat;; x9 `. Q2 s0 u* w, Z; f
  12. . x0 b# J3 H0 \) f
  13. class Life{7 m4 K8 ~# A& a& |0 ?1 ^0 v  i/ z
  14.     function __construct(){( l7 t( ?& b1 D. `# I* _
  15.             echo 'cat life!';
    3 ~# R5 `; Z8 m" Z; l6 k2 b
  16.         }! r  C: f$ E3 i
  17. }/ p/ O" x! J9 [2 y6 s- E6 x* p8 F

  18. 3 t/ J9 _" u2 l9 ?/ r
  19. use animal\dog\Life as dog;  9 d1 J* l& ^; k2 K7 T. ?
  20. new dog();
复制代码

1 l  q( o/ ~/ D* u9 F
如上所示,use后加上类名后,就相当于把类改了个名称:由Life改为dog了。
上面不用as dog就会报错:
  1. Fatal error:  Cannot use animal\dog\Life as Life because the name is already in use
复制代码

- n7 a  i% ]3 V" z. I" C- j
因为cat下也有个一样名称的Life类。
可以理解为,使用use后,这个昵称对应的类只能归当前命名空间占有,其它命名空间下不允许存在该类。
  1. //name.php# V* N2 N: Q' U( }( @
  2. & t8 {, _, k3 x- [/ N' `6 N. r% ^
  3. namespace animal\dog;
    + C: }4 b1 g0 \& x5 L+ y; m* `- W
  4. - d; ~! F6 x7 E) U5 q" e
  5. class Life{( k+ {* q2 M1 a6 k" b
  6.     function __construct(){
    3 p' `/ p5 f, ~6 ]. z' N
  7.             echo 'dog life!';: g( X" M4 _5 R/ [9 A
  8.         }
    ' t( l: P8 M6 ~7 P$ h
  9. }  S7 q1 J3 V& @. P! u/ q' p
  10. class Dog{9 O9 H1 `- a" R! M( A# e( B$ o3 e
  11.     function __construct(){0 c/ x# K: n% ^0 o
  12.             echo 'dog in dog!';
    7 |' S6 [4 E0 Y1 p. V/ X4 G2 R
  13.         }# V& e  y: u0 R1 r7 |* [
  14. }
    + v$ o7 N, E' h5 W

  15. - M1 Y$ e$ `! Y1 o7 a8 i
  16. namespace animal\cat;
    - s* q: C1 {& j2 U/ K

  17. / R( P) H# m4 B3 C2 _. w
  18. // class Dog{1 n' ]% A. O3 M/ B$ N7 W) J% @$ s
  19. //     function __construct(){( A( I8 o% U, ?9 Q* E, G
  20. //             echo 'dog in cat!';2 _3 N& E" x) D7 J/ _' x2 |
  21. //         }
    / C# z3 `1 E# x) d2 ]/ T: K
  22. // }
    ) F" m2 E. ^+ X) [( u, P# a
  23. class Life{
    * D7 N# F6 f- r( \; _
  24.     function __construct(){
    ' }* j3 K4 Z# F3 c0 E6 ], d
  25.             echo 'cat life!';5 U8 W  A$ c  C7 H  t7 _
  26.         }: K! ]/ z' k6 R
  27. }
    0 l0 j- C1 I6 ?! L$ F

  28. % E6 A6 S% M+ C& C% Q
  29. use animal\dog;  ! i6 @! j6 I" H2 J( x5 |
  30. new dog\Dog();
复制代码

  I; t9 i2 z9 X$ c3 A! Q1 i" Q+ i  T. z
如上,使用了
  1. use animal\dog;
复制代码
# F- y. Q' f2 x" m, d2 o
cat
通过上面代码,我想使用use的目的效果(缩短命名空间名称)就很明显了。
# g3 I, ~2 ^( t. m' d
简单总结一下:
namespace就是划分领域的作用,代表这些东西是属于某个命名空间下的。
use就是起小名的作用,不论写起来还是说起来都可以省不少事儿。
5 x  |6 ?+ M. X% i+ O  m' L

/ T. B2 n( g2 b7 Q8 h6 N% z* s* ~5 @; \: b4 q" k
" f& I0 P5 u4 \" L2 D: ~/ d
0 t& t. O, n9 {0 ?" w( A3 Q- V" C
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-8-4 10:51 , Processed in 0.067185 second(s), 20 queries .

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