解读 thinkphp5 源码(一):自动加载

   2016-09-08 0
核心提示:听说 TP5 已经 RC4 了,曾经在 RC3 的时候用它写过一个小东西。官方说从 RC4 以后改动不是太大。索性读一下它的源码。然后顺便记录一下,如有错漏,请路过大神多多指正!入口作为单入口框架,就从入口文件看起,按照tp5文档所示的规范,入口文件应该是放在pub

听说 TP5 已经 RC4 了,曾经在 RC3 的时候用它写过一个小东西。官方说从 RC4 以后改动不是太大。索性读一下它的源码。然后顺便记录一下,如有错漏,请路过大神多多指正!

入口

作为单入口框架,就从入口文件看起,按照tp5文档所示的规范,入口文件应该是放在public/ 下。

那么为什么大多数要把入口放到子文件夹下呢? 这是一个小技巧。

第一为了 动静分离 ,因为现在的php框架一般都是单入口,既然是单入口,那么必然要做rewrite,如果把静态文件和程序文件放到一起。框架路由势必要对每一个请求进行筛选。所以这些框架不约而同的把资源文件和程序文件区分开来,放在了不同的文件夹下。从整体来看,也就是为什么入口会在子目录下了。

第二是为了 安全 ,linux下的权限划分非常严格,分别分为读、写、执行,在这个基础上又分为文件所有组、所在组、其他组。这样划分可以更好的对文件权限进行梳理,避免上传漏洞(用户上传php文件被执行)等等。

打开public/index.php

define('APP_PATH', __DIR__ . '/../application/');
// 加载框架引导文件
require __DIR__ . '/../thinkphp/start.php';

只有两行代码,定义 APP_PATH ,加载 '/../thinkphp/start.php' 。APP_PATH 可以自己修改。

然后打开 /../thinkphp/start.php

namespace think;
// ThinkPHP 引导文件
// 加载基础文件
require __DIR__ . '/base.php';
// 执行应用
App::run()->send();

也只有三行代码,定义命名空间,加载基础文件,启动应用。这里注意一下命名空间,所有thinkphp类都在think及其子命名空间下。程序中用到框架类的时候要先use 该类的命名空间;

环境配置

然后我们打开 base.php
12-31行定义了一坨常量。注意里面 defined('THINK_PATH') or define('THINK_PATH', __DIR__ . DS); 这种定义方式,先判断时候存在,如果不存在则定义。也就是说我们可以在这行代码之前(一般在index.php中)执行定义这个常量,而不会被覆盖。

36-37行

// 载入Loader类
require CORE_PATH . 'Loader.php';

载入Loader类,这个类比较重要,实现了自动加载。

39-51行

// 加载环境变量配置文件
if (is_file(ROOT_PATH . 'env' . EXT)) {
    $env = include ROOT_PATH . 'env' . EXT;
    foreach ($env as $key => $val) {
        $name = ENV_PREFIX . strtoupper($key);
        if (is_bool($val)) {
            $val = $val ? 1 : 0;
        } elseif (!is_scalar($val)) {
            continue;
        }
        putenv("$name=$val");
    }
}

加载环境变量配置文件,可能很多同学不理解是干什么用的。

我们假设一个场景,你在公司和家里开发程序,在内网服务器上进行测试,在外网服务器上部署,所有的配置不能可能全部相同(比如数据库帐号密码、文件路径等等)。总不能每次都改配置吧?如果做负载、有几十个服务器怎么部署?总不能都用ftp上传,然后改配置吧?

所以现在主流的做法就是区分环境( 开发环境、测试环境、生产环境 ),然后程序自动加载不同的配置。但是通过什么区分呢?方法有很多,但是大多数都是选择通过环境变量来区分,然后加载对应的配置文件。然后使用 git 做版本控制,然后在服务器部署同步脚本,通过 git push钩子进行代码同步,以达到自动化部署的模式。当然也还有其他方式,但是大多都类似。

自动加载

