PHP的Yii框架中YiiBase入口类的扩展写法示例


Posted in PHP onMarch 17, 2016

通过yiic.php自动创建一个应用后,入口文件初始代码如下:

<?php
// change the following paths if necessary
$yii=dirname(__FILE__).'/../yii/framework/yii.php';
$config=dirname(__FILE__).'/protected/config/main.php';
// remove the following lines when in production mode
defined('YII_DEBUG') or define('YII_DEBUG',true);
// specify how many levels of call stack should be shown in each log message
defined('YII_TRACE_LEVEL') or define('YII_TRACE_LEVEL',3);
require_once($yii);
Yii::createWebApplication($config)->run();

其中第三行引入了一个yii.php的文件,这个可以在yii核心目录里的framework/下找到,这个文件中定义了一个Yii类,并且继承了YiiBase类。

代码如下

require(dirname(__FILE__).'/YiiBase.php');
 
/**
 * Yii is a helper class serving common framework functionalities.
 *
 * It encapsulates {@link YiiBase} which provides the actual implementation.
 * By writing your own Yii class, you can customize some functionalities of YiiBase.
 *
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @package system
 * @since 1.0
 */
class Yii extends YiiBase
{
}

Yii::createWebApplication

这个方法实际上是在YiiBase父类中定义的,所以,Yii为我们预留了扩展的可能。我们只需要在yii.php中添加我们想要扩展的方法即可,在项目中直接使用 Yii::方法名() 调用。
为了将项目代码和核心目录完全分离,我个人觉得在项目目录下使用另外一个yii.php来替代从核心目录中包含yii.php更加好。

这里我用了更加极端的方法,我直接将yii这个类定义在了入口文件,并扩展了一个全局工厂函数 instance()方法,请看代码:

<?php
// change the following paths if necessary
$yii=dirname(__FILE__).'/../yii/framework/YiiBase.php';
$config=dirname(__FILE__).'/protected/config/main.php';
// remove the following lines when in production mode
defined('YII_DEBUG') or define('YII_DEBUG',true);
// specify how many levels of call stack should be shown in each log message
defined('YII_TRACE_LEVEL') or define('YII_TRACE_LEVEL',3);
require_once($yii);
//扩展基类
class Yii extends YiiBase{
  /**
   * 全局扩展方法:工厂函数
   * @param type $alias 类库别名
   */
  static function instance($alias){
    static $_class_ = array();
    $key = md5($alias);
    if(!isset($_class_[$key])){
      $_class_[$key] = self::createComponent($alias);
    }
    return $_class_[$key];
  }
}
Yii::createWebApplication($config)->run();

这个类是在最后一行Yii::createWebApplication()之前定义的,以保证Yii类能正常使用(不要把这个类放在文件末尾,会出错。)

在项目中任何地方,使用$obj = Yii::instance($alias);去实例化一个类,并且是单例模式。

YiiBase中的两个比较重要的方法 (import,autoload)
然后看看YiiBase中的import方法就知道这些静态变量是干嘛用的了:

