其实框架的核心思想都是基本上一直的,只要精通其中一个框架并且知道框架的底层原理,那么基本上其他框架都可以非常快速的掌握。现阶段的PHP工程师,很多工程师都停留在使用框架的层次上,通过文档才能够使用,其实这对于工程师来说是可怕的,因为框架的更新换代非常快,深入理解框架的源码可以理解框架是如何实现的,以后再遇到其他的框架就可以非常快速的掌握,通过阅读源码也可以使工程师的水平提升非常多。一个框架可能会涉及到很多的设计模式,也是一个很好的看到设计模式应用的例子。
指定版本安装TP
1 |
composer create-project topthink/think=5.1.35 tp5.1 |
类的自动加载
简介
启动TP的入口文件是Public下面的index.php,
1 2 3 4 5 6 7 8 9 10 |
// [ 应用入口文件 ] namespace think; // 加载基础文件 require __DIR__ . '/../thinkphp/base.php'; // 支持事先使用静态方法设置Request对象和Config对象 // 执行应用并响应 Container::get('app')->run()->send(); |
这个类会去加载一个base.php,在这里面有
1 2 3 4 5 |
// 载入Loader类 require __DIR__ . '/library/think/Loader.php'; // 注册自动加载 Loader::register(); |
这个register就是自动加载的灵魂,其他框架也是这个逻辑,在入口文件执行的时候执行自动加载,执行是在loader.php中,在这里会加TP的加载和composer的加载都会在这里执行,
最基础的自动加载 – spl_autoload_register
准备的基础的类
Bing.php
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<?php /** * Created by bingxiong. * Date: 4/10/19 * Time: 11:05 PM * Description: */ class Bing{ public function hi(){ echo 'hi'; } } |
现在创建一个文件,我们希望在这个文件里面new 一个类并执行这个类的方法,如果直接就new是无法通过类型来找到这个类的,因此这里就需要使用自动加载通过spl_autoload_register函数来实现,这个函数的第一个参数是一个自定义的函数,这里是autoload,在这个函数里面include需要的类,就实现了一个最简单的自动加载
spl.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<?php /** * Created by bingxiong. * Date: 4/10/19 * Time: 11:04 PM * Description: */ // 第二个参数是无法注册成功是否抛出异常 // 第三个参数是是否加载到队列之首 spl_autoload_register("autoload",true,true); // 自定义的类加载 function autoload($className=""){ echo '类名为'.$className.PHP_EOL; include "./{$className}.php"; } $a = new Bing(); $a->hi(); |
自动加载loader深度分析
在TP中最核心的的自动加载是这个register
有些地方是两个斜线,这是转义而已,其实就是一个斜线
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
// 注册自动加载机制 public static function register($autoload = '') { // 注册系统自动加载 // 但调用一个不存在的类的时候才会调用这个autoload方法 spl_autoload_register($autoload ?: 'think\\Loader::autoload', true, true); $rootPath = self::getRootPath(); self::$composerPath = $rootPath . 'vendor' . DIRECTORY_SEPARATOR . 'composer' . DIRECTORY_SEPARATOR; // Composer自动加载支持 if (is_dir(self::$composerPath)) { if (is_file(self::$composerPath . 'autoload_static.php')) { require self::$composerPath . 'autoload_static.php'; $declaredClass = get_declared_classes(); $composerClass = array_pop($declaredClass); foreach (['prefixLengthsPsr4', 'prefixDirsPsr4', 'fallbackDirsPsr4', 'prefixesPsr0', 'fallbackDirsPsr0', 'classMap', 'files'] as $attr) { if (property_exists($composerClass, $attr)) { self::${$attr} = $composerClass::${$attr}; } } } else { self::registerComposerLoader(self::$composerPath); } } // 注册命名空间定义 self::addNamespace([ 'think' => __DIR__, 'traits' => dirname(__DIR__) . DIRECTORY_SEPARATOR . 'traits', ]); // 加载类库映射文件 if (is_file($rootPath . 'runtime' . DIRECTORY_SEPARATOR . 'classmap.php')) { self::addClassMap(__include_file($rootPath . 'runtime' . DIRECTORY_SEPARATOR . 'classmap.php')); } // 自动加载extend目录 self::addAutoLoadDir($rootPath . 'extend'); } |
加载类库映射文件 – 通过命令行
1 |
php think optimize:autoload |
可以生成classname.php,是类的映射关系,大概在这个文件中的属性有这些: