thinkPHP 框架 引导类Think.class.php 分析(一)

thinkPHP框架中的引导类(核心类)Think.class.php是一个非常重要的类。该类主要包含如下属性和方法:


该类主要在公告入口文件ThinkPHP.php中的最后一行被引用。

// 加载核心Think类
require CORE_PATH.'Think'.EXT;
// 应用初始化 
Think\Think::start();
所以我们从strat方法开始分析。

static public function start() {
  // 注册AUTOLOAD方法
  spl_autoload_register('Think\Think::autoload');      
  // 设定错误和异常处理
  register_shutdown_function('Think\Think::fatalError');
  set_error_handler('Think\Think::appError');
  set_exception_handler('Think\Think::appException');
  // 初始化文件存储方式
  Storage::connect(STORAGE_TYPE);
  $runtimefile  = RUNTIME_PATH.APP_MODE.'~runtime.php';
  if(!APP_DEBUG && Storage::has($runtimefile)){
      Storage::load($runtimefile);
  }else{
      if(Storage::has($runtimefile))
          Storage::unlink($runtimefile);
      $content =  '';
      // 读取应用模式
      $mode   =   include is_file(CONF_PATH.'core.php')?CONF_PATH.'core.php':MODE_PATH.APP_MODE.'.php';
      // 加载核心文件
      foreach ($mode['core'] as $file){
          if(is_file($file)) {
            include $file;
            if(!APP_DEBUG) $content   .= compile($file);
          }
      }
      // 加载应用模式配置文件
      foreach ($mode['config'] as $key=>$file){
          is_numeric($key)?C(load_config($file)):C($key,load_config($file));
      }
      // 读取当前应用模式对应的配置文件
      if('common' != APP_MODE && is_file(CONF_PATH.'config_'.APP_MODE.CONF_EXT))
          C(load_config(CONF_PATH.'config_'.APP_MODE.CONF_EXT));
      // 加载模式别名定义
      if(isset($mode['alias'])){
          self::addMap(is_array($mode['alias'])?$mode['alias']:include $mode['alias']);
      }
      // 加载应用别名定义文件
      if(is_file(CONF_PATH.'alias.php'))
          self::addMap(include CONF_PATH.'alias.php');
      // 加载模式行为定义
      if(isset($mode['tags'])) {
          Hook::import(is_array($mode['tags'])?$mode['tags']:include $mode['tags']);
      }
      // 加载应用行为定义
      if(is_file(CONF_PATH.'tags.php'))
          // 允许应用增加开发模式配置定义
          Hook::import(include CONF_PATH.'tags.php');
      // 加载框架底层语言包
      L(include THINK_PATH.'Lang/'.strtolower(C('DEFAULT_LANG')).'.php');
      if(!APP_DEBUG){
          $content  .=  "\nnamespace { Think\\Think::addMap(".var_export(self::$_map,true).");";
          $content  .=  "\nL(".var_export(L(),true).");\nC(".var_export(C(),true).');Think\Hook::import('.var_export(Hook::get(),true).');}';
          Storage::put($runtimefile,strip_whitespace('<?php '.$content));
      }else{
        // 调试模式加载系统默认的配置文件
        C(include THINK_PATH.'Conf/debug.php');
        // 读取应用调试配置文件
        if(is_file(CONF_PATH.'debug'.CONF_EXT))
            C(include CONF_PATH.'debug'.CONF_EXT);           
      }
  }
  // 读取当前应用状态对应的配置文件
  if(APP_STATUS && is_file(CONF_PATH.APP_STATUS.CONF_EXT))
      C(include CONF_PATH.APP_STATUS.CONF_EXT);   

  // 设置系统时区
  date_default_timezone_set(C('DEFAULT_TIMEZONE'));

  // 检查应用目录结构 如果不存在则自动创建
  if(C('CHECK_APP_DIR')) {
      $module     =   defined('BIND_MODULE') ? BIND_MODULE : C('DEFAULT_MODULE');
      if(!is_dir(APP_PATH.$module) || !is_dir(LOG_PATH)){
          // 检测应用目录结构
          Build::checkDir($module);
      }
  }

  // 记录加载文件时间
  G('loadTime');
  // 运行应用
  App::run();
}

spl_autoload_register 

将函数注册到SPL __autoload函数队列中。如果该队列中的函数尚未激活,则激活它们。

