cncml手绘网

标题: PHP命令空间namespace及use的用法实践总结 [打印本页]

作者: admin    时间: 2020-7-1 23:37
标题: PHP命令空间namespace及use的用法实践总结
以下皆为本人自我理解内容,如有失误之处,请多多包涵。
0 y9 ^2 Q* Z! z, Q' z; r
文章大纲:
使用namespace的目的
namespace的使用方法
使用use的目的
use的使用方法

& o4 e! O3 A3 _9 v  Z( A) c" b6 f& r  ^* C9 P7 H$ v! s( q* b
使用namespace的目的:
团队合作项目时,避免与团队其它成员新建的类发生冲突;个人负责项目时,避免前后新建的类发生冲突;
/ z6 N+ n; H" o* E
据个人理解,用到所需要的类时,需要先require或include引入,所以会发生类重定义的错误的前提是:两个相同命名的类都有被引入。目前有些php框架会自动加载(即include)所有新建的model类,所以为了避免你新建的model类和项目框架原生的核心类发生重名冲突,采用了namespace。(想了想,与团队成员新建的类产生冲突应该通过沟通避免,即使事发后也应该重新调整类名即时维护,避免后期造成因为对类的理解混淆而带来维护上的复杂度提高)

: W: R+ }/ c8 C- X( z. G* p结合使用方法来进一步理解它的使用目的吧。

/ u; ]( j8 M1 j- k% B
9 O$ c8 a: _; lnamespace的使用方法:
为了进行测试,我将创建3个文件:1.php和name.php(此文件用来执行测试),后面将不再说明,请自行注意代码的变化。
1.namespace后命名的定义不区分大小写
  1. namespace one;
    7 J& L' d, N" g; O
  2. namespace One;( ~5 {( @& d; r+ A7 r+ j
  3. namespace ONE;
复制代码

' H+ M7 U9 Q! Z- k
如上写法都可以,选择一种作为自己的规范即可。(后面代码我采用第一种进行测试哈)

) d+ i+ g; L) J! r) V2. 没有定义命名空间,就理解为使用顶级命名空间。new类时,可以在类前加上反斜杠\,也可以不加。
  1. //1.php   1 c3 U6 H9 q2 r; S4 s5 P
  2. class Person{9 x& @+ {0 J) b. {
  3.     function __construct(){
    3 y/ V4 Y' {0 a8 U0 P! o- S
  4.             echo 'I am one!';
    0 v0 \7 r2 X/ }
  5.         }
    " B# d2 B( z$ d+ ^2 S  H
  6. }
复制代码
  1. //name.php! N' |* B# A8 k% r3 N+ |. ]
  2. require_once './1.php';& s7 n! q# P! I7 v/ q* o7 [
  3. % _# }' u1 Q8 Y& T2 K9 Q
  4. new Person();     //输出 I am one!;, U5 {1 K1 Z9 k; O
  5. new \Person(); //输出 I am one!;
复制代码

; K! ~; Y! j) H' [# N6 K3. new类时,带上命名空间时,之间一定用反斜杠字符,而不是顺斜杠。
记忆方法:按找%中斜杠的顺序理解为顺斜杠。(有时说反斜杠,自己都不知道是哪种方向,以前按自左向右上升方向这种方向记忆,现在感觉这个太不靠谱了)
  1. //name.php
    : n6 i  M5 X. U3 i; u9 e
  2. require_once './1.php';: C0 I) |  c" H$ E1 l
  3. new /Person();  // 代码报错:Parse error: syntax error, unexpected '/'
复制代码

