[关闭]
@Purpose 2017-03-12T08:08:02.000000Z 字数 7463 阅读 1202

YII框架特性学习之高效篇

YII学习笔记


YII的延迟加载


类的延迟加载

lazy loading技术,yii加载技术依赖于php的spl_autoload_register(),注册一个自己的自动加载函数(autoloader),并插入到自动加载函数栈的最前面,确保yii的autoloader会被最先调用,类自动加载的这个机制的引入要从入口文件index.php 开始说起。在框架启动最开始时,入口脚本index.php(basic/web)会执行Yii.php文件,这时候就注册了自动加载的函数autoload,以后PHP程序在执行的时候,遇到一些不认识的类的时候,就会通过autoload函数去自动加载各种各样的类的信息,以此来完成延迟加载,进一步提高程序的执行效率。

  1. <?php
  2. defined('YII_DEBUG')or define('YII_DEBUG',false);
  3. defined('YII_ENV')or define('YII_ENV','prod');
  4. //这个是第三方的autoloader
  5. require(__DIR__.'/../vendor/autoload.php');
  6. //这个是yii的Autoloader,放在最后面,确保 其插入的autoloader会放在最前面
  7. require(__DIR__.'/../vendor/yiisoft/yii2/Yii.php');
  8. require(__DIR__.'/../../common/config/aliases.php');
  9. $config=yii\helpers/ArrayHelper::merge(
  10. require(__DIR__.'../../common/config/main.php'),
  11. require(__DIR__.'../../common/config/main-local.php'),
  12. require(__DIR__.'../config/main.php'),
  13. require(__DIR__.'../config/main-local.php')
  14. );
  15. $application=new yii\web\Application($config);
  16. $application->run();
  17. //这个文件主要看点在于第三方的autoloader与Yii实现的autoloader的顺序,不管第三方的代码是如何使用spl_autoloader_register()来注册资金的autoloader的。只有yii的代码在最后面,就可以确保其可以将自己的autoloader插入到整个 autoloader栈的最前面,从而在需要时最先被调用
  1. /*****lazy_loading/index.php*****/
  2. //Yii框架也根据这种机制实现了类的延迟加载,做得更加地道(使用spl_autoload_register()自动完成类的加载)。
  3. //第五步、所以在最后,当PHP发现实例化时不认识Class1,它会把Class1的名字传递给my_loader函数的$class参数当中,那么$class变量就代表了Class1。(同理,当PHP实例化Class2时也如此)
  4. function my_loader($class){
  5. //第三步、但是以下的代码不仅加载了Class1,还加载了Class2,导致类还是会被多余加载。怎样解决这个问题?
  6. /***require('class\Class1.php');****
  7. ****require('class\Class2.php');***/
  8. //第四步、所以可以通过$class对require代码进行优化:把Class1改为$class变量,因为\具有转义的意思,所以需要2个\\来代表1个\。
  9. require('class\\'.$class.'.php');
  10. }
  11. //第二步、这是由于PHP准备报错时,这个函数告诉PHP先不报错,先去运行一下my_loader。然后PHP真的去运行my_loader函数,把里面的Class1类文件加载进来了。也就不会报错了。
  12. spl_autoload_register(my_loader);
  13. $is_girl = $_GET['sex'] == 0 ? ture : false;
  14. if ($is_girl) {
  15. echo 'this is a girl!';
  16. $Class1 = new Class1;
  17. //第一步、当PHP运行到这一行,不认识Class1并且在这里也没有加载类文件,这时候PHP八成会报错,但实际上并没有报错。
  18. }else{
  19. echo 'not a girl!';
  20. $Class2 = new Class2;
  21. }
  22. /*****lazy_loading/class/Class1.php*****/
  23. class Class1{}
  24. /*****lazy_loading/class/Class2.php*****/
  25. class Class2{}
  26. ?>

类的映射表机制

Yii框架也提供了类的映射表机制去进一步地更快加载类,可以通过使用Yii::$classMap,对延迟加载机制进行优化,是典型的空间换时间的做法(常用的类,不建议不常用的类也放在$classMap中,会让在这个数组里查找相应的类的速率降低同时会占用更大的内存)

  1. //使用类的映射表去加载Order类,使用\Yii全局类里的$classMap['参数key:加载的类的全名','']数组,因为是要根据它的名字去加载它的绝对路径,所以这个数组的值就是Order类所在类文件的绝对路径。
  2. \Yii::$classMap['app\models\Order'] = 'C:\wamp\www\mooc\yii\basic\modelsx\Order.php';
  3. //实例化Order活动记录
  4. $order = new Order;

组件的延迟加载

