WordPress架构简单剖析

前言

最近在搭建自己的博客站点时, 选择了网站使用较多的WordPress, 随着慢慢的使用, 它灵活的插件和主题令我折服. 基本上任何想要实现的功能, 都可以在上面通过插件的形式进行添加. 无论是在访问前的缓存、访问后的统计、访问中的过滤、各种流程的修改等等, 几乎都能够以插件的形式进行修改. 我觉得这太酷了, 如果在我平常业务上能够将架构写成这样, 还有什么需求变化能难倒我?

基于这个原因, 我对WordPress进行了简单的分析, 这就是开源的好处嘛. 我从index.php文件一步步跟踪了整个请求的开始到结束. 因为能力有限, 这可能是最笨的办法了.

解析

执行流程

index.php文件很简单, 就一句:

require __DIR__ . '/wp-blog-header.php';

wp-blog-header.php文件呢, 也很简单:

if ( ! isset( $wp_did_header ) ) {$wp_did_header = true;require_once __DIR__ . '/wp-load.php';wp();require_once ABSPATH . WPINC . '/template-loader.php';
}

而这, 已经将WordPress的执行流程体现出来了.

1.防止重复加载

! isset( $wp_did_header ) 判断, 是为了防止文件被重复加载的, 直接跳过

2.加载 库/主题/插件

第二步引入了wp-load.php文件, 然后又引入了wp-config.php文件, 再然后又引入了wp-settings.php文件, 实际的加载过程, 就在wp-settings.php文件中. 此文件做了下面几件事

  1. 引入初始化文件
  2. 常量定义
  3. 引入库
  4. 加载插件
  5. 加载主题

到这里, 还没有针对当前页面数据的查询, 仅完成了初始化过程.

3.查询页面数据

wp()函数是执行页面数据加载的方法, 会根据当前页面, 到数据库中查询需要显示的数据, 将需要展示的数据准备好.

4.页面展示

最终引入的template-loader.php文件, 其作用是将数据进行可视化展示.

5.完成

至此, 整个页面的展示流程就走完了. 按照这个步骤看下来, 整个流程还是比较清晰的.

但是还是没有回答最开始的问题啊, 它灵活在哪里呢? 上面只是简单描述了一下整体的加载流程, 但具体细节还没有提到.

页面展示

WordPress加载页面的地方, 就是最后的template-loader.php这个文件了.

image-20210806204234754

其根据当前页面, 加载不同的文件进行展示. 至于页面为什么这么灵活, 随便找个页面看一下就知道了. index.php:

20210807114551

拼图式生成页面. 可针对每一个位置进行定制, 并将其进行组装. 所以每个主题都有很高的灵活性, 可以自己设置页面, 也可以选择丢弃某些内容而不展示.

另外, HTML在加载页面的时候, 会对几个模板进行查找, 如在访问: 计算机是如何进行时间同步的 这篇文章的时候, get_single_template 方法会依次查找下面几个文件:

  • single-post-计算机是如何进行时间同步的.php
  • single-post-%e8%ae%a1%e7%ae%97%e6%9c%ba%e6%98%af%e5%a6%82%e4%bd%95%e8%bf%9b%e8%a1%8c%e6%97%b6%e9%97%b4%e5%90%8c%e6%ad%a5%e7%9a%84.php
  • single-post.php
  • single.php

若某个文件存在, 就会直接加载. 有没有悟到什么. 这玩意不就可以做缓存嘛. 但是, 不好意思, 在执行这步操作之前, 该查询的数据就已经查过了, 所以这个缓存加了等于没加, 没什么卵用.

钩子函数

如果WordPress只是能够拼图式组装页面, 那还不够灵活, 因为只能对页面进行操作, 而无法影响执行流程. 对执行流程的影响, 就是它的各种钩子函数了. WordPress的钩子函数通过do_actionapply_filters两个方法进行调用,

看过方法add_action发现, 它就是简单的调用了add_filter方法. 也就是说这两个方法内部是同一个方法. 个人理解, do_action注重与流程的插入, 既向主流程中加入一段逻辑, 没有返回值. 而 apply_filters方法有返回值, 更注重对数据的处理吧.

WordPress中, 随处可见各种钩子的调用, 初始化的时候、加载插件、插件加载完成、加载主题等等等等.