1 V) `3 a- E( b; j9 d% F1 [4.类在指定命名空间下, new类时,一定要带上指定的命名空间。
没有带上指定的命名空间,按照第2点,php就会从顶级命名空间里找这个类。切记:这里不能按照顶级命名空间包含一切其它的命名空间来理解。而应该将顶级命名空间完完全全与其他命名空间区分开。
  1. //1.php   
    " x( T# i1 P( A  j1 V5 L
  2. namespace one;, h: e- e& J' {* {! A$ Q( h1 a
  3. class Person{# F# f1 b: {8 D; T! a; K3 M
  4.     function __construct(){" _" l2 x' M( U. f) X  f
  5.             echo 'I am one!';
    . @4 V& d6 R9 F) @
  6.         }" V: k4 u( A8 b9 x7 T. J
  7. }
复制代码
  1. //name.php
    0 a% s2 F  Q4 S7 B) D
  2. require_once './1.php';
      r: ^" E, m. m
  3. new \one\Person(); //输出 I am one!;
    & M6 E* k6 l5 f6 z
  4. new \Person(); //代码报错:Fatal error: Class 'Person' not found
复制代码

) f+ F4 I% Z$ _
可以举个这个通俗例子来理解:带上指定命名空间代表某人的苹果(在他手里),顶级命名空间代表苹果箱里的苹果(在箱子里)。现在要找某人的苹果,就将某人的命名空间带上,否则就会从箱子里找某人的苹果,结果当然是找不到。

6 N  D, |- c, V0 N5.命名空间声明后的代码便属于这个命名空间,即使有include或require也不影响(重点是对后半句的理解,具体看代码)。+ r) p- z' a0 Q- k
  1. //1.php   
    : ~1 b$ Z8 e( M+ d3 k, \# \
  2. namespace one;
    ' @9 q- J3 h+ _5 c) Z
  3. class Person{
    * M& \4 {* M" k
  4.     function __construct(){1 Q/ P* O" n0 I2 h, s& h1 \
  5.             echo 'I am one!';/ S3 H: S9 c2 l* W
  6.         }9 e( S; v! Q6 I- S" d
  7. }
复制代码
  1. //name.php
      Z" k0 m! n5 x5 \
  2. namespace test;' Q, O- u" V. z- v6 n
  3. require './1.php'; 9 ]6 i6 _' v6 U3 S
  4. new \one\Person(); //输出 I am one!;9 O7 @, M2 A- f" v# ]( z
  5. new Person();      //这里结果会是什么呢,猜猜看. f2 W. P% j# N4 D" {$ a' j
  6. 最后一行结果报错:) U: k2 [  P2 J6 f! B
  7. Fatal error:  Class 'test\Person' not found
复制代码
& I  A: m& W. b: O( ^" @
# i* s3 l/ v% v2 E  K
首先,这里与第2点比较一下:
第2点,我说,没有命名空间时,new类时,有没有反斜杠意义一样。
在这里,有了命名空间,有和没有反斜杠的意义就不一样了。
最后一行换成
  1. new \Person();
复制代码

# T" `8 c5 S4 {
结果报错:
  1. Fatal error:  Class 'Person' not found
复制代码
  U1 R* M. S; ]+ Q) J$ I7 _