index.php请求交给应用主体后,应用主体实例化后会加载一系列组件(如sessionresponse等),应用主体加载后会交给控制器使用。
组件的延迟加载就是:应用主体并没有加载进来,而是在控制器真正使用时才被加载进来,又app初始化时加载延迟到控制器真正使用时,如:
$session=\Yii::$app->session;
session实际不存在,只有调用时,才加载,流程是:
当访问session时,触发PHP的魔术方法__get()方法,方法中将组件加载,实现了延迟加载/初始化

比如用户给Yii框架的项目发送了一个请求,index.php入口脚本文件最先处理这个请求->再把请求交给应用主体app处理(在处理请求之前,把它自己给实例化出来,实例化过程当中会去加载组件<-组件components[包含:session/request/response...组件])->app加载完组件之后再把请求交给Controller处理(控制器在处理请求时可以使用app加载过来的组件)。
那么所谓的组件延迟加载就是:看起来好像是app预先加载了components里的组件,然后在Controller中直接拿过来用。实际上app并没有真正的加载components里的组件,而是在Controller里真正使用到某一个组件(如session)时才加载进来,也就是说把这个组件的加载过程由app的初始化延迟到Controller真正的使用某一个组件时。


YII的缓存


数据缓存

数据缓存的CRUD

  1. //获取缓存组件
  2. $cache=\YII::$app->cache;
  3. //往缓存中写入数据add
  4. $cache->add('key1','hello world');
  5. //修改数据set
  6. $cache->set('key1','hahhaha');
  7. //删除数据delete
  8. $cache->delete('key1');//只能删除一条
  9. //清空缓存flush
  10. $cache->flush();
  11. //读缓存get
  12. $data=$cache->get('key1');
  13. var_dump($data);

缓存时间

  1. //获取缓存组件
  2. $cache=\YII::$app->cache;
  3. //有效期设置15秒
  4. $cache->add('key','value',15); //add新增不覆盖
  5. $cache->set('key1','value',15); //set不论有没有,直接覆盖
  6. //读取缓存
  7. echo $cache->get('key');

缓存文件的依赖关系

  1. //文件依赖 如果hw.txt发生修改 缓存失效或为false
  2. $dependency = new \yii\caching\FileDependency(['fileName'=>'hw.txt']);
  3. $cache->add('file_key','hello depend', 3000, $dependency);
  4. //表达式依赖 表达式的值发生变化则缓存失效
  5. $dependency = new \yii\caching\ExpressionDependency(
  6. ['expression'=>'\YII::$app->request->get("name")']
  7. );
  8. $cache->add('expression_key', 'hello cache', 3000, $dependency);
  9. //DB依赖 数据表数据修改则缓存失效
  10. $dependency = new \yii\caching\DbDependency(
  11. ['sql'=>'select count(*) from yii.order']
  12. )
  13. $cache->add('db_key', 'hello cache', 3000, $dependency);

片段缓存


片段缓存的使用

  1. //控制器中开启
  2. return $this->render('view_file_name');
  3. //在视图文件中设置
  4. if ($this->beginCache('cache_name')) {
  5. /***...html code...***/
  6. $this->endCache();
  7. }

由调用方法可知$this->beginCache('name')负责判断及输出缓存内容
若无缓存,则返回true,进入到if的代码块内;
然后由$this->endCache()捕捉if代码块内的输出并缓存;
下次再运行至此处时,beginCache将输出缓存并返回false,以跳过if代码块


片段缓存的设置

  1. //前端页面的区域(不经常动的)
  2. //缓存时间
  3. $duration = 15;
  4. if($this->beginCache('cache_div',['duration'=>$duration])){
  5. <div id="cache_div"></div>
  6. }
  7. $this->endCache();
  8. //缓存依赖
  9. $dependency = [
  10. 'class'=>'yii\caching\FileDependency',
  11. 'fileName'=>'hw.txt'
  12. ];
  13. if($this->beginCache('cache_div',['dependency'=>$dependency])){
  14. <div id="cache_div"></div>
  15. }
  16. $this->endCache();
  17. //缓存开关
  18. $enabled = false;
  19. if($this->beginCache('cache_div',['enabled'=>$enabled])){
  20. <div id="cache_div"></div>
  21. }
  22. $this->endCache();