为什么要使用自动加载呢?因为像java、C等编译型语言在编译过程中会把程序中引用的库、包等等自动引入进来。但是php是脚本行语言啊,没有编译过程,怎么办呢?最早期的程序都是手动引入,比如早期的xxshop、xxcms,都是写一坨require、include。又搓又不方便,对于世界上最好的语言来说这样多丢面啊,所以我们需要用自动加载让我们最好的语言看起来更有B格(至于某些性能论的同学会说自动加载影响性能啊之类的,请用汇编!)。

我们继续看base.php 的 54行 \think\Loader::register();
注册自动加载,从这一行之后就可以使用符合自动加载规范的任何类了。

比如56-60行,虽然没有加载对应的文件,但是通过自动加载就可以直接使用。

// 注册错误和异常处理机制
\think\Error::register();
// 加载惯例配置文件
\think\Config::set(include THINK_PATH . 'convention' . EXT);

接下来我们看一下自动加载的实现方法。打开 Loader.php ,按照上面的执行顺序,先看Loader类的register方法

核心是

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));
}

spl_autoload_register方法可能很多同学都有了解,在我们实例化一个当前已加载文件中不存在的类后(比如在a.php中new一个类,会先在a.php和已加载的文件中找),会执行此方法指定的函数,并把类名传递进去。在这个函数中如果能正确加载到该文件,那么也可以实例化成功,并不会报错。所以借助此函数可以达到自动加载。

首先我们知道当 new 一个不存在的类时,如果使用 spl_autoload_register 定义了一个处理函数,那么这个函数可以获得一个参数,参数名是new 的类名。比如从前面base.php中我们看到 \think\Error::register(); 使用\think命名空间下的Error类的register静态方法,但是我们并没有引入这个文件。于是我们可以在 spl_autoload_register 注册的函数中得到一个参数think\Error,如果我们的命名空间按照文件夹格式的方法命名(这也是推荐的、常用的命名方式),那么就可以通过该参数来加载对应的文件,但是如果特殊情况下没有按照文件夹的格式来进行命名空间的命名,那么就需要手动指定映射关系。 self::addClassMap(__include_file(RUNTIME_PATH . 'classmap' . EXT)); 加载了映射文件。然后我们看 spl_autoload_register 中指定的函数:autoload。

这个不用详细解释了,先处理由 addNamespace 设定的命名空间别名,然后通过 findFile 来处理映射关系,得到真实的路径,并加载文件。

__autoload() 函数具有类似的功能。但是为什么用的很少呢?因为 __autoload() 只能指定一个函数,而 spl_autoload_register 可以注册多个函数来处理这个逻辑。一旦业务复杂 __autoload() 就完全不能胜任。比如我们继续看Loader类的register方法下面的内容

// Composer自动加载支持
        if (is_dir(VENDOR_PATH . 'composer')) {
            self::registerComposerLoader();
        }
        // 自动加载extend目录
        self::$fallbackDirsPsr4[] = rtrim(EXTEND_PATH, DS);

一个框架是否好用,很大程度取决于它的扩展能力。所以自动加载除了要处理自身类库的加载、还要处理扩展类库的自动加载。tp5支持使用两种方式来扩展类库一种是Composer,一种是手动放入 extend 目录。

Composer不用多说,就像npm之于nodejs、yum之于Centos、apt-get之于、Ubuntu。一个php的包管理工具。Composer有一套自己的自动加载机制,tp5这里只不过是调用了Composer自己的注册自动加载函数的方法。有兴趣的同学可以看一下 registerComposerLoader 方法,以及 vendor/composer 下几个autoload开头的文件。原理基本上和上面的一致。