接着,就说说当前这点。
我们可以发现,最后一行代码对应的命名空间为test,并没有受到require文件里的命名空间的影响。
进一步加强验证,我修改了name.php文件如下:
  1. //name.php
    - _2 c* ^' B' `# q( d
  2. namespace test;
    6 z, H8 a& n+ @1 }1 t
  3. require './1.php'; 3 X9 T# H! x+ F/ e/ |2 i

  4. 6 c- u, a6 n! v, f/ z$ x0 g
  5. class Person{
    & r& z" ~1 z$ f$ A8 s
  6.     function __construct(){
    + u' J, }5 b$ b# r' P
  7.             echo 'I am test!';
    + e9 W: h- b- ]+ A6 J
  8.         }" W3 R( i9 @# G2 v" C6 [
  9. }- |; f7 b: V; r/ Q0 d" ]5 y

  10. ! Q4 i5 n* a) @3 z* g: M
  11. new \one\Person(); //输出 I am one!;
    ( e' W+ g6 ^6 u3 r8 T# l
  12. new Person();    //这里结果会是什么,自己猜猜看
复制代码
' e1 a9 c' G# r+ ?' B; }6 o
最后,这个例子刷新了我对require的认识了。
按照我以前对require的理解:PHP 程序在执行前,就会先读入 require 所指定引入的文件,使它变成 PHP 程序网页的一部分。所以我常常就简单的理解为替换,只不过把抽离出来的代码再放回原处而已。然后我试了将1.php文件内容放到name.php里:
  1. //name.php
    % P: P7 O; x- k- W% v: K
  2. namespace test;6 R# A9 w8 T( h
  3. namespace one;, d. Y3 \5 {9 K1 R8 C0 d  c0 U
  4. class Person{2 P6 U0 x7 z; A* t1 A
  5.     function __construct(){
    ' T8 g4 S/ Y! o3 s
  6.             echo 'I am one!';
    ( z/ C7 a# A  H  d. |2 T
  7.         }% b! |/ B1 t% c. _7 q5 r
  8. }6 e# x( p, q& T. M7 t
  9. ' ?( ^/ |$ R4 j, L  y6 \3 V/ `, [
  10. class Person{
    # S9 r7 t+ N2 G0 A2 o; E
  11.     function __construct(){$ ]. M* u# j. ]4 C% O' a
  12.             echo 'I am test!';( o8 N: r* v/ m
  13.         }3 I$ G0 e- v( |
  14. }
复制代码
. ?) p/ w; T1 L3 A1 Y! K3 q9 r/ J+ W
无需new类,该文件就会报错:
  1. Fatal error:  Cannot redeclare class one\Person
复制代码
  W/ ]3 w- _: s% Z
看来简单的把require理解为替换,在这里行不通。

7 m5 M; b. X1 [6.namespace里不包含类名称,即使存在与类名称同名的部分,那也不代表类。new类时,还是得将这部分带上。
6 Y/ D0 b' D/ {
  1. //name.php0 Q; z. K: i6 _. R0 ~

  2. 1 }" u' h) U; E& [# s  g
  3. namespace test\person;
    2 e' l/ U' {4 i8 q6 N& O: ?
  4. # I4 @$ J4 \' G# d4 D
  5. class Person{
    7 v  v# x. Y) Z0 N1 S8 }( W
  6.     function __construct(){
    3 t, a. ~& i4 l. }# R% Y" f
  7.             echo 'I am test!';$ c* d! _  d$ t9 E4 m3 |5 b
  8.         }
    8 w9 Z1 ?' Q8 P0 ^5 n
  9. }
    # N0 y+ B( g  w7 a  c( ?
  10. new \test\person\Person();  //命名空间里person无法代表类名
复制代码
: i8 B2 A7 E# b8 j
不过这样纯粹是画蛇添足,直接干脆点,namespace里不要带类名称就好。

; T* }2 v4 E9 }) I; J1 B) e7.一个php文件中可以存在多个命名空间,第一个命名空间前不能有任何代码。
只说第一个命名空间前不能有任何代码,之后的命名空间之前可以有代码。这个自行测试即可。
  1. //name.php
    * C$ d0 I8 |+ k) g5 ?" [! i
  2. 7 z2 V- v( P% K
  3. namespace test;
    . Q: K$ A/ C0 ^* Y
  4. echo 'zhai14';4 a0 y8 V- o7 H$ R0 Q* z) \
  5. namespace zhai;
    & G5 ]7 }. K- Z! p; j0 ]
  6. require './1.php';
复制代码
: t6 @% H) Z' J) ^: T+ i8 a5 {+ v, B/ r
php命名空间namespace告一段落了,接下来说说use的用途。
使用use的目的:
在命名空间字符串过长时,使用use可以相应的缩短命名空间。

