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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 8669|回复: 0

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

[复制链接]
发表于 2020-7-1 23:37:46 | 显示全部楼层 |阅读模式
以下皆为本人自我理解内容,如有失误之处,请多多包涵。

* P) t; L5 {7 J  D* }+ S2 G. l5 O
文章大纲:
使用namespace的目的
namespace的使用方法
使用use的目的
use的使用方法

5 D  r: V8 H0 B. `; |( }4 X4 C2 p0 T3 s! s
使用namespace的目的:
团队合作项目时,避免与团队其它成员新建的类发生冲突;个人负责项目时,避免前后新建的类发生冲突;
6 y2 N% f6 n2 S. ~% f2 {
据个人理解,用到所需要的类时,需要先require或include引入,所以会发生类重定义的错误的前提是:两个相同命名的类都有被引入。目前有些php框架会自动加载(即include)所有新建的model类,所以为了避免你新建的model类和项目框架原生的核心类发生重名冲突,采用了namespace。(想了想,与团队成员新建的类产生冲突应该通过沟通避免,即使事发后也应该重新调整类名即时维护,避免后期造成因为对类的理解混淆而带来维护上的复杂度提高)

3 ^. x  ^& L( q0 W# M结合使用方法来进一步理解它的使用目的吧。
! j* }$ O# r' c* b3 Z3 g% q$ {. g

( q5 G) F. p+ n0 v3 p" x: Bnamespace的使用方法:
为了进行测试,我将创建3个文件:1.php和name.php(此文件用来执行测试),后面将不再说明,请自行注意代码的变化。
1.namespace后命名的定义不区分大小写
  1. namespace one;
      p. q0 ?% l0 g  \. ^2 W
  2. namespace One;
      X$ X- r2 X) M# m. ^3 t3 d1 x1 v
  3. namespace ONE;
复制代码

% `$ t# t9 ^6 O; \1 I
如上写法都可以,选择一种作为自己的规范即可。(后面代码我采用第一种进行测试哈)

