欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2024-04-01 21:45:04
通过yiic.php自动创建一个应用后,入口文件初始代码如下:

通过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() 语句。