ThinkPHP5的惰性加载

ThinkPHP5的惰性加载

定义:惰性加载,一个类只有在使用的时候才include(require)进来。

优点:减少内存占用,提高系统整体速度。

在TP3.2.3的时候,核心的文件是统一加载的。

在Think.class.php【路径:ThinkPHP\Library\Think\Think.class.php】的start方法中可以看到:

// 读取应用模式
$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);
    }
}

所以一般情况下,他是读取ThinkPHP/Mode目录下的common.php这个文件,该文件返回一个数组,其中便包含有core这个成员。

/**
 * ThinkPHP 普通模式定义
 */
return array(
    // 配置文件
    ‘config’    =>  array(),
    // 别名定义
    ‘alias’     =>  array(),
    // 函数和类文件
    ‘core’      =>  array(
        THINK_PATH.‘Common/functions.php’,
        COMMON_PATH.‘Common/function.php’,
        CORE_PATH . ‘Hook’.EXT,
        CORE_PATH . ‘App’.EXT,
        CORE_PATH . ‘Dispatcher’.EXT,
        //CORE_PATH . ‘Log’.EXT,
        CORE_PATH . ‘Route’.EXT,
        CORE_PATH . ‘Controller’.EXT,
        CORE_PATH . ‘View’.EXT,
        BEHAVIOR_PATH . ‘BuildLiteBehavior’.EXT,
        BEHAVIOR_PATH . ‘ParseTemplateBehavior’.EXT,
        BEHAVIOR_PATH . ‘ContentReplaceBehavior’.EXT,
    ),
    // 行为扩展定义
    ‘tags’  =>  array(),
);

但是在TP5.0,包括这些核心文件都使用了懒惰加载,也就是使用到了才加载进来。主要策略是:

1、自动加载类先行
2、核心文件配置在一个文件中

加载类先行:由于核心文件也使用了懒惰加载,因此在框架运行起来之前,自动加载方法必须依据被注册好。因此可以看到在TP5中,自动加载方法单处成一个loader.php类。并且在base.php【路径:ThinkPHP目录下】中可以看到,loader.php是第一个被加载进来的类方法。

// 环境常量
define(‘IS_CLI’, PHP_SAPI == ‘cli’ ? true : false);
define(‘IS_WIN’, strpos(PHP_OS, ‘WIN’) !== false);
// 载入Loader类
require CORE_PATH . ‘Loader.php’;
// 加载环境变量配置文件
if (is_file(ROOT_PATH . ‘.env’)) {
    $env = parse_ini_file(ROOT_PATH . ‘.env’, true);
    foreach ($env as $key => $val) {
        $name = ENV_PREFIX . strtoupper($key);
        if (is_array($val)) {
            foreach ($val as $k => $v) {
                $item = $name . ‘_’ . strtoupper($k);
                putenv($item=$v);
            }
        } else {
            putenv($name=$val);
        }
    }
}
// 注册自动加载
\think\Loader::register();
// 注册错误和异常处理机制
\think\Error::register();
// 加载惯例配置文件
\think\Config::set(include THINK_PATH . ‘convention’ . EXT);

核心文件配置:同TP3.2.3一样,TP5的核心文件也配置在一个文件中,不过现在不是通过应用模式了,而是直接定义在classmap.php中,该文件同样会返回一个包含核心文件的数组。

// 注册自动加载机制
public static function register($autoload = )
{
    // 注册系统自动加载
    spl_autoload_register($autoload ?: ‘think\\Loader::autoload’, true, true);
    // 注册命名空间定义
    self::addNamespace([
        ‘think’    => LIB_PATH . ‘think’ . DS,
        ‘behavior’ => LIB_PATH . ‘behavior’ . DS,
        ‘traits’   => LIB_PATH . ‘traits’ . DS,
    ]);
    // 加载类库映射文件
    if (is_file(RUNTIME_PATH . ‘classmap’ . EXT)) {
        self::addClassMap(__include_file(RUNTIME_PATH . ‘classmap’ . EXT));
    }
    // Composer自动加载支持
    if (is_dir(VENDOR_PATH . ‘composer’)) {
        self::registerComposerLoader();
    }
    // 自动加载extend目录
    self::$fallbackDirsPsr4[] = rtrim(EXTEND_PATH, DS);
}

addClassMap方法会把classmap.php返回的数组合并到self:$map中,方便autoload方法的查询使用。
当有一个类文件还没有包含进来的时候,Loader:autoload方法就会被调用:

// 自动加载
public static function autoload($class)
{
    // 检测命名空间别名
    if (!empty(self::$namespaceAlias)) {
        $namespace = dirname($class);
        if (isset(self::$namespaceAlias[$namespace])) {
            $original = self::$namespaceAlias[$namespace] . ‘\\’ . basename($class);
            if (class_exists($original)) {
                return class_alias($original, $class, false);
            }
        }
    }
    if ($file = self::findFile($class)) {
        // Win环境严格区分大小写
        if (IS_WIN && pathinfo($file, PATHINFO_FILENAME) != pathinfo(realpath($file), PATHINFO_FILENAME)) {
            return false;
        }
        __include_file($file);
        return true;
    }
}

综上,TP5.0使用了懒惰加载,虽然单单在这一点上,系统的性能提升不明显(TP3.x性能实际上已经胜过其他框架),因为核心文件不管在TP3.2.3还是TP5中,大多数情况都需要全部包含进来的,晚包含和早包含都得包含的。但是胜在什么地方呢?

1、遵循规范(PSR-4):限制了自由度,换来了规范化和工程化。对于底层架构,遵守规范还是比较好的。比如如果两个不同框架使用了不同的规范,那么我为他开发第三方库的时候,可能就需要读取两种不同的规范。但是如果他们都使用同一种规范的话,那么我了解这一种规范后,同样也可以用于另外一个框架,这就方便多了。对于规范,我觉得用到才查吧~~~

2、代码更加简洁:核心文件代码不需要额外代码实现,直接让自动加载方法加载便可。

 

来源:http://blog.csdn.net/cde7070/article/details/51757036

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据