/* Yii::import()
* $alias: 要导入的类名或路径
* $forceInclude false:只导入不include类文件,true则导入并include类文件
*/
 public static function import($alias, $forceInclude = false){  
 //Yii把所有的依赖放入到这个全局的$_imports数组中,名字不能重复
 //如果当前依赖已经被引入过了,那么直接返回
 if (isset(self::$_imports[$alias])) {    
    return self::$_imports[$alias];  
  }  
 //class_exists和interface_exists方法的第二个参数的值为false表示不autoload 
 if (class_exists($alias, false) || interface_exists($alias, false)) {    
   return self::$_imports[$alias] = $alias;  
 }  
 //如果传进来的是一个php5.3版本的命名空间格式的类(例如:\a\b\c.php)
 if (($pos = strrpos($alias, '\\')) !== false) {    
  //$namespace = a.b
  $namespace = str_replace('\\', '.', ltrim(substr($alias, 0, $pos), '\\')); 
  //判断a.b这个路径是否存在,或者a.b只是alias里面的一个键,调用该方法返回这个键对应的值,比如'email' => realpath(__DIR__ . '/../vendor/cornernote/yii-email-module/email')
  if (($path = self::getPathOfAlias($namespace)) !== false) {   
    $classFile = $path . DIRECTORY_SEPARATOR . substr($alias, $pos + 1) . '.php';       
    if ($forceInclude) {        
     if (is_file($classFile)) {          
       require($classFile);        
      } else {          
      throw new CException(Yii::t('yii', 'Alias "{alias}" is invalid. Make sure it points to an existing PHP file and the file is readable.', array('{alias}' => $alias)));        
     }        
     self::$_imports[$alias] = $alias;      
     } else {        
     self::$classMap[$alias] = $classFile;      
    }      
    return $alias;    
  } else {      
// try to autoload the class with an autoloader      
  if (class_exists($alias, true)) {        
    return self::$_imports[$alias] = $alias;      
  } else {        
    throw new CException(Yii::t('yii', 'Alias "{alias}" is invalid. Make sure it points to an existing directory or file.',          array('{alias}' => $namespace)));      
  }    
  }  
 }  
if (($pos = strrpos($alias, '.')) === false) // a simple class name 
 {    
  // try to autoload the class with an autoloader if $forceInclude is true    
  if ($forceInclude && (Yii::autoload($alias, true) || class_exists($alias, true))) {      
   self::$_imports[$alias] = $alias;    
   }    
  return $alias;  
 }  
 $className = (string)substr($alias, $pos + 1);  

 $isClass = $className !== '*';  
 if ($isClass && (class_exists($className, false) || interface_exists($className, false))) {    
  return self::$_imports[$alias] = $className;  
 }  
 if (($path = self::getPathOfAlias($alias)) !== false) {    
   if ($isClass) {      
      if ($forceInclude) {        
         if (is_file($path . '.php')) {          
             require($path . '.php');        
         } else {          
             throw new CException(Yii::t('yii', 'Alias "{alias}" is invalid. Make sure it points to an existing PHP file and the file is readable.', array('{alias}' => $alias)));        
             }        
        self::$_imports[$alias] = $className;      
     } else {        
        self::$classMap[$className] = $path . '.php';      
     }      
      return $className;    
    } 
    // $alias是'system.web.*'这样的已*结尾的路径,将路径加到include_path中
    else // a directory    
     {      
       if (self::$_includePaths === null) {    
          self::$_includePaths = array_unique(explode(PATH_SEPARATOR, get_include_path()));  
           if (($pos = array_search('.', self::$_includePaths, true)) !== false) {          
        unset(self::$_includePaths[$pos]);        
      }      
    }      
    array_unshift(self::$_includePaths, $path);      
    if (self::$enableIncludePath && set_include_path('.' . PATH_SEPARATOR . implode(PATH_SEPARATOR, self::$_includePaths)) === false) {        
     self::$enableIncludePath = false;      
     }      
     return self::$_imports[$alias] = $path;    
    }  
  } else {    
    throw new CException(Yii::t('yii', 'Alias "{alias}" is invalid. Make sure it points to an existing directory or file.',      array('{alias}' => $alias)));  
    }
 }

是的,上面这个方法最后就把要加载的东西都放到$_imports,$_includePaths中去了。这就是Yii的import方法,好的,接下来我们看看autoload方法:

public static function autoload($className, $classMapOnly = false){  // use include so that the error PHP file may appear  
if (isset(self::$classMap[$className])) {       
  include(self::$classMap[$className]);  
} elseif (isset(self::$_coreClasses[$className])) {    
  include(YII_PATH . self::$_coreClasses[$className]);  
} elseif ($classMapOnly) {    
  return false;  
} else {    
 // include class file relying on include_path    
    if (strpos($className, '\\') === false) 
    // class without namespace    
    {      
      if (self::$enableIncludePath === false) {        
         foreach (self::$_includePaths as $path) {              
            $classFile = $path . DIRECTORY_SEPARATOR . $className . '.php';          
            if (is_file($classFile)) {       
               include($classFile);            
              if (YII_DEBUG && basename(realpath($classFile)) !== $className . '.php') {              
                throw new CException(Yii::t('yii', 'Class name "{class}" does not match class file "{file}".', array(                '{class}' => $className,                '{file}' => $classFile,              )));            
              }            
              break;          
           }        
       }      
   } else {        
      include($className . '.php');      
       }    
 } else // class name with namespace in PHP 5.3    
   {      
     $namespace = str_replace('\\', '.', ltrim($className, '\\'));    
     if (($path = self::getPathOfAlias($namespace)) !== false) {  
      include($path . '.php');      
     } else {        
      return false;      
     }    
   }

   return class_exists($className, false) || interface_exists($className, false);    }    return true;}
