flink 入门程序-wordcount flink 配置项介绍 在 Mac 上搭建 Flink 的开发环境 lambda 架构问题的阅读笔记 IDEA常用插件 Mybatis源码分析(1) - Mybatis关键类 Mybatis源码分析(1) - Mybatis包目录简介 tair 1:tair学习 dataflow论文阅读笔记 Polysh的安装使用 SnappyData排序函数比较 Squirrel-sql客户端连接SnappyData手册 在虚拟机里显示Hello World spark学习博客推荐 SnappyData学习博客和官网文章 Docker常用命令 MyBatis支持的OGNL语法 mysql性能优化 mysql性能优化-优化Sql语句 java各版本新特性 mac上命令行操作 explain输出格式 从文件中读取zk配置——ZooKeeper编程技能(1) git进阶经验-从项目中删除移除的目录 Mongodb 学习之shell命令操作(3) mysql命令 git进阶经验-从多模块项目中分理子模块 从零学hadoop-搭建基础(单点)的Hdfs环境 ZooKeeper集群操作脚本 Vue安装使用 2 初学JVM之问答式记住类加载机制 2 初学JVM之问答式记住虚拟机性能监控与故障处理工具 2 初学JVM之问答式记住垃圾收集器 log4j2 按天生成日志文件 1 初学JVM之问答式记住java自动内存管理 MapReduce学习心得之MapReduce初识 log4j2 日志发送到kafka配置实战 log4j2 日志配置实战 Mongodb 学习之shell命令操作(二) Mongodb 学习之linux版本安装(一) Dubbo的初级使用 ServiceLoader内部实现分析 ServiceLoader 初级应用 log4j日志发送邮件配置实战 红黑树笔记 IDEA首次使用之前的配置 java源码学习之Enum java源码学习之String 自定义Spring tag标签 编写一键发布脚本 记一次Spring Scheduler莫名不执行的一次堆栈分析 kafka的基本操作 nginx 5:Nginx内部变量 nginx 4:Nginx日志管理 提高hadoop配置效率的shell脚本 Hive编程指南之一 Hive的安装 Ambari服务器安装 Ambari服务器管理集群 HBase分布式安装 windows下Eclipse远程调试运行MR程序 基于MapReduce新的API的编程Demo-wordCount window下Eclipse远程只读HDFS上的文件 YARN上节点标签 编写第一个MapReduce的wordcount程序 NodeManager的重启 搭建JStorm集群 YARN上的web应用代理 YARN上的ResourceManager的高可用方案 配置vmware中的虚拟机使用宿主机的共享网络 YARN架构简述 HDFS 架构 Spring的统一异常处理机制 Tomcat 配置服务 HDFS的viewfs指南 HDFS的Federation之路 HDFS基于QJM的HA之路 nginx 3:Nginx反向代理 mybatis操作主体流程 1.正则表达式学习-基础篇 log4j日志配置详解 mysql的时间函数 nginx 2:Nginx模块配置理论及实战 HashMap相关解析和测试文章 工作一年后的面试 用私有构造器或枚举类型强化Singleton属性 java中比较重要的图 mybatis处理枚举类 mybatis集成进spring Spring比较重要的几个截图 21.hadoop-2.7.2官网文档翻译-使用NFS的HDFS高可用性 20.hadoop-2.7.2官网文档翻译-使用仲裁日志管理器的HDFS高可用性 markdown在jekyll中支持的一些操作 Spring项目中配置sl4j和log4j的日志配置 19.hadoop-2.7.2官网文档翻译-HDFS命令指南 Spring的profile机制介绍 mybatis-generator反向生成 18.hadoop-2.7.2官网文档翻译-HDFS用户指南 17.hadoop-2.7.2官网文档翻译-实现Hadoop中Dapper-like追踪 16.hadoop-2.7.2官网文档翻译-Hadoop的KMS(key 管理服务器)-文档集 15.hadoop-2.7.2官网文档翻译-Hadoop的http web认证 14.hadoop-2.7.2官网文档翻译-服务级别的授权指南 13.hadoop-2.7.2官网文档翻译-安全模式中的Hadoop 09.hadoop-2.7.2官网文档翻译-Hadoop命令行微型集群 12.hadoop-2.7.2官网文档翻译-机架感知 11.hadoop-2.7.2官网文档翻译-代理用户-超级用户对其他用户的代表 10.hadoop-2.7.2官网文档翻译-原生库指南 08.hadoop-2.7.2官网文档翻译-文件系统规范 07.hadoop-2.7.2官网文档翻译-Hadoop接口类别 (转)浅析 Decorator 模式,兼谈 CDI Decorator 注解 06.hadoop-2.7.2官网文档翻译-Hadoop的兼容性 05.hadoop-2.7.2官网文档翻译-文件系统命令 04.hadoop-2.7.2官网文档翻译-Hadoop命令指南 03.hadoop-2.7.2官网文档翻译-集群安装 02.hadoop-2.7.2官网文档翻译-单节点集群安装 01.hadoop-2.7.2官网文档翻译-概述 Http 协议相应状态码大全及常用状态码 IDEA快捷键 JDBC Type与Java Type redis 12:redis 操作集合 mybatis-generator错误集合 redis 11:redis 错误集合 nginx 1:nginx的安装 redis 10:redis cluster命令操作 redis 9:redis实例集群安装 java设计模式 hadoop集群学习笔记(1) Apache Shiro 简介 vim编辑神器的进阶命令 Eclipse配置 Eclipse快捷键 Linux 测试题 Linux脚本学习(1) Linux启动简要过程 Centos7上安装Mysql hadoop集群学习笔记(1) (转)分布式发布订阅消息系统 Kafka 架构设计 maven 命令 Kafka集群安装 Kafka初步使用 redis 8:redis server 和 scripting命令操作 redis 7:redis transaction 和 connection命令操作 redis 6:redis hash 命令操作 redis 5:redis sorted_set 命令操作 搭建本地Jekyll+Markdown+Github的开发环境 Spring源码阅读笔记(2) redis 4:redis set命令操作 Spring添加任务调度配置 redis 3:Redis list命令操作 redis 2:redis 一般命令操作 redis 1:redis单机安装笔记 redis 0:redis配置属性描述 Spring源码阅读笔记(1) spark 错误集锦 spark集群安装 Linux 基本命令操作 Hadoop错误信息处理 Hadoop代码拾忆 从零开始搭建spring-springmvc-mybatis-mysql和dubbo项目 java知识点札记 java排错 Google Java Style 中文版 git进阶经验 github使用经验 MongoDB用户角色授权与AUTH启用 MongoDB 命令 MongoDB 特定规范 Spring MVC实现跳转的几种方式 史上最全最强SpringMVC详细示例实战教程 Spring 零星笔记 js中(function(){…})()立即执行函数写法理解 如何解决跨域问题 创建ajax简单过程 前端定位 设置MYSQL允许通过IP访问 mybatis异常 :元素内容必须由格式正确的字符数据或标记组成 如何为 WordPress 绑定多个域名的方法s WordPress工作原理之程序文件执行顺序(传说中的架构源码分析) Spring源码导入Eclipse中 基于PHPnow搭建Eclipse开发环境 解决wordpress首页文章内容截断处理的几种方法 ZooKeeper理论知识 ZooKeeper集群安装配置 Git常用命令速查表 Linux 4:磁盘与文件系统管理 Linux 3:文件与目录管理 Linux 2:文件权限与目录配置 Markdown输入LaTeX数学公式
从零学hadoop-搭建基础(单点)的Hdfs环境 MapReduce学习心得之MapReduce初识 Ambari服务器安装 Ambari服务器管理集群 windows下Eclipse远程调试运行MR程序 基于MapReduce新的API的编程Demo-wordCount window下Eclipse远程只读HDFS上的文件 YARN上节点标签 编写第一个MapReduce的wordcount程序 NodeManager的重启 YARN上的web应用代理 YARN上的ResourceManager的高可用方案 YARN架构简述 HDFS 架构 HDFS的viewfs指南 HDFS的Federation之路 HDFS基于QJM的HA之路 21.hadoop-2.7.2官网文档翻译-使用NFS的HDFS高可用性 20.hadoop-2.7.2官网文档翻译-使用仲裁日志管理器的HDFS高可用性 19.hadoop-2.7.2官网文档翻译-HDFS命令指南 18.hadoop-2.7.2官网文档翻译-HDFS用户指南 17.hadoop-2.7.2官网文档翻译-实现Hadoop中Dapper-like追踪 16.hadoop-2.7.2官网文档翻译-Hadoop的KMS(key 管理服务器)-文档集 15.hadoop-2.7.2官网文档翻译-Hadoop的http web认证 14.hadoop-2.7.2官网文档翻译-服务级别的授权指南 13.hadoop-2.7.2官网文档翻译-安全模式中的Hadoop 09.hadoop-2.7.2官网文档翻译-Hadoop命令行微型集群 12.hadoop-2.7.2官网文档翻译-机架感知 11.hadoop-2.7.2官网文档翻译-代理用户-超级用户对其他用户的代表 10.hadoop-2.7.2官网文档翻译-原生库指南 08.hadoop-2.7.2官网文档翻译-文件系统规范 07.hadoop-2.7.2官网文档翻译-Hadoop接口类别 06.hadoop-2.7.2官网文档翻译-Hadoop的兼容性 05.hadoop-2.7.2官网文档翻译-文件系统命令 04.hadoop-2.7.2官网文档翻译-Hadoop命令指南 03.hadoop-2.7.2官网文档翻译-集群安装 02.hadoop-2.7.2官网文档翻译-单节点集群安装 01.hadoop-2.7.2官网文档翻译-概述 hadoop集群学习笔记(1) hadoop集群学习笔记(1) Hadoop错误信息处理 Hadoop代码拾忆