Loader.php中核心方法已经介绍完毕,其他的几个方法有处理规范的方法(PSR-0,PSR-2,PSR-4,有兴趣的同学可以谷歌、百度了解一下)、和根据类名处理模型和控制器的方法,这点需要看完路由才能详解。

 
标签: ThinkPHP
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与乐学笔记(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

  • nginx 各类网站设置 (laravel , thinkphp , nod
    基础部分设置[root@centos ~]# vim /opt/nginx/conf/nginx.confuser www www;worker_processes auto;pid logs/nginx.pid;worker_rlimit_nofile 100000;events {use epoll;multi_accept on;worker_connections 65535 ;}http {include mime.types;default_type
    02-09
  • thinkphp5 IIS7.5 隐藏index.php的方法
    ?xml version="1.0" encoding="UTF-8"? configurationsystem.webServerrewriterulesrule name="WPurls" enabled="true" stopProcessing="true"match url=".*" /conditions logicalGrouping="MatchAll"
    02-09
  • ThinkPHP 利用.htaccess文件的 Rewrite 规则隐
    通常的URL里面含有index.php,为了达到更好的SEO效果可能需要去掉URL里面的index.php ,通过URL重写的方式可以达到这种效果,通常需要服务器开启URL_REWRITE模块才能支持。 下面是Apache的配置过程,可以参考下:1、httpd.conf配置文件中加载了mod_rewrite.so
    02-09
  • 【小程序+thinkphp5】 用户登陆,返回第三方session3rd
    【小程序+thinkphp5】 用户登陆,返回第三方ses
    服务器环境: centos7   php7.0准备工作: 注册小程序,并获取 appid 、appsecret下载微信解密算法sdk : https://mp.weixin.qq.com/debug/wxadoc/dev/api/signature.htmlhttps 的域名。需要在小程序后台服务器域名那配置   代码实现 一 、 thinkphp5 
    02-09
  • 码云推荐 | 基于 ThinkPHP5 的通用后台 lyadmin_v2
    码云推荐 | 基于 ThinkPHP5 的通用后台 lyadmin
    lyadmin_v2 项目介绍 lyamdin是一套轻量级通用后台,采用Bootstrap3制作,自带权限管理,模块化开发。lyadmin_v2是基于ThinkPHP5全新开发的新版本。真正原创的Builder页面生生成器完美支持2.0并且支持多达38中表单类型的支持,包括但不限于文本、富文本、图片
  • 在 thinkphp 中使用 laravel 的全部组件
    作为一个使用 php 作为主力语言的公司,不管怎么说,在一些老的项目中,总会碰到使用 thinkphp 的。那么,热爱 laravel 的你,当你去开发新的 feature 时,大胆的去引入 laravel 的组件吧。不管是对于现在的开发效率,还是日后项目的重构,迁移都是有很大帮助
  • ThinkPHP V5.0.5 版本发布 — 祝大家新春快乐!
    ThinkPHP V5.0.5 版本发布 — 祝大家新春快乐!
    ThinkPHP V5.0.5 版本发布,祝大家新春快乐,事业有成,“鸡”祥如意^_^官方快速入门系列教程 新增了控制器从入门到精通 V5.0.5版本是年前最后一个发布版本,也是5.0系列版本的最后一个功能版本,主要改进和优化了数据库和模型部分,并修正了之前版本的一些问
  • 基于thinkphp的音乐网站源码
    基于thinkphp的音乐网站源码
    KSmusic音乐网站源码是一个以php+MySQL进行开发的免费音乐网站源码,只需进行简单的设置,即可拥有属于自己的音乐网站。 更新日志:标签增加 分页功能 大大增加数据自由性专辑 count 标签 用于读取数据总数量新增上一个,下一个标签 ,新增 网盘下载设置项新
  • 在线工单售后客户服务管理系统(thinkphp内核)
    在线工单售后客户服务管理系统(thinkphp内核)
    THINKPHP内核的工单系统,非常适合于售后客户服务,二开后对接到网站系统是非常不错的哦,可以添加客户和售后人员,支持短信和邮件提醒,只需要在后台配置好就行了,还是非常简单的。1、系统管理1.1:客户管理:可实现对职员的管理,可添加职员,并对不同角色
    01-06 ThinkPHP
  • thinkphp 模板解析的流程
    thinkphp 模板解析的流程
    ThinkPHP控制器中在每一个方法的最后都有这样的一句话 ,你确定对这句话非常了解吗?$this-display();当然你会说这句话是用来解析或显示控制器的方法所对应的模板的。有了这句,模板里的内容才可以正常显示,没有这句话就会抛出错误:模板不存在。但是这句话是
    12-23 ThinkPHP
点击排行