片段缓存的嵌套设置

  1. <!--HelloController.php-->
  2. return $this->renderPartial('cache');
  3. <!--basic/views/hello/cache.php-->
  4. <!-- 片段缓存嵌套 -->
  5. <!-- 片段缓存的嵌套使用有时会产生一些问题:比如给内外的beginCache都设上一个缓存有效时间duration。
  6. 第1次刷新浏览器时,outer和inner里的内容都被缓存了;在20内,如果此时修改了inner里的缓存内容,
  7. 再次刷新浏览器,inner里修改后的缓存内容不会被显示,这是因为在20秒有效期内,PHP只解析了outer的缓存(没过期直接抛出缓存数据),
  8. 没有去解析inner的缓存(尽管inner缓存的有效期已过并且缓存内容修改了);只有当outer的20秒有效期过期,此时刷新浏览器,
  9. inner里被修改过的缓存内容才会被显示出来。-->
  10. <?php if($this->beginCache('cache_div',['duration'=>20])){?>
  11. <div id='cache_outer_div'>
  12. <div>这里是外层,待会会被缓存</div>
  13. </div>
  14. <?php if($this->beginCache('cache_inner_div',['duration'=>1])){?>
  15. <div id='cache_inner_div'>
  16. <div>这里是内层,待会会被缓存</div>
  17. </div>
  18. <?php
  19. $this->endCache();
  20. }
  21. ?>
  22. <?php
  23. $this->endCache();
  24. }
  25. ?>

页面缓存

  1. //behavior会先于action操作被YII框架先执行
  2. public function behaviors(){
  3. echo '1';
  4. return [
  5. [
  6. 'class'=>'yii\filters\PageCache',//开启页面缓存
  7. 'duration'=>1000,//缓存时间
  8. 'only'=>['index','test']//指定缓存哪些方法
  9. 'dependency'=>[
  10. 'class'=>'yii\caching\DbDependency',
  11. 'fileName'=>'hw.txt'
  12. ]//缓存的依赖方式
  13. ]
  14. ];
  15. }
  16. public function actionIndex(){
  17. echo '2';
  18. }
  19. public function actionTest(){
  20. echo '2';
  21. }

http缓存


http缓存原理

last-modify是个时间,用来区别是否有修改,但还是会存在文件实质上没有被修改,但修改时间(last-modify)变化的情况,此时就要根据etag来区分是否真正有修改.
在浏览器端,通过请求头信息 last-modified, etag来判断是文件是否发生变化,若无无变化,则使用状态码304(Not Modified),通知浏览器使用缓存


http缓存的时机

  1. <?php
  2. namespace app\controllers;
  3. use yii\web\Controller;
  4. use app\models\Customer;
  5. use app\models\Order;
  6. class HelloController extends Controller{
  7. /**
  8. * 先于操作来执行
  9. * 1.F是怎么告诉L把数据缓存在浏览器本地的呢?
  10. * HttpCache类决定了L要不要缓存F发送给它的数据。F发送数据给L是以响应的方式,响应分为响应头和响应体2部分
  11. * HttpCache在响应发送给L之前,会往响应头存放一些缓存相关的信息(Cache-Control:"public,max-age=3600")
  12. * 然后L在接收到响应之后会根据缓存相关信息(Cache-Control)来决定把数据缓存在L这边
  13. */
  14. public function behaviors(){//行为相关的方法
  15. return [
  16. [
  17. 'class'=>'yii\filters\HttpCache',
  18. //时间标识
  19. 'lastModified'=>function(){
  20. return 1432817565;//返回一个时间戳
  21. }
  22. //内容标识
  23. 'etagSeed'=>function(){
  24. return 'etagseed2';//返回字符串
  25. }
  26. ]
  27. ];
  28. }
  29. /**
  30. * 自己设置的last_modified的时间戳,使得两次请求携带的last_modified时间戳是一样的,
  31. * 即使修改了文件的数据信息,自定义设置的last_modified没有修改
  32. * (在未自定义设置last_modified的情况下,last_modified的时间戳是会自动修改为修改时的时间戳的)
  33. */
  34. public function actionIndex(){
  35. return $this->renderPartial('index');
  36. }
  37. }

http缓存实例

  1. <?php
  2. namespace app\controllers;
  3. use yii\web\Controller;
  4. use app\models\Customer;
  5. use app\models\Order;
  6. class HelloController extends Controller{
  7. public function behaviors(){//行为相关的方法
  8. return [
  9. [
  10. 'class'=>'yii\filters\HttpCache',
  11. 'lastModified'=>function(){//根据浏览器的数据和服务器的数据修改日期是否一样
  12. return filemtime('hw.txt');//取最后一次修改时间,返回一个时间戳
  13. },
  14. 'etagSeed'=>function(){//判断浏览器的数据和服务器的数据内容是否一样
  15. $fp = fopen('hw.txt','r');
  16. $title = fgets($fp);//取第一行数据
  17. fclose($fp);
  18. return $title;//和返回数据内容相关的字符串
  19. }
  20. ]
  21. ];
  22. }
  23. public function actionIndex(){
  24. $content = file_get_contents('hw.txt');//把文件全部数据读出来
  25. return $this->renderPartial('index',['new'=>$content]);
  26. }
  27. }
  28. /*********************************************************************/
  29. views/hello/index.php
  30. <div>
  31. <div><?=$new;?></div>
  32. </div>
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注