WordPress工作原理之程序文件执行顺序(传说中的架构源码分析)

2015年11月19日
摘要:

在了解WordPress挂载机制时,一直有一个疑惑,到底是WordPress的内核源文件先执行还是主题文件里functions.php文件先执行。为了解决这个问题,想了解WordPress的工作原理,它是如何生成网页的,各程序文件的执行顺序是什么,于是有了这篇文章。

WordPress所有的前端页面生成都要经过根目录下的index.php文件(不是主题根目录),这是通过Web服务器的rewrite规则实现的。然后通过index.php文件一步步引导WordPress环境启动,再分析请求URL返回相应数据所组成的前台页面。以下将一步步分析源码文件,以此来了解WordPress整体框架及工作原理。

第一步:加载index.php文件

该文件有效源码如下:

//定义是否加载主题文件,true为加载;
define('WP_USE_THEMES',true);
//加载wp-blog-header.php文件,该文件用于启动WordPress环境及模板;
require('./wp-blog-header.php');

第二步:加载wp-blog-header.php文件

该文件有效源码如下:

if ( !isset($wp_did_header) ) {
        //判断$wp_did_header变量是否已经设置,如果未设置则执行代码块;	
        //见解析1;
        $wp_did_header = true;
        //见解析2;	
    	require_once( dirname(__FILE__) . '/wp-load.php' );
        //见解析3;	
        wp();
    	//见解析4;
    	require_once( ABSPATH . WPINC . '/template-loader.php' );
}
  • 解析1:对$wp_did_header进行赋值,这样如果代码块已经执行过,判断就会失败,代码块就不会再执行。这种做法可以确保wp-blog-header.php文件只执行一次(重复执行的话会出现函数名冲突、变量重置等,WordPress会精神分裂的!);

  • 解析2:加载WP根目录下wp-load.php文件,执行初始化工作,如初始化常量、环境、加载类库和核心代码等完成WordPress环境启动工作,如加载wp-includes目录下functions.php(函数库)、class-wp.php(类库)、plugin.php(插件)、pomo目录(语言包)、query.php(数据请求)、theme.php(加载主题文件)、post-template.php(文章模板)、comment.php(评论模板)、rewrite.php(URL重写)等等。

  • 解析3:执行wp()函数,执行内容处理工作,如根据用户的请求调用相关函数获取和处理数据,为前端展示准备数据;

  • 解析4:加载根目录绝对路径下wp-includes目录中template-loader.php文件,执行主题应用工作,如根据用户的请求加载主题模板。

