博客列表 >PHP大牛成长之路:命名空间与自动加载器

PHP大牛成长之路:命名空间与自动加载器

周Sir-BLOG
周Sir-BLOG原创
2020年08月02日 01:13:41707浏览

1、命名空间

1.1、理解全局成员

  1. // 全局成员共有四个: 函数, 常量, 类/接口(函数外部声明)
  2. // 1、函数
  3. function demo() {}
  4. // 2、常量
  5. const USER_NAME = 'Peter Zhu';
  6. // 3、类
  7. class User {}
  8. // 4、接口
  9. interface iDb {}
  10. // 全局成员最大特点:全局可见 / 最大缺点: 不能重复命名

1.2、命名空间的定义

1、命名空间使用 namespace 关键字定义,语法如下:

  1. namespace project1;
  2. namespace project2;
  3. namespace project3;

一般情况下,不推荐单个文件中定义多个命名空间,如果需要,可以使用大括号进行定义:

  1. namespace project1
  2. {
  3. }
  4. namespace project2
  5. {
  6. }
  7. namespace project3
  8. {
  9. }

1.3、命名空间的访问

非同一命名空间的访问,需指定要访问的命名空间名称
一旦定义命名空间,命名空间{}之外不能存在任何代码

  1. namespace project1
  2. {
  3. // 接口
  4. interface iTest {
  5. public function getSite();
  6. }
  7. // 类
  8. class Demo implements iTest
  9. {
  10. public function getSite()
  11. {
  12. return 'php中文网';
  13. }
  14. }
  15. // 函数
  16. function f1(iTest $obj) {
  17. return $obj->getSite();
  18. }
  19. // 常量
  20. const SITE_NAME='php中文网';
  21. //命名空间内访问:
  22. echo (new Demo)->getSite().'<br>';
  23. echo f1(new Demo).'<br>';
  24. echo SITE_NAME.'<br>';
  25. }
  26. //-------------------------------------------------------------
  27. // 注意:一旦定义命名空间,命名空间{}之外不能存在任何代码
  28. // echo (new Demo)->getSite().'<br>';
  29. // echo f1(new Demo).'<br>';
  30. // echo SITE_NAME.'<br>';
  31. //报错:Fatal error: No code may exist outside of namespace {}
  32. //-------------------------------------------------------------
  33. namespace project2
  34. {
  35. //在project2访问project1内容:
  36. echo '<hr>';
  37. //方法访问:示例化对象时加上要访问的命名空间名称
  38. echo (new \project1\Demo)->getSite().'<br>';
  39. //函数访问:函数前及示例化对象时都要加上要访问的命名空间名称
  40. echo \project1\f1(new \project1\Demo).'<br>';
  41. //常量访问:常量前加上要访问的命名空间名称
  42. echo \project1\SITE_NAME.'<br>';
  43. // “\”表示全局“路径”,相当于根目录位置开始
  44. }

1.4、命名空间使用

  • 非限定名称: 总是从全局空间开始, 前面总是一个: “\” , “\A\B…”

  • 限定名称:类名总是会有一个或多个空间名称,但不是从全局开始, “A\B…”

  • 完全限定名称:就是不带有空间名称的类,如当前命名空间的类。

  1. namespace project1
  2. {
  3. class T1 {}
  4. }
  5. namespace project2
  6. {
  7. class T1 {}
  8. }
  9. namespace project3
  10. {
  11. class T1 {}
  12. }
  13. namespace demo\project
  14. {
  15. class T1 {}
  16. }
  17. namespace demo
  18. {
  19. class T1 {}
  20. // 1. 完全限定名称的类名:\project1\T1 ,类似绝对路径
  21. echo \project1\T1::class, '<br>';
  22. echo \project2\T1::class, '<br>';
  23. echo \project3\T1::class, '<hr>';
  24. // 2. 限定名称的类名: demo\project 理解成相对路径(当前命名空间下的下一级可以省略当前命名空间)
  25. echo project\T1::class, '<hr>';
  26. // 3. 非限定名称的类:
  27. echo T1::class, '<hr>';
  28. }

