下载tp5.1.35
composer create-projecttopthink/think=5.1.35 imooc_tp5 --prefer-dist
执行php think run
php think optimize:autoload 生成classmap.php
自动加载Loader 深度分析
类的自动加载
注册系统自动加载spl_autoload_register
loader::register
// Composer自动加载支持
autoload_static.php的属性都映射到本类
self::${$attr} = $composerClass::${$attr}
// 注册命名空间
addNamespace
会给composer下的autoload_static.php
填充新的内容
$prefixLengthsPsr4
$prefixDirsPsr4
// 注册类库别名Loader::addClassAlias
新增自定义类
2、放在thinkphp/library/ali/Send.php
composer下的自动加载
找到composer下的autoload_static.php
解读配置文件
配置文件的种类
1、惯例配置thinkphp/convention.php
2、应用配置config/app.php..
3、模块配置config/index
4、动态配置
php 底层ArrayAccess
提供像访问数组一样访问对象的能力的接口
实现它的四个方法
yaconf扩展
https://github.com/laruence/yaconf下载源码
phpize
./configure --with-php-config=/usr/local/php/bin/php-config
make &&make install
vim php.ini
extension=yaconf.so
yaconf.directory=/usr/local/nginx/html/imooc_tp5/ini
Config底层类分析
Load深度加载
Public/index.php 调用容器的app类,会调用initialize方法,它会调用init方法
其中有一段是调用load方法的
本身$this没有config这个属性,会调用容器种的__get()方法,最后实例化config类,调用load()方法,加载配置文件(多种格式)
Yaml初体验
1、安装pecl install yaml
https://blog.csdn.net/nianyixiaotian/article/details/97017381
2、php -i|grep php.ini
使用方法:
$abc=yaml_parse_file("../config/singwa.yaml");
优化1
框架的bug 需要把环境变量配置的代码提前到$this->configExt
项目中使用
在根目录创建.env 写入CONFIG_EXT=”.yaml”
在控制器层调用
优化2
设计模式
单例模式
注册树模式
依赖注入
1、依赖注入主要用来减少代码间的耦合
2、有效分离对象和它所需的外部资源
PHP的反射机制
Container容器类
编写自己的容器类
包括单例模式、注册树模式、反射机制
实例化
Countable类的使用
Container容器类刨析
获取容器中的对象实例
[if !vml]
[endif]
Make()方法 创建类的实例
[if !vml]
[endif]
[if !vml]
[endif]
[if !vml]
[endif]
在控制器中具体使用容器
[if !vml]
[endif]
门面模式facade
[if !supportLists]1、[endif]门面为容器中的类提供了一个静态调用接口
[if !supportLists]2、[endif]相比于传统的静态方法调用,带来了更好的可测试性和扩展性。
thinkphp\library\think\Facade.php此类是父类
thinkphp\library\think\facade\有很多文件,每个文件只做一件事
继承并返回类的标识。
[if !vml]
[endif]
底层的类不是静态的方法
如thinkphp\library\think\config.php类里不是静态的方法。
上层可以通过静态的方式去用think\xxx.php的方法。
1、dump(\think\facade\Config::get("app."));
2、\think\facade\Config类没有get方法,会调用父类facade类的__callStatic
[if !vml]
[endif]
3、__callStatic的createFacade,创建实例
[if !vml]
[endif]
好处:通过静态的方法调用类的方法。
图示
[if !vml]
[endif]
在控制器中的具体使用
dump(\Config::get("app."));
dump(\think\facade\Config::get("app."));
门面模式facade实战
普通的写法
在application\common\Singwa.php
[if !vml]
[endif]
控制器层实例化调用
[if !vml]
[endif]
使用门面模式进行
[if !vml]
[endif]
[if !vml]
[endif]
[if !vml]
[endif]
最后在控制器用静态的方式调用
[if !vml]
[endif]
框架执行流程以及路由解读
Container::get('app')找到think\App.php
初始化应用init分析
1、多次初始化
2、检测被多次初始化
$array=debug_backtrace();var_dump($array);
想要知道某方法被在哪调用可以使用它,主要是回溯跟踪。
App.php下的init做的功能
1、加载初始化文件 $path.init.php(本身是没有的,$path是application或具体模块目录)
2、加载行为扩展文件$path.tags.php (application下有此文件)
3、加载公共文件$path.common.php (application下有此文件)
4、加载助手函数helper.php
5、加载中间件 $path.middleware.php(本身是没有的,$path是application或具体模块目录)
6、注册服务的容器对象实例$path.provider.php 然后bindTo($provider)
7、自动读取配置目录文件,并load
8、如果有具体的模块,则对容器中的对象实例进行配置更新
注册服务的容器对象实例
[if !vml]
[endif]
[if !vml]
[endif]
application\common\Sa.php
[if !vml]
[endif]
控制器层
dump(Container::get('sa')->abcd());
路由初始化
initialize方法最后调用
$this->routeInit();
主要工作是扫描根目录的route,引入所有文件。
并导入
[if !vml]
[endif]
Route::get指向的是think\Route.php下的rule方法
[if !vml]
[endif]
http://127.0.0.1:8000/hello/111
Route类种rule方法执行方式脑图
https://naotu.baidu.com/file/bacd378635905a00c7a20bd9ca9d59bf
route.php--->Domain.php--继承-->RuleGroup.php—调用—>addRule方法
路由规则预处理setRule方法
如果是$ 则处理成 $this->option['complete_match']= true;
[if !vml]
[endif]
[if !vml]
[endif]
可选的是[:name]=>
[if !vml]
[endif]
$value的结果是
[if !vml]
[endif]
[if !vml]
[endif]
Set的结果是
$this->item[name][]=$value
[if !vml]
[endif]
[if !vml]
[endif]
setRule注册路由规则
$this->rule[$route->getDomain()][$rule][$route->getMethod()]= $route;
$rule路由规则
[if !vml]
[endif]
路由参数
Rule.php 的rule()方法的第四个参数option=[]来表示
Route::get() //返回的是RuleItem对象
两种方式设置参数
[if !vml]
[endif]
变量规则
Rule.php的rule()方法的第五个参数$pattern
写法
[if !vml]
[endif]
另外一种写法
[if !vml]
[endif]
注册变量规则
[if !vml]
[endif]
资源路由
支持设置restful请求的资源路由,
[if !vml]
[endif]
[if !vml]
[endif]
Route.php定义了rest的几种规则
[if !vml]
[endif]
Resource这个类在library\think\route\Resoure.php
通过资源路由的实例
[if !vml]
[endif]
[if !vml]
[endif]
[if !vml]
[endif]
路由配置--数组方式配置
之前都是调用route类的方法,现在使用返回数组的方式
[if !vml]
[endif]
APP.php的initialize方法,调用了routeInit路由初始化方法
它调用了import方法
import方法做路由规则的导入
[if !vml]
[endif]
Dispatch初始
APP.php的run()方法
[if !vml]
[endif]
打印两个场景
[if !supportLists]1、[endif]通过路由配置
[if !supportLists]2、[endif]普通的,没有经过配置的
无论是什么模式,最后$dispatch的结果都是
[if !vml]
[endif]
上上图中的routeCheck()方法种有url路由检测
[if !vml]
[endif]
最后return $dispatch
而check()方法
[if !vml]
[endif]
[if !vml]
[endif]
request类如何找到
上上图中的$this->request,是Route.php的属性,
[if !vml]
[endif]
[if !vml]
[endif]
没有容器则创建容器
[if !vml]
[endif]
调用container.php的make方法,会找到Request.php
DOmain.php->check()------RuleGroup.php->check()
检测url变量和规则路由是否匹配
Route.php -->check()检测url路由
Domain.php->check()检测域名路由parent::check($request, $url, $completeMatch)
RuleGroup.php->check()检测分组路由
RuleGroup.php->checkMergeRuleRegex()检测分组路由
[if !vml]
[endif]
RuleItem.php-> checkRule()检测路由
其中会调用match()方法主要是检测url变量和规则路由是否匹配
dump($match)时变量数组
控制器解读
课前复习
匿名函数
在php5.3及以上版本
匿名函数,也叫闭包函数,允许临时创建一个没有指定名称的函数。
[if !vml]
[endif]
Eg2:匿名函数作为函数的参数访问
Demo(function(){return“####”})
闭包
连接闭包和外界变量的关键字:USE
闭包可以保存所在代码块上下文的一些变量和值。
PHP在默认情况下,匿名函数不能调用所在代码块的上下文变量,而需要通过使用use关键字
[if !vml]
[endif]
匿名函数作为返回值返回
[if !vml]
[endif]
通俗的说:子函数可以使用父函数中的局部变量,这种行为就叫做闭包!
闭包函数返回时,该函数内部变量处于激活状态,函数所在栈区依然保留
实例化控制器
App.php run()方法
[if !vml]
[endif]
[if !vml]
[endif]
调用该类的run()
[if !vml]
[endif]
在本类是抽象方法,在Module.php中实现
[if !vml]
[endif]
[if !vml]
[endif]
实例化控制器
[if !vml]
[endif]
执行控制器中的方法
Module.php 中的exec()方法
[if !vml]
[endif]
[if !vml]
[endif]
[if !vml]
[endif]
[if !vml]
[endif]
$data时方法最后的return “hello world”
闭包返回的数据,最后注册到中间件中
执行autoResponse调度
[if !vml]
[endif]
[if !vml]
[endif]
第一次走的是elseif 执行Response::create()方法
[if !vml]
[endif]
实例化的时候会调用构造方法,
[if !vml]
[endif]
最后autoResponse返回的的结果是
以及
[if !vml]
[endif]
返回的结果是一样的
[if !vml]
[endif]
[if !vml]
[endif]
[if !vml]
[endif]
执行中间件的调度
输出数据到终端
[if !vml]
[endif]
fastcgi_finish_request()
客户端响应到此结束,服务端代码还是会去执行
控制器的初始化
[if !vml]
[endif]
trait特性讲解
php以前是单继承的,无法同时继承多个类
trait jump类
[if !vml]
[endif]
[if !vml]
[endif]
DB和模型
DB操作
Db::query($sql)
Db需要use \think\Db
query这个静态方法是没有的
\think\Db.php类文件没有query方法,会调用__callStatic()方法
会调用本类的static::connect()方法,主要是用来切换数据库连接
[if !vml]
[endif]
[if !vml]
[endif]
[if !vml]
[endif]
$this->connection 是Connection.php 下的Mysql的实例,它在connector下,Mysql.php没有query方法,去父类找query()
Db类库结合连接器、查询器、生成器
$res=DB::table('imooc_user')->where(['id'=>1])->find();
没有tabe方法,会调用__callStatic()方法
call_user_func_array([static::connect(),$method], $args);
这里是 static::connect是结果new Query
table 在此类中,where也一样,find 方法会
$result = $this->connection->find($this);
而connection是依赖注入的方式find(Query $query)
此方法中有生成器
// 生成查询SQL
$sql = $this->builder->select($query);
builder中的select方法主要是使用str_replace替换下列字符串中的字符
SELECT%DISTINCT% %FIELD% FROM %TABLE%%FORCE%%JOIN%%WHERE%%GROUP%%HAVING%%UNION%%ORDER%%LIMIT%
%LOCK%%COMMENT%
model场景
[if !vml]
[endif]
model场景分析--新增逻辑
print_r(model('user'));
app\index\model\User Object ( [data] => Array ( ) [relation]
=> Array ( ) )
save()方法在model.php
在此方法中调用本类的checkBeforeSave()方法,主要功能是写入之前检查数据
checkBeforeSave调用setAttr
[if !vml]
[endif]
setAttr方法
// 检测修改器$method = 'set' . Loader::parseName($name, 1) . 'Attr';
最后形成
// 设置数据对象属性
return$this->data[$name] = $value;
深度分析
设置完属性对象,逻辑还是回到save()方法中,接着进行insertData方法
[if !vml]
[endif]
[if !vml]
[endif]
其中上上图的insert方法
[if !vml]
[endif]
[if !vml]
[endif]
最后在此方法中执行execute()
异常处理、缓存
Base.php有类的关系映射,通过\Cache找到对应的门面模式
通过配置文件设置需要type是文件,redis,memcache,
通过工厂模式进行调用
面试技巧
MySQL基本使用、优化(加索引、主从分离,读写分离),查询elecsearch
redis场景投票、抢票、排序
Nginx 基本配置限流,负载均衡
框架:深入理解框架就够了
简历体现技术难点
内推:算法,数据结构
框架层:设计模式、门脸模式、迭代器、反射、类自动加载、路由
对框架的理解
[if !supportLists]1、[endif]组织好目录结构,如应用目录,配置目录,
[if !supportLists]2、[endif]入口文件处理自动加载(框架层的自动加载,composer的自动加载)
[if !supportLists]3、[endif]容器(单例模式)
[if !supportLists]4、[endif]配置文件的加载(tp配置文件写在文件里,对性能有损耗,yaconf)
[if !supportLists]5、[endif]路由(中大型公司用不到,在nginx做配置就可以)