欢迎来到源码交易网,为站长提供交易担保服务 访问移动版
站长交易首选担保平台!
酷客淘

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

日期: 2019-11-18 09:33:14 人气: -

通过yiic.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 

 

 

 

</qiang.xue@gmail.com> 

而:


Yii::createWebApplication


这个方法实际上是在YiiBase父类中定义的,所以,Yii为我们预留了扩展的可能。我们只需要在yii.php中添加我们想要扩展的方法即可,在项目中直接使用 Yii::方法名() 调用。


为了将项目代码和核心目录完全分离,我个人觉得在项目目录下使用另外一个yii.php来替代从核心目录中包含yii.php更加好。


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


// 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;     

//phpfensi.com 

    }   

 

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