7 Y* D( h2 T, z2. 没有定义命名空间,就理解为使用顶级命名空间。new类时,可以在类前加上反斜杠\,也可以不加。
  1. //1.php   2 G/ v% C/ V8 q1 x# T7 J- u
  2. class Person{
    ! N5 _: s' g3 U& T2 O" W
  3.     function __construct(){
    3 S" \9 j8 u, P' q
  4.             echo 'I am one!';
    / T, L. d; j7 f( M+ @* R6 Q
  5.         }
    # R/ O% Q6 \4 X
  6. }
复制代码
  1. //name.php
    1 K1 `# _& o3 m" X' l
  2. require_once './1.php';
    0 V& J0 e6 w& _
  3. 1 {( \$ E3 g5 W& N2 z
  4. new Person();     //输出 I am one!;1 \8 }8 U* I* f# ?* \; D1 j% e0 a0 \
  5. new \Person(); //输出 I am one!;
复制代码

; k8 n1 j4 T: s; E: Q3. new类时,带上命名空间时,之间一定用反斜杠字符,而不是顺斜杠。
记忆方法:按找%中斜杠的顺序理解为顺斜杠。(有时说反斜杠,自己都不知道是哪种方向,以前按自左向右上升方向这种方向记忆,现在感觉这个太不靠谱了)
  1. //name.php
    & ?0 ~9 E( C! V& b8 R  ^
  2. require_once './1.php';
    2 K, e9 U- m' E
  3. new /Person();  // 代码报错:Parse error: syntax error, unexpected '/'
复制代码
# Z, `2 `4 |" X" g% `5 B0 h
4.类在指定命名空间下, new类时,一定要带上指定的命名空间。
没有带上指定的命名空间,按照第2点,php就会从顶级命名空间里找这个类。切记:这里不能按照顶级命名空间包含一切其它的命名空间来理解。而应该将顶级命名空间完完全全与其他命名空间区分开。
  1. //1.php   ( P* i4 I9 r" Z9 j
  2. namespace one;
    3 R# F* N) J( k/ i  C5 L- a" m
  3. class Person{1 }! a$ {9 |0 d/ x+ H* q8 s) x1 j; r
  4.     function __construct(){
    / w' ]# |4 A0 |! G
  5.             echo 'I am one!';1 C: y, V5 s; n
  6.         }% n4 K* ?5 Q6 I
  7. }
复制代码
  1. //name.php0 y1 e+ q+ i2 N4 N2 t* ]
  2. require_once './1.php';
    , Z" M. }1 Q% u+ k
  3. new \one\Person(); //输出 I am one!;
    2 [; \, E, a2 Y+ ]; G
  4. new \Person(); //代码报错:Fatal error: Class 'Person' not found
复制代码
' e% B1 ]: O2 p6 g
可以举个这个通俗例子来理解:带上指定命名空间代表某人的苹果(在他手里),顶级命名空间代表苹果箱里的苹果(在箱子里)。现在要找某人的苹果,就将某人的命名空间带上,否则就会从箱子里找某人的苹果,结果当然是找不到。

: D5 {; o$ q/ ?$ n8 F5.命名空间声明后的代码便属于这个命名空间,即使有include或require也不影响(重点是对后半句的理解,具体看代码)。1 U, z* k, y0 V; K
  1. //1.php   ! p' q6 n" B1 U! I" l
  2. namespace one;1 n! ]5 e, Z. g7 A  v1 B
  3. class Person{! o5 f9 G$ g; l9 f
  4.     function __construct(){
      n- j, P2 W8 i8 ~% C: i8 J
  5.             echo 'I am one!';. B0 d: Z, F4 @# Z; i
  6.         }
      l- C% N6 @; s( k0 b' ~, X
  7. }
复制代码
  1. //name.php
    % ~; o7 T' k" p* s  n/ W
  2. namespace test;7 M. c9 }6 O* x: ^$ }
  3. require './1.php'; 2 Z% a3 n# k  @' V, f
  4. new \one\Person(); //输出 I am one!;
    ' s8 I- v; O4 O7 v# y
  5. new Person();      //这里结果会是什么呢,猜猜看
    & l3 J# o+ T; q4 ^; U4 [8 O# f
  6. 最后一行结果报错:$ X5 Q- r. {2 |) X
  7. Fatal error:  Class 'test\Person' not found