举个例子, 有一个缓存插件, 就是通过在添加init钩子函数, 将页面内容 echo之后, 直接执行die函数, 以达到快速返回的效果.

不过在查看源码的过程中, 有一个问题, 所有钩子函数的调用, 都是直接使用字符串调用的, 如 do_action('init'). 这种通用的变量, 不应该写个常量列表的么?

不过好在官方维护了一份钩子函数的列表, 列出了所有的钩子, 同时进行了说明并指出调用的具体地址. 需要的时候可以看一下. 我数了一下, 目前一共1470个钩子. https://developer.wordpress.org/reference/hooks/

可以说, WordPress就是通过各种钩子以及拼图式页面, 分别实现展示和流程的个性化定制. 而这个钩子函数倒也不是什么新鲜玩意, 接口的监听器、各种beforeAction afterAction等等, 在平常开发过程中也经常用到. 只是没有用到这么极致罢.

其他细节

配置加载

WordPress的配置是存储在MySQL中的, 而请求加载配置文件的方式是执行sql查询:

SELECT option_name, option_value FROM $wpdb->options WHERE autoload = 'yes'

直接将表中的所有配置, 一次性读出来, 而且, 取出来的数据还不少嘞, 给你个直观感受, 我将结果保存到txt文件, 文件大小1.4mb.

如果说这个查询可以增加缓存, 或者通过配置文件引入的话, 能够省去一些消耗. 但是, 如果想通过插件的方式修改配置读取, 不好意思, 这个不可以. 因为 配置的首次读取是在调用wp_not_installed()函数时, 而此时插件还没加载呢. 如果想修改的话, 貌似只能修改源码了,

在加载配置的时候, 在请求缓存中先读了一次:

image-20210807103715008

故可以预先将配置放到请求缓存中. 在调用方法wp_start_object_cache()加载缓存之后, 立刻调用了wp_cache_add( 'alloptions', $alloptions, 'options' );方法, 可以将全局配置预先放到缓存中, 实验了一下, 确实可行. 如果追求性能极致的话, 可以考虑.

配置存储

看到数据库配置表wp_options中启用插件的值时, 我完全摸不到头脑, 存储的内容是这样的:

a:7:{i:0;s:49:"easy-table-of-contents/easy-table-of-contents.php";i:1;s:47:"simple-yearly-archive/simple-yearly-archive.php";i:2;s:30:"wp-githuber-md/githuber-md.php";i:3;s:29:"wp-mail-smtp/wp_mail_smtp.php";i:5;s:27:"wp-super-cache/wp-cache.php";i:6;s:31:"wpdiscuz/class.WpdiscuzCore.php";i:7;s:32:"xml-sitemap-feed/xml-sitemap.php";}

这这这, 这是啥? 看不懂, 但又好像能看懂. 于是我追踪了这个值的解析, 就是下面这个函数:

image-20210806230134501

解析后的数据是:

{"0": "easy-table-of-contents/easy-table-of-contents.php","1": "simple-yearly-archive/simple-yearly-archive.php","2": "wp-githuber-md/githuber-md.php","3": "wp-mail-smtp/wp_mail_smtp.php","5": "wp-super-cache/wp-cache.php","6": "wpdiscuz/class.WpdiscuzCore.php","7": "xml-sitemap-feed/xml-sitemap.php"
}

是不是一下就懂了? 存储的是通过serialize函数进行对象序列化之后的值, 于是, 弱弱的问一下, 直接存json字符串不好么?

全局变量定义

WordPress中到处都充斥着各种全局变量. 我在查看缓存文件的时候, 看到了这段代码:

image-20210806230810146

但奇怪的是, 我全局搜索变量$wp_object_cache, 却没有找到定义的地方. 最终我一点一点找到了它定义的地方.

image-20210806230935842

而这种功能风格到处都是, 如果想找到一个变量都有哪些地方使用了, 很不好找. 而且, 直接引用全局变量的方式, 也导致变量之后很难修改. 在源码中就看到了这么一个活生生的例子:

image-20210806231146550

这种风格导致一个后果, 一个变量一旦定义, 就摘不掉了.

数据库查询记录

在查看数据库查询的时候, 看到了这样的代码:

image-20210807014422380

也就是说, 如果定义了SAVEQUERIES常量, 且为true, 那么就会将查询的sql记录下来. 在log_query方法中, 记录到了queries变量中.