5 P6 P8 H5 @) Q7 _0 e2 ?; fuse的使用方法:1.new类时,最前面无需用反斜杠。此外,use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。% C3 y3 {/ i5 p4 M
  1. //name.php
    / }4 F# f5 N% V& W. U# ?
  2. , E! Z# z- D4 ?4 E9 w9 z
  3. namespace animal\dog;2 S$ x) e& G; K9 E- G* {$ r2 ~
  4. ! @3 r  V& O8 J* @
  5. class Life{6 N- y/ Q3 Y( r# ]5 U
  6.     function __construct(){% R: a# P/ p; a& P/ g+ s
  7.             echo 'dog life!';! T" a2 d; e8 k% P: W7 o
  8.         }  c$ B. `/ ~' d6 m7 W) @: a; o
  9. }; _  M4 b/ P' @
  10. 8 T. [; q' T# T% }8 |2 x# z. e
  11. namespace animal\cat;3 J. I( a! Y4 y) b
  12. 1 ^- t) ^- H% e: I3 h( ^- b
  13. class Life{4 A  g  O/ b: ~# C4 b# d7 w6 p
  14.     function __construct(){( H6 [' Q! [+ K* n5 `" U
  15.             echo 'cat life!';+ d  C5 H) X) r: q+ e- T+ W
  16.         }
    ( {5 Q% n9 q' e3 {! h
  17. }
    5 N  j- ^! Q0 e) {9 h
  18. 0 p( a3 x1 X) k( c" q
  19. new Life();  //按照代码执行顺序,这里默认animal\cat这个命名空间1 P, _5 f9 }& m) |* v6 h
  20. new \animal\dog\Life();  //A: R0 h, ]/ C+ j6 l. {8 z: Z2 ^, h) i& L6 ^

  21. 8 p  N/ _  Y2 ^2 i, @( F
  22. use animal\dog;  //a2 ]' b4 L; N2 j( v
  23. new dog\Life();  //B0 d4 ~' ^0 l3 L6 g3 d$ J$ F

  24. 6 Q1 {2 {3 j4 f# I( G
  25. use animal\dog as d;  //b
    * g. w0 O* Z  u
  26. new d\Life();
复制代码
9 D4 b7 ?8 c- J9 ~  s$ n- `3 p
通过A、B行代码比较,需要注意:
使用use后,new类时,最前面没有反斜杠。
没使用use时,命名空间最前面有反斜杠

8 S4 a) X' D  v8 v) r5 j$ r& o
通过a、b行代码比较,可以理解:
use后没有as时,缩短的命名空间默认为最后一个反斜杠后的内容。如上的:
  1. use animal\dog;
复制代码

2 X+ x: m! v: `
相当于
  1. use animal\dog as dog;
复制代码
$ b) D  [9 v# e* a% M; g4 I
2.namespace后面不建议加类名,但use后可以。1 J+ n. E" @; m- X
  1. //name.php
    5 ~) g! j' h  s
  2. ' k# B# N$ z0 a, h3 Q( [
  3. namespace animal\dog;8 d$ N' |& S  u: ^8 ]4 v  y

  4. 6 j! G) H3 |: ?
  5. class Life{
    4 ~6 q6 r+ D# u) b( [7 a, O: j
  6.     function __construct(){
    7 q* N- y# v' {/ c3 l9 q* O
  7.             echo 'dog life!';. s: x3 k0 [: W9 w8 n, b) d, x3 j
  8.         }
    0 y5 ?# ]: v: D$ w5 @. S" i2 r
  9. }
    9 k7 z% S- s0 n% Z" M5 i- j
  10. 2 M2 d# m) I) R. d5 ]& U: ]
  11. namespace animal\cat;
    4 i) G5 V% {  p) V. l' [

  12.   Y  N5 j+ U$ x* d+ v' g
  13. class Life{
    3 {4 d# K" I% q1 W" \( a" V
  14.     function __construct(){
      ]4 W# g* [5 }0 r3 S, P
  15.             echo 'cat life!';
    ' a: W; i# |. F, M2 `' Y% F/ p
  16.         }/ A0 r1 r* ]' |0 \0 M7 y2 W' q: V( a7 G
  17. }2 k2 O6 m. s3 D5 q/ c

  18. + ]+ n- j, [* s7 A  y/ f
  19. use animal\dog\Life as dog;  ! V6 Q, {6 [# B; L
  20. new dog();
复制代码

" u- E8 ?# ]. }  H0 n2 ^# e& P: ]
如上所示,use后加上类名后,就相当于把类改了个名称:由Life改为dog了。
上面不用as dog就会报错:
  1. Fatal error:  Cannot use animal\dog\Life as Life because the name is already in use
复制代码
7 N; g3 Y* \* B
因为cat下也有个一样名称的Life类。
可以理解为,使用use后,这个昵称对应的类只能归当前命名空间占有,其它命名空间下不允许存在该类。
  1. //name.php' v& o+ s  J$ q; p
  2. 1 v# R7 v- O/ z9 Z$ P! D0 V
  3. namespace animal\dog;% r+ e$ T* M! w  h$ _- v& D# E
  4. ; B) g5 J1 \+ j
  5. class Life{
    ) B; M  N' F$ ]
  6.     function __construct(){4 L, O' _) A, U8 {8 D
  7.             echo 'dog life!';  O8 C8 x2 q! x9 O1 ]6 ]7 g
  8.         }
      b" [7 v. l+ }6 y, r1 W5 b
  9. }0 _2 o3 M9 a8 a6 ~, Z3 _1 |6 u
  10. class Dog{. K3 _, ]9 V, _( X7 \3 G
  11.     function __construct(){
    + q: F; [% I# ~: l+ D
  12.             echo 'dog in dog!';  B" y6 h$ G7 Q- T% _% _
  13.         }: ^+ {8 W/ d0 B
  14. }% K/ [* m# @" `

  15. 6 R; I6 j/ `$ }) P0 J5 N7 g& c0 H
  16. namespace animal\cat;
    5 t7 K' v4 z. T% N

  17. " ^8 `6 G+ Z+ X) a: y. }
  18. // class Dog{
    + g, g' }5 W' Z! M, }1 a
  19. //     function __construct(){
    1 F+ _1 Y4 m. k& |% i$ Z6 J' i+ K
  20. //             echo 'dog in cat!';3 N0 Q2 a- Y( D; [) x# f' ?
  21. //         }' Z6 w' J+ u4 ]5 E4 Z% C7 W; }
  22. // }
    / ~5 {1 ?! U% C- a
  23. class Life{% i% P# A; g9 {9 o) T
  24.     function __construct(){
    ' [) F! X& h2 x- Q
  25.             echo 'cat life!';
    $ k# t% E1 w3 K! k
  26.         }
    # p; I# h: c: B
  27. }
    2 `# r/ M5 k/ ^2 X' Q

  28. 2 t! M8 O; ~8 D& l* Q
  29. use animal\dog;  ! A: q" X; J# L, S
  30. new dog\Dog();
复制代码
2 D# a: O; h4 k6 h3 o& o5 z
如上,使用了
  1. use animal\dog;
复制代码
2 J. x0 ^! U' M0 D! p/ I" ^; F7 @
cat
通过上面代码,我想使用use的目的效果(缩短命名空间名称)就很明显了。

5 W+ y( G# d4 f- w  g
简单总结一下:
namespace就是划分领域的作用,代表这些东西是属于某个命名空间下的。
use就是起小名的作用,不论写起来还是说起来都可以省不少事儿。
7 W+ b5 {$ U% F
! u% r9 K) z' ^% V8 P
8 n4 M8 L) `5 g6 i
2 D! m. H- F) s  [( Q
" G' @- q% \8 M" A' X





欢迎光临 cncml手绘网 (http://bbs.cncml.com/) Powered by Discuz! X3.2