1.5、命名空间的别名

  1. namespace project1
  2. {
  3. class T1 {}
  4. }
  5. namespace project2
  6. {
  7. class T1 {}
  8. }
  9. namespace demo
  10. {
  11. // 1、非别名访问
  12. echo \project1\T1::class, '<br>';
  13. echo \project2\T1::class, '<hr>';
  14. // 2、别名访问
  15. use \project1\T1 AS P1;
  16. use \project2\T2 AS P2;
  17. echo P1::class, '<br>';
  18. echo P2::class, '<hr>';
  19. }
  20. namespace demo1
  21. {
  22. class T1 {}
  23. // 3、如果当前类中也有一个与之同名的非限定的类,就不能省略别名
  24. use \project1\T1 AS PT1;
  25. echo PT1::class, '<br>';
  26. echo T1::class, '<hr>';
  27. }

2、类的加载

如demo.php目录下有以下几个类文件:

  1. #inc/lib/Test1.php
  2. // 当前类的命名空间与当前类的文件路径对应起来
  3. namespace inc\lib;
  4. // 类名必须与当前类文件名称相同
  5. class Test2 {}
  6. function show(){
  7. return 'PHP中文网';
  8. }
  9. #inc/lib/Test2.php
  10. namespace inc\lib;
  11. class Test2 {}
  12. #inc/lib/Test3.php
  13. namespace inc\lib;
  14. class Test3 {}

2.1、手动加载

  1. # demo.php
  2. require 'inc/lib/Test1.php';
  3. require 'inc/lib/Test2.php';
  4. require 'inc/lib/Test3.php';
  5. var_dump(new inc\lib\Test1());
  6. echo '<br>';
  7. var_dump(new inc\lib\Test2());
  8. echo '<br>';
  9. var_dump(new inc\lib\Test3());

如果一个php文件里需要引用更多对象,那么这个文件就需要使用include或require逐个引用,于是就可以使用自动加载。

2.2、自动加载

  1. # demo.php
  2. function classLoader($class)
  3. {
  4. // DIRECTORY_SEPARATOR 可以随操作系统不同,使用不同的目录分隔符
  5. //1、获取文件名(替换目录分隔符)
  6. // $path = str_replace('\\', '/', '\inc\lib\Test1' );
  7. $path = str_replace('\\', DIRECTORY_SEPARATOR, $class);
  8. //2、获取文件名完整路径(替换目录分隔符)
  9. $file = __DIR__ . DIRECTORY_SEPARATOR . $path . '.php';
  10. //3、检测文件是否存在,存在则引入
  11. if (file_exists($file)) {
  12. require_once $file;
  13. //equire()与require_once()的区别
  14. // require()会在每一处出现调用的地方都重新调用(加载文件)。
  15. // require_once() 指定的文件如果已经被包含过,则不会再次包含。它可以避免函数重定义,变量重新赋值等问题。
  16. }
  17. }
  18. try {
  19. spl_autoload_register('classLoader');
  20. }catch (Exception $e){
  21. die($e->getMessage());
  22. }
  23. var_dump(new inc\lib\Test1());
  24. echo '<br>';
  25. var_dump(new inc\lib\Test2());
  26. echo '<br>';
  27. var_dump(new inc\lib\Test3());
  28. //实例化对象可以使用use引用以缩短代码可读性
  29. use inc\lib\Test1;
  30. var_dump(new Test1());

使用匿名函数实现:

  1. try {
  2. spl_autoload_register(function($class){
  3. $path = str_replace('\\', DIRECTORY_SEPARATOR, $class);
  4. $file = __DIR__ . DIRECTORY_SEPARATOR . $path . '.php';
  5. if (file_exists($file)) {
  6. require_once $file;
  7. }
  8. });
  9. } catch (Exception $e) {
  10. die($e->getMessage());
  11. }
  12. // 通过实例化自动加载inc\lib\Test1.php
  13. new inc\lib\Test1();
  14. // 输出inc\lib\Test1.php中的函数
  15. echo \inc\lib\show();
  16. echo '<br>';
  17. var_dump(new inc\lib\Test1());
  18. echo '<br>';
  19. var_dump(new inc\lib\Test2());
  20. echo '<br>';
  21. var_dump(new inc\lib\Test3());

总结

1、全局成员共有四个: 函数, 常量, 类/接口(函数外部声明);
2、命名空间使用:namespace 空间名;namespace 空间名{}定义;
3、对命名空间的访问和使用有了初步理解;
4、类的加载需要includerequire手动引入类文件,使用spl_autoload_register()可以实现自动加载,通过验证,自动加载后函数也可以自动加载并访问。

声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议
老周2020-08-02 21:26:422楼
我发现点回复没有用啊,老师都没评价,你就看出好了,哈哈哈
老黑2020-08-02 20:13:171楼
总结的很好啊,后面关注下