这个操作对于数据库的调优还是比较方便的. 在配置文件中定义常量, 在最终拿到所有的sql及执行时间

总结

对于这种充斥着全局变量和钩子函数的内容, 阅读起来有一丢丢的疲惫, 经常看着看着就看丢了. 不过还是发现了很多有意思的地方.

本来是想看看它为什么这么灵活, 结果发现其实在平常的开发过程中已经用到了, 不过WordPress对一些内容的处理还是给了我一些启发.

比如这种拼图式的页面组成, 可以将页面的展示和数据处理分离. 而在开发接口的时候, 是不是也可以借鉴类似的思路. 这种方式有一个问题, 就是即使页面没有用到的数据, 在查询的时候也都查询出来了, 对于接口这种追求性能的情况, 肯定是不能忍受的. 或者可以将需要使用的数据让展示方给出配置? 不过这样的话, 耦合度又高了, 灵活度也下降了, 难搞.

不过最重要的是, 这破玩意就是我现在在用的呀, 不好好了解一下怎么行. 以后如果有定制化需求, 咱也不至于无从下手了.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/508374.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Gale-Shapley算法

前言 最近看了一档综艺《心动的信号》(唉, 单身久了, 开始喜欢看别人谈恋爱了) 节目中共有n男n女, 他们会在节目的最后进行表白, 如果我喜欢你, 恰好你也喜欢我, 那么便就会在一起, 自此传为一段佳话. 于是, 我就在想, 如何用算法来实现这个匹配的过程呢? 单一匹配 将信息…

阿里云定时任务并自动释放

前言 最近写了一个爬虫脚本, 脚本跑在一台北京的 ecs 上. 但奈何因某种未知力量, 需要连接代理才能访问目标网站. 本来想着自己搭代理, 但是太贵了, 就暂时搁置了. 直到我发现了这个: 阿里云香港的服务器, 一个小时才5分钱. 如果脚本直接跑在香港服务器上不就可以了咩, 按照这…

智能优化算法应用:基于金豺算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用:基于金豺算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用:基于金豺算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.金豺算法4.实验参数设定5.算法结果6.参考文献7.MA…

pixiv小控件

前言 最近看到一个大佬, 开源了一款博客小插件, 地址. 可以将pixiv网站的日榜放到博客侧边栏. 看上去很炫酷. 于是我也引入到了自己的博客中. 在此向大佬表示感谢. 但是在使用过程中, 经常遇到访问很慢的情况, 查看之后才发现, 大佬的服务器架设在韩国, 难怪访问比较慢, 都走…

PHP-PDO参数绑定问题

前言 今天在执行这样一段代码: $data [username > hujingnb,address > beijing, ]; $dbh new PDO("mysql:host{$host};dbname{$dbname}", $username, $password); $statement $dbh->prepare(INSERT INTO test_user (username, address) VALUES (:usern…

Python 的协程

前言 最近在看部分Python源码时, 发现了async 这个关键字. 查了一下发现了Python中的协程. 协程这玩意, 在GO中我用过啊, 简单说, 就是一个轻量级的线程嘛, 由语言自己来实现不同协程的调度. 想着Python中可能也是差不多的东西吧. 但是我Google搜了一下, 前面的说明都给出了下…

PHP脚本调用命令获取实时输出

在写脚本的时候, 经常会有需要调用其他命令. 而在调用一些耗时命令的时候, 我们是需要能够实时掌握脚本进度的. 一般来说, 脚本的进度通常是通过脚本的输出来获得. 如果是一个bash脚本, 那么直接调用命令 A就可以将执行权交出去, 然后命令 A的输出就可以实时显示出来了. 如果…

如何使用git管理crontab任务

前言 在Linux系统上执行定时任务, 使用crontab还是很方便的(有关crontab的使用可看crontab指令笔记). 只需要一行命令就完成了. 但是, 美中不足的是, crontab通过命令行管理任务, 无法通过代码库对任务进行管理. 若要更换机器, 所有任务都要重新增加一遍. 更糟的是若服务器突…

Golang 反射操作整理

前言 反射是什么? 我们平常也是经常用到, 而且这名词都用烂了, 这里就不再详细介绍了. 简单说, 就是有一个不知道是什么类型的变量, 通过反射可以获取其类型, 并可操作属性和方法. 反射的用途一般是用作生成工具方法, 比如你需要一个ToString方法, 要将变量转为字符串类型,…

Wordpress不同页面显示不同小工具

问题 想做一个在右侧显示的文章目录, 使用文章目录的插件 Easy Table of Contents, 将其添加到右侧的侧边栏中, 很轻松做到了这点. 但是, 一个新的问题出现了. 这个目录的工具, 需要在文章页面显示, 而在其他页面不显示. 那么问题来了, 如何让不同的页面显示不同的侧边栏工具…

虚拟内存分页机制的地址映射

概述 在之前的文章虚拟内存对分页机制做了简单的介绍. 还有一个疑问, 那就是如何将虚存中的逻辑地址映射为物理地址呢? 今天就来简单分析一下. 对于一个分页的地址来说, 一般包含两个元素: 页号: 第几页偏移量: 当前页的第几个字节 以下以 addr_virtual(p, o)表示一个逻辑…

虚拟内存分页机制的页面置换

前言 之前简单介绍过虚拟内存是如何与物理内存进行地址映射的: 虚拟内存分页机制的地址映射, 但是仅仅地址映射是不够的, 在地址映射说过会有缺页的情况, 此时就需要操作操作系统将缺少的页加载到内存中. 但是, 如果内存满了怎么办呢? 毕竟虚拟内存一般都要大于物理内存的, 不…

Kubernetes各个组件的概念

前言 Kubernetes中的概念太多了, 什么Pod Service Deployment 等等等等, 给刚接触的我都整蒙了. 通过几天观察下来, 说一下我对各个组件的理解. 此文章仅仅对这些概念做一个简单的介绍, 不至于后面看其他文章的时候一头雾水. Node Node很好理解. 就是服务实际运行的实例, 可…

Kubernetes中Pod生命周期

在 Kubernetes中Pod是容器管理的最小单位, 有着各种各样的Pod管理器. 那么一个Pod从启动到释放, 在这期间经历了哪些过程呢? Pod自开始创建, 到正常运行, 再到释放, 其时间跨度及经历的阶段大致如下: 说一下各个阶段的作用以及是为了解决什么问题. 容器调度和下载镜像的过程就…

Kubernetes存储卷的使用

在Kubernetes中, 有这不同方式的内容挂载, 简单记录一下他们的配置方式. ConfigMap 配置内容 内容配置 apiVersion: v1 kind: ConfigMap metadata:name: test-config data: # 添加配置的 key-value 内容test-key: test-value引入 apiVersion: v1 kind: Pod spec: containe…

响应HTTP服务的shell脚本

以下内容均为第一版, 实际使用请查看最新信息, 转至: https://hujingnb.com/archives/729 前言 兄弟萌, 我实现了一个实用的小工具, 特来分享. 事情刚开始是这样的, 我需要一个脚本来实现代码仓库web hook的任务, 首先想到的是直接调用php, 但是php-fpm是以www-data用户运行…

wait函数的作用

前言 在编写C程序的时候, 通过fork函数来创建新的进程, wait函数来等待子进程结束. 那么就有一个问题了, 什么情况下父进程需要等待子进程结束后继续执行呢? 如果需要等待子进程结束, 那直接将操作放到父进程执行不就醒了么? 反正等着也是等着. 当然, 还有有一种情况, 任务…

OAuth1.0介绍

背景 为什么需要OAuth授权呢? 最典型的应用场景就是第三方登录了, 我们开发了一个网站希望用户可以QQ登录, 但是怎么能拿到用户的 QQ 信息呢? 用户将 账号密码告诉我们当然可以, 但是这样有如下隐患: 我们拿到了用户的密码, 这样很不安全. 而且任意一个应用被黑, 所有相关…

PHP 数组的内部实现

前言 这几天在翻github的时候, 碰巧看到了php的源码, 就 down 下来随便翻了翻. 地址: https://github.com/php/php-src 那么PHP中什么玩意最引人注目嘞? 一定是数组了, PHP中的数组太强大了, 于是就想着不如进去看看数组的实现部分. 这篇文章打算全程针对代码进行解读了. 以…

go1.18新特性

前言 最近突然发现golang更新版本1.18了, 于是迫不及待的来看看这个版本加了些什么新特性. 没准就有之前困扰很久的问题, 在新版本被官方解决了呢. 先简单概述一下都有些什么变化, 后面再细说: 增加泛型的支持系统库方法增加修复 bug 另外, 像"系统内核更新"这种…