复制代码
0 Y9 v2 B! V! H# j1 ~
" W1 w" D/ L, E* `
首先,这里与第2点比较一下:
第2点,我说,没有命名空间时,new类时,有没有反斜杠意义一样。
在这里,有了命名空间,有和没有反斜杠的意义就不一样了。
最后一行换成
  1. new \Person();
复制代码
8 S9 W$ L8 ?5 S/ T
结果报错:
  1. Fatal error:  Class 'Person' not found
复制代码
* g' z0 b) ^5 w* |. F4 Y
接着,就说说当前这点。
我们可以发现,最后一行代码对应的命名空间为test,并没有受到require文件里的命名空间的影响。
进一步加强验证,我修改了name.php文件如下:
  1. //name.php
    + _7 R& O2 P5 y
  2. namespace test;
    ) \6 g3 _% P4 ^6 Z  v6 W& P
  3. require './1.php';
    / u8 a% ]6 P$ Q7 \, T2 K
  4. % P( k# H$ U$ z, |- B6 u0 }3 \
  5. class Person{
    ( s# o# M$ E- L$ o& @
  6.     function __construct(){
    0 G! B$ P3 O# w$ f' `. F/ g
  7.             echo 'I am test!';
    1 b6 i7 I, C6 \% @4 A% d" H  {/ Q
  8.         }! d' j; y4 }; o/ F. D
  9. }! k3 n2 E# a& T! N+ x/ N
  10. ( _* A2 e  j# u- J* m: c( h
  11. new \one\Person(); //输出 I am one!;/ T0 j$ Y4 P3 f6 U( G
  12. new Person();    //这里结果会是什么,自己猜猜看
复制代码

' Z7 s0 _$ c1 ~% ]( a, S: m$ q8 O
最后,这个例子刷新了我对require的认识了。
按照我以前对require的理解:PHP 程序在执行前,就会先读入 require 所指定引入的文件,使它变成 PHP 程序网页的一部分。所以我常常就简单的理解为替换,只不过把抽离出来的代码再放回原处而已。然后我试了将1.php文件内容放到name.php里:
  1. //name.php
    3 z  n8 G( Y2 ^3 m3 b6 w& K
  2. namespace test;
    1 y# _8 `% j- ]1 ]2 M% k
  3. namespace one;
    / Y0 T9 ~3 j$ s2 R2 |
  4. class Person{
    0 N8 L: l, Q. J6 {4 |# s  a+ A
  5.     function __construct(){
    % O: s; W! v5 `7 p
  6.             echo 'I am one!';
    8 Y. C+ ]+ M' G- M+ C# g' X
  7.         }* \" k; d; e2 z( u( E' V
  8. }
    + H$ }5 b2 d0 L  a. \) V

  9. ) j% L, L  p! C& p
  10. class Person{
    / d, F9 [* z$ ~7 [& v
  11.     function __construct(){& S# q  N8 N0 Q- V% b- R
  12.             echo 'I am test!';2 M* t. V  L1 H
  13.         }' n* [' ^. n' q
  14. }
复制代码
1 B7 Q2 x( B% I
无需new类,该文件就会报错:
  1. Fatal error:  Cannot redeclare class one\Person
复制代码

% F( z! Z% w, s2 B% M1 f4 C
看来简单的把require理解为替换,在这里行不通。

1 R: a$ F: A% ^8 r9 J' h6.namespace里不包含类名称,即使存在与类名称同名的部分,那也不代表类。new类时,还是得将这部分带上。
" p( n; d( ?+ b8 ?. q
  1. //name.php8 |* j0 e0 H& o  f) q0 @6 C

  2. ) L7 G' v+ S0 H+ o1 C3 G& _9 l% A
  3. namespace test\person;9 S" q5 m% p! [6 ?
  4. / e9 f7 Q% u3 ^. \$ {
  5. class Person{7 s! \. m7 j+ H* \8 l' L: d+ f
  6.     function __construct(){# Z. V: K. [: f1 U1 j2 I: ]
  7.             echo 'I am test!';3 q7 ~" q) i7 k+ K# g. }6 n
  8.         }
    ; H* Z6 o9 J5 J2 V
  9. }1 v: F; G9 A- x
  10. new \test\person\Person();  //命名空间里person无法代表类名
复制代码

# ~2 N# S% Y" z. \
不过这样纯粹是画蛇添足,直接干脆点,namespace里不要带类名称就好。

% N% m$ q5 {1 t0 F6 _% {7.一个php文件中可以存在多个命名空间,第一个命名空间前不能有任何代码。
只说第一个命名空间前不能有任何代码,之后的命名空间之前可以有代码。这个自行测试即可。
  1. //name.php  F5 F* @- u3 Q

  2. ' t; C9 p7 s0 H* i0 q+ }" m. [) ^
  3. namespace test;  F8 R# f3 Z" P& K
  4. echo 'zhai14';
    / |! H6 i; f7 y
  5. namespace zhai;
    7 }: y, l. ^) u: |
  6. require './1.php';
复制代码
0 d& r- R4 N0 ^7 u4 l0 z
php命名空间namespace告一段落了,接下来说说use的用途。
使用use的目的:
在命名空间字符串过长时,使用use可以相应的缩短命名空间。
( R4 t) Y$ i* X# |$ H
use的使用方法:1.new类时,最前面无需用反斜杠。此外,use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。/ G: o, t2 Q5 f, H
  1. //name.php
    * b1 U$ V! I& u- |, e6 _
  2. & h0 m0 s9 x1 j2 M1 [" x
  3. namespace animal\dog;9 k/ {. Z4 r0 N2 E

  4. 2 y$ l0 N" `$ j
  5. class Life{
    0 r! d) p2 S% |7 q/ F& c9 d
  6.     function __construct(){3 M+ t$ l( P+ L7 ^( E6 J  s" U
  7.             echo 'dog life!';( W/ Q, ~! x( u+ n( f; U5 i; S
  8.         }# Q9 H; P  g  a0 ~
  9. }
    4 h# A9 V! k  B! w
  10. ' [. c. r6 S- u6 I5 W, Q' M
  11. namespace animal\cat;: K! w! z; T4 c3 Q7 J' F; t
  12. ! S) K" w9 |$ [# a( L
  13. class Life{
    ! {1 S: [: j3 x' p' V; K% I- T
  14.     function __construct(){
    % ^# n. g$ _- H! p* w$ @
  15.             echo 'cat life!';& ^) g/ T( B" j* L2 S6 P2 |* ]
  16.         }& t! w3 N  T1 S- Y+ O
  17. }9 o# O1 J8 t- `+ Y; b3 R0 W; @4 Z
  18. / n- X! t0 D  y5 w) s+ [8 B$ Y  I$ |
  19. new Life();  //按照代码执行顺序,这里默认animal\cat这个命名空间
    $ E+ n: M6 D% h  P
  20. new \animal\dog\Life();  //A( o0 B* [! H* I# R) ]* p4 m  y4 l

  21. 7 V0 h, ]% J* g5 Z: _" ]' b: B
  22. use animal\dog;  //a
    - F+ t# p) {! u3 B; Y
  23. new dog\Life();  //B5 F* P( m  B( j- n
  24. 3 d2 ]& R# \4 u
  25. use animal\dog as d;  //b5 _0 v- Q7 O- v
  26. new d\Life();
复制代码

( T' N4 F; R: H* D. c
通过A、B行代码比较,需要注意:
使用use后,new类时,最前面没有反斜杠。
没使用use时,命名空间最前面有反斜杠

; t$ {# r' T- V; f9 _
通过a、b行代码比较,可以理解:
use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。如上的:
  1. use animal\dog;
复制代码
0 G7 \, R- ^0 G# R
相当于
  1. use animal\dog as dog;
复制代码

# k& v0 m. T2 l3 V. g2.namespace后面不建议加类名,但use后可以。
% L5 j* f' K2 ^  ^$ D# g+ \
  1. //name.php; n, V, C+ E# i1 b8 K

  2. ! i$ j- \( [# C$ @- P2 k$ n1 S
  3. namespace animal\dog;
    ! \" c, D+ m( C" f) Y. m
  4. 6 f; t) Q. y( n8 x- P8 b
  5. class Life{& F2 R( U0 M- ^7 C9 }0 t
  6.     function __construct(){
    . |9 z3 D: v4 G9 r8 {: r5 ^. b* y
  7.             echo 'dog life!';
    9 @& j. j* ?# R) o' `! q
  8.         }
    + S; i# t, l* }/ H) d
  9. }
    : a' m; _1 d" e1 t2 y2 F
  10. & {4 o6 O0 z+ b* L; V: V2 y
  11. namespace animal\cat;
    3 M1 c2 U; a5 s* E$ X0 S# `

  12. + G, e, i- Q' o" C+ K8 R
  13. class Life{4 H# s0 ~7 k1 _6 E+ N( f/ o
  14.     function __construct(){
    3 O, ^& E$ N$ ~5 ?  B3 U
  15.             echo 'cat life!';
    ) V# J5 q6 H& r
  16.         }
    , H. m( G% @; A' t
  17. }9 g( y% |# U/ P6 ^
  18. $ d' Z) d3 F- u/ [
  19. use animal\dog\Life as dog;  " H7 p7 |( }& C: v) [, g  ^
  20. new dog();
复制代码

# A* ^. P9 R" h, F- }- X+ G
如上所示,use后加上类名后,就相当于把类改了个名称:由Life改为dog了。
上面不用as dog就会报错:
  1. Fatal error:  Cannot use animal\dog\Life as Life because the name is already in use
复制代码
' g% w, `$ V2 s( k  H. x- [
因为cat下也有个一样名称的Life类。
可以理解为,使用use后,这个昵称对应的类只能归当前命名空间占有,其它命名空间下不允许存在该类。
  1. //name.php
    + W( F! p( G" q  [& b
  2. : e: h( h1 ^% {; R( @8 W6 ?& ?. l
  3. namespace animal\dog;7 c+ Y' l: K; d% h

  4. 1 N4 F- \0 o7 l8 Z
  5. class Life{
    # r- \" O3 y; {. Q
  6.     function __construct(){
    0 H+ n6 t) B& n, Z6 Y4 [
  7.             echo 'dog life!';' j# |2 m# R% }* L* Y2 R# z. r
  8.         }
    , G" C4 x1 M6 o- U- }9 g# l" W! T5 M8 i
  9. }
    * I) {2 V3 D" z+ @! y$ _' h
  10. class Dog{! z; Y( f$ S1 G6 \0 ?* B$ G
  11.     function __construct(){+ P# H# `* D/ y$ [; {
  12.             echo 'dog in dog!';
    ) Q& W% N: p4 g0 W# r2 m) D
  13.         }6 @: w9 H/ ^" Z1 \
  14. }
    ( [- s6 @- }! {; G4 ]  h& U& B

  15. 3 R1 g3 @$ L3 m* T& C
  16. namespace animal\cat;8 a# y# p. C- }3 }" s9 @

  17. ! P7 R6 [, m4 y8 [# q$ l( i" D
  18. // class Dog{
    # e4 f4 Z; S7 G" x( L  N/ Y
  19. //     function __construct(){
    / V: \, `/ ~. X% q
  20. //             echo 'dog in cat!';: X, T" K& }+ T1 f
  21. //         }
    ! |+ T* l) M, P7 R0 m% y6 d( _
  22. // }
    ( b6 r( k) e3 \6 M3 r0 q) j
  23. class Life{
    ( c# R8 F. t# c* r4 v% Y( Y- I
  24.     function __construct(){( |+ A+ w! f- d, c  T, i8 R) o
  25.             echo 'cat life!';3 m3 j, ~1 X4 G( i
  26.         }/ Q0 S: [7 h. i+ J; F# p
  27. }
    # k2 L1 V! t5 ?1 c

  28. 8 t) i4 Z( l& D
  29. use animal\dog;  
    5 Z9 Y5 h0 q2 p/ {* \
  30. new dog\Dog();
复制代码
" V8 {5 m9 j% z, k4 a
如上,使用了
  1. use animal\dog;
复制代码
$ C% V6 K" c8 C0 m
cat
通过上面代码,我想使用use的目的效果(缩短命名空间名称)就很明显了。

: b! ^7 y$ Q: f* @8 F5 ?# O( |" B4 t
简单总结一下:
namespace就是划分领域的作用,代表这些东西是属于某个命名空间下的。
use就是起小名的作用,不论写起来还是说起来都可以省不少事儿。
5 e# f; G9 J2 y4 ^: Y* `8 F

7 F1 d# Q) O1 c1 _8 v# |* {$ K$ Q! u2 c6 c  }2 ]0 ]
5 Q9 o# ^+ n% Y$ P

( }2 i% ^( t# g- z
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-4-19 02:13 , Processed in 0.153229 second(s), 22 queries .

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