WordPress之所以能将用户请求的页面生成出来,都是最后这三行核心代码起的作用。wp-load.php会完成页面生成所需要的所有环境、变量、API等,相当于做了好准备工作;wp()函数根据用户请求的URL从数据库中取出相应的数据内容备用;template-loader.php把已经准备好的内容用主题所设定的样式展现方式给拼接出来。这三项工作完成,就可以将用户请求的页面展现出来了。我们姑且将这三项工作也认定为三个大步骤,以下将重点分析。

第三步:加载wp-load.php文件(初始化)

该文件初始化常量(如:定义绝对路径、设定功能文件及内容文件路径等)并加载wp-config.php文件(本处不分析wp-config.php文件不存在的情况),部分核心代码如下:

//定义常量ABSPATH为根目录绝对地址
define( 'ABSPATH', dirname(__FILE__) . '/' );
//加载根目录下wp-config.php文件
require_once( ABSPATH . 'wp-config.php' );

从代码看出,本文件的主要作用就是加载wp-config.php文件,故我们可以抽象的将之看作是wp-load.php初始化时的第一个小步骤,具体如下:

一、加载wp-config.php文件

该文件主要用于配置MySQL数据库通信信息、设定数据库表名前缀、设定密钥、设置语言及文件绝对路径等,部分核心代码如下(为省事就直接在代码后加#然后解释含义了):

//定义数据库名db_name;
define('DB_NAME', 'db_name');
//定义数据库用户名db_username;
define('DB_USER', 'db_username');
//定义数据库密码db_password;
define('DB_PASSWORD', 'db_password');
//定义数据库主机地址,如localhost或其他IP;
define('DB_HOST', 'db_host_location');
//定义数据表默认文字编码,如utf8;
define('DB_CHARSET', 'utf8');
//定义数据库表前缀,一般默认为wp_;
$table_prefix = 'wp_';
//定义WordPress语言,中文默认zh_CH,使用的汉化语言文件为/wp-content/languages目录下的zh_CH.mo文件,该文件为二进制,查看具体中文可见zh_CH.po文件;
define('WPLANG', 'zh_CN');
//设置开发环境DEBUG,默认为false不开启;
define('WP_DEBUG', false);
//加载根目录下wp-settings.php文件;
require_once(ABSPATH . 'wp-settings.php');

代码中定义的数据库常量主要用于数据请求时通信数据库,本文件还有个主要作用就是加载了wp-settings.php文件,而该文件相当于启动WordPress环境的总指挥,下面我们就将该文件作为初始化的第二步来分析。

二、加载wp-settings.php文件

该文件主要用于创建和定义常见变量、函数和类的库来为WordPress运行做准备,也就是说WordPress运行过程中使用的大多数变量、函数和类等核心代码都是在这个文件中定义的。这个文件相当于一个总控制器,很多常量定义、函数定义等都是在其他文件中完成,而该文件的作用就是执行那些文件或执行在那些文件中已经定义好的函数。

该文件源码分析内容较多,详见“WordPress核心文件wp-setting.php源码分析”。

第四步: 执行wp()函数(内容处理)

在这一阶段,调用wp()函数对数据库内容进行查询,并将查询的内容赋值给一些全局变量,方便在模板中使用模板标签获取相应的数据并展示在前端。该函数源码如下:

function wp( $query_vars = '' ) {    
	global $wp, $wp_query, $wp_the_query;
	# 对变量$wp,$wp_query,$wp_the_query进行全局化;	$wp->main( $query_vars );
	# 见解析1;	if ( !isset($wp_the_query) )
		$wp_the_query = $wp_query;
	# 见解析2;
} - 解析1:调用$wp->main(),即调用对象$wp的main()方法,该对象是class-wp.php文件中WP类实例化得到的,该类主要用于启动WordPress环境,main()方法源码分析详见“WordPress核心类WP内main()方法源码分析”;
  • 解析2:判断$wp_the_query是否设置,若未设置将其赋值为$wp_query,该对象是query.php文件中WP_Query类实例化得到的,该类作用强大,几乎WP所需要的所有数据信息都是由该类得到的,所以内容的准备工作基本都是这段代码来完成的,该类的具体分析见“”;

至此,WP根据请求准备相应数据的工作也已经完成,下面就需要加载模板并把这些数据展现到前台去了。

第五步:加载template-loader.php文件(主题应用)

该文件根据用户URL返回加载相应模板,其源码如下:

 if ( defined('WP_USE_THEMES') && WP_USE_THEMES )    
	do_action('template_redirect');//如果常量WP_USE_THEMES存在且值为真,则触发挂载点(动作钩子)template_redirect;if ( is_robots() ) :
	do_action('do_robots');
	return;elseif ( is_feed() ) :
	do_feed();
	return;elseif ( is_trackback() ) :
	include( ABSPATH . 'wp-trackback.php' );
	return;endif;//判断函数is_robots(), is_feed() 和 is_trackback()的返回结果,处理 feeds 和 trackbacks,即使没有使用任何主题;if ( defined('WP_USE_THEMES') && WP_USE_THEMES ) :
	$template = false;
	if   ( is_404()            && $template = get_404_template()    ) :
	elseif ( is_search()         && $template = get_search_template()    ) :
	elseif ( is_tax()            && $template = get_taxonomy_template()  ) :
	elseif ( is_front_page()     && $template = get_front_page_template()    ) :
	elseif ( is_home()           && $template = get_home_template()    ) :
	elseif ( is_attachment()     && $template = get_attachment_template()    ) :
		remove_filter('the_content', 'prepend_attachment');
	elseif ( is_single()         && $template = get_single_template()    ) :
	elseif ( is_page()           && $template = get_page_template()    ) :
	elseif ( is_category()       && $template = get_category_template()    ) :
	elseif ( is_tag()            && $template = get_tag_template()    ) :
	elseif ( is_author()         && $template = get_author_template()    ) :
	elseif ( is_date()           && $template = get_date_template()    ) :
	elseif ( is_archive()        && $template = get_archive_template()    ) :
	elseif ( is_comments_popup() && $template = get_comments_popup_template() ) :
	elseif ( is_paged()          && $template = get_paged_template()    ) :
	else :
		$template = get_index_template();
	endif;
	    //见解析1;	
	if ( $template = apply_filters( 'template_include', $template ) )
	    include( $template );
	  return;
    endif;
	 //若template_include过滤钩子上有挂载函数,则对$template进行应用,最终将内容呈现给用户;
解析1:如果常量WP_USE_THEMES存在且值为真,则判断页面类型同时给$template变量赋相应值;其中,判断页面类型的函数如is_404()位于wp-includes目录下query.php文件,该函数返回对象$wp_query中is_404()方法,若is_404()为false则继续往下判断是否是其他页面;若为true则给$template赋值为get_404_template(),该函数位于wp-includes目录下template.php文件,它返回get_query_template('404'),而该函数将页面类型传入数组$templates并应用调用函数locate_template($templates)且应用过滤器;locate_template()函数根据传入数组在主题中查找到相应的文件然后交给load_template()函数然后使用require加载,最终将用户需要的页面呈现出来;

该文引自网络http://www.ecdoer.com/post/wordpress-source-analysis.html