config文件中的 import 项里的类或路径在脚本启动中会被自动导入。用户应用里个别类需要引入的类可以在类定义前加入 Yii::import() 语句。

PHP 相关文章推荐
PHP 5.0对象模型深度探索之绑定
Sep 05 PHP
PHP常用代码
Nov 23 PHP
PHPMyadmin 配置文件详解(配置)
Dec 03 PHP
PHP strtotime函数详解
Dec 18 PHP
PHP ? EasyUI DataGrid 资料取的方式介绍
Nov 07 PHP
PHP网页游戏学习之Xnova(ogame)源码解读(四)
Jun 23 PHP
本地计算机无法启动Apache故障处理
Aug 08 PHP
php微信公众号开发(3)php实现简单微信文本通讯
Dec 15 PHP
关于Laravel Route重定向的一个注意点
Jan 16 PHP
动态表单验证的操作方法和TP框架里面的ajax表单验证
Jul 19 PHP
laravel5.4生成验证码的实例讲解
Aug 05 PHP
PHP用函数嵌入网站访问量计数器
Oct 27 PHP
Symfony控制层深入详解
Mar 17 #PHP
详解PHP的Yii框架的运行机制及其路由功能
Mar 17 #PHP
深入解析PHP的Yii框架中的event事件机制
Mar 17 #PHP
全面解读PHP的Yii框架中的日志功能
Mar 17 #PHP
Symfony核心类概述
Mar 17 #PHP
使用symfony命令创建项目的方法
Mar 17 #PHP
Symfony实现行为和模板中取得request参数的方法
Mar 17 #PHP
You might like
基于PHP生成简单的验证码
2016/06/01 PHP
Laravel统一错误处理为JSON的方法介绍
2020/10/18 PHP
JavaScript DOM 学习第三章 内容表格
2010/02/19 Javascript
flexigrid 类似ext grid的JS表格代码
2010/07/17 Javascript
javascript 伪数组实现方法
2010/10/11 Javascript
JavaScript 放大镜 移动镜片效果代码
2011/05/09 Javascript
angularJS 入门基础
2015/02/09 Javascript
JavaScript实现模仿桌面窗口的方法
2015/07/18 Javascript
JQuery实现网页右侧随动广告特效
2016/01/17 Javascript
解决layui-table单元格设置为百分比在ie8下不能自适应的问题
2019/09/28 Javascript
js刷新页面location.reload()用法详解
2019/12/09 Javascript
vscode 配置vue+vetur+eslint+prettier自动格式化功能
2020/03/23 Javascript
vue中element 的upload组件发送请求给后端操作
2020/09/07 Javascript
搭建Python的Django框架环境并建立和运行第一个App的教程
2016/07/02 Python
Python 实现数据库(SQL)更新脚本的生成方法
2017/07/09 Python
Windows系统下多版本pip的共存问题详解
2017/10/10 Python
pandas.DataFrame删除/选取含有特定数值的行或列实例
2018/11/07 Python
python 实现数字字符串左侧补零的方法
2018/12/04 Python
python同时替换多个字符串方法示例
2019/09/17 Python
python next()和iter()函数原理解析
2020/02/07 Python
pandas DataFrame运算的实现
2020/06/14 Python
Python性能测试工具Locust安装及使用
2020/12/01 Python
美国Rue La La闪购网站:奢侈品、中高档品牌限时折扣
2016/10/19 全球购物
经济学博士求职自荐信范文
2013/11/23 职场文书
工商管理毕业生推荐信
2013/12/24 职场文书
时尚休闲吧创业计划书
2014/01/25 职场文书
运动员口号
2014/06/09 职场文书
小学教师先进事迹材料
2014/12/15 职场文书
2016年校园重阳节广播稿
2015/12/18 职场文书
《开国大典》教学反思
2016/02/16 职场文书
励志语录:只有自己足够强大,才能不被别人践踏
2020/01/09 职场文书
Python的flask接收前台的ajax的post数据和get数据的方法
2021/04/12 Python
原生JS封装vue Tab切换效果
2021/04/28 Vue.js
canvas实现贪食蛇的实践
2022/02/15 Javascript
python画条形图的具体代码
2022/04/20 Python
Spring JPA 增加字段执行异常问题及解决
2022/06/10 Java/Android