如果在你的程序中已经实现了__autoload()函数,它必须显式注册到__autoload()队列中。因为 spl_autoload_register()函数会将Zend Engine中的__autoload()函数取代为spl_autoload()spl_autoload_call()

如果需要多条 autoload 函数,spl_autoload_register() 满足了此类需求。 它实际上创建了 autoload 函数的队列,按定义时的顺序逐个执行。相比之下, __autoload() 只可以定义一次。

所以我们只需要看autoload()函数。下面register_shutdown_function和set_error_handler、set_exception_handler 都只需要看里里面的函数即可。autoload函数实现了类库的自动加载,下面我详细的分析下autoload函数。

public static function autoload($class)
{
    // 检查是否存在映射
    //首先在加载未知的类时,根据类名检测在静态变量$_map中是否存在这样的类,存在的话,就不用再次加载了
    if (isset(self::$_map[$class])) {
        include self::$_map[$class];

        //判断在实例化类时是否存在反斜杠,不存在的话,直接。。。。。
    } elseif (false !== strpos($class, '\\')) {
        //strstr()函数 详解(因为本人在这个函数上浪费过时间,故而提醒广大朋友)
        // $str="dsdfsd/mfg";
        //strstr("/",$str);找到 / 在字符串第一次出现的位置,并返回剩余的部分。结果为  /mfg
        //strstr("/",$str,true);找到 / 在字符串第一次出现的位置,并返回之前的部分  dsdfsd。
        //所以这个true还是很关键的。
        $name = strstr($class, '\\', true);
        //如果返回的$name 在以下array('Think', 'Org', 'Behavior', 'Com', 'Vendor')中或者在ThinkPHP/Library 中会自动定位
        // 再结合下面的代码 可以判断
        //        new  Think\Page() (前提对应目录下存在这样的类库)
        //        new  Vendor\Page()
        //  像这样形式的实例化应该可以加载类库,但是在thinkphp中还是报错。 new  \Think\Page()  这样才会正常
        // 当时我看到这段代码感觉  new  Think\Page() 符合要求啊,于是我百思不得其姐。最后将问题定位到命名空间请看
        //下面的命名空间讲解。我看完就明白了。
        //最后我得出结论:autoload($class) 中参数$class 是结合命名空间生成的
        //new  Think\Page() 这样实例化的话,生成的$class 是带上命名空间的 如 Home\Controller\Think\Page
        if (in_array($name, array('Think', 'Org', 'Behavior', 'Com', 'Vendor')) || is_dir(LIB_PATH . $name)) {
            // Library目录下面的命名空间自动定位
            $path = LIB_PATH;
        } else {
            // 检测自定义命名空间 否则就以模块为命名空间
            $namespace = C('AUTOLOAD_NAMESPACE');
            $path = isset($namespace[$name]) ? dirname($namespace[$name]) . '/' : APP_PATH;
        }
        $filename = $path . str_replace('\\', '/', $class) . EXT;
        if (is_file($filename)) {
            // Win环境下面严格区分大小写
            if (IS_WIN && false === strpos(str_replace('/', '\\', realpath($filename)), $class . EXT)) {
                return;
            }
            include $filename;
        }
        //关闭命名空间,可以自行探索
    } elseif (!C('APP_USE_NAMESPACE')) {
        // 自动加载的类库层
        foreach (explode(',', C('APP_AUTOLOAD_LAYER')) as $layer) {
            if (substr($class, -strlen($layer)) == $layer) {
                if (require_cache(MODULE_PATH . $layer . '/' . $class . EXT)) {
                    return;
                }
            }
        }
        // 根据自动加载路径设置进行尝试搜索
        foreach (explode(',', C('APP_AUTOLOAD_PATH')) as $path) {
            if (import($path . '.' . $class))
                // 如果加载类成功则返回
                return;
        }
    }
}

这里使用了私有静态变量$_map,只能在类的内部访问,而不能在类的外部访问。静态成员只保留一个变量值,而这个变量值对所有的实例都是有效,也就是说,所有的实例共享这个成员。 这个变量中存放着已经加载过的类的名称。当然thinkphp初始化的时候,会自动加载一些类。至于如何自动加载,暂时留一个疑问?我们接着讲解autoload函数。

命名空间讲解:


时间有限,先写这些。





  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值