WordPress架构简单剖析
前言
最近在搭建自己的博客站點(diǎn)時(shí), 選擇了網(wǎng)站使用較多的WordPress, 隨著慢慢的使用, 它靈活的插件和主題令我折服. 基本上任何想要實(shí)現(xiàn)的功能, 都可以在上面通過插件的形式進(jìn)行添加. 無論是在訪問前的緩存、訪問后的統(tǒng)計(jì)、訪問中的過濾、各種流程的修改等等, 幾乎都能夠以插件的形式進(jìn)行修改. 我覺得這太酷了, 如果在我平常業(yè)務(wù)上能夠?qū)⒓軜?gòu)寫成這樣, 還有什么需求變化能難倒我?
基于這個(gè)原因, 我對(duì)WordPress進(jìn)行了簡單的分析, 這就是開源的好處嘛. 我從index.php文件一步步跟蹤了整個(gè)請(qǐng)求的開始到結(jié)束. 因?yàn)槟芰τ邢? 這可能是最笨的辦法了.
解析
執(zhí)行流程
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'; }而這, 已經(jīng)將WordPress的執(zhí)行流程體現(xiàn)出來了.
1.防止重復(fù)加載
! isset( $wp_did_header ) 判斷, 是為了防止文件被重復(fù)加載的, 直接跳過
2.加載 庫/主題/插件
第二步引入了wp-load.php文件, 然后又引入了wp-config.php文件, 再然后又引入了wp-settings.php文件, 實(shí)際的加載過程, 就在wp-settings.php文件中. 此文件做了下面幾件事
到這里, 還沒有針對(duì)當(dāng)前頁面數(shù)據(jù)的查詢, 僅完成了初始化過程.
3.查詢頁面數(shù)據(jù)
wp()函數(shù)是執(zhí)行頁面數(shù)據(jù)加載的方法, 會(huì)根據(jù)當(dāng)前頁面, 到數(shù)據(jù)庫中查詢需要顯示的數(shù)據(jù), 將需要展示的數(shù)據(jù)準(zhǔn)備好.
4.頁面展示
最終引入的template-loader.php文件, 其作用是將數(shù)據(jù)進(jìn)行可視化展示.
5.完成
至此, 整個(gè)頁面的展示流程就走完了. 按照這個(gè)步驟看下來, 整個(gè)流程還是比較清晰的.
但是還是沒有回答最開始的問題啊, 它靈活在哪里呢? 上面只是簡單描述了一下整體的加載流程, 但具體細(xì)節(jié)還沒有提到.
頁面展示
WordPress加載頁面的地方, 就是最后的template-loader.php這個(gè)文件了.
其根據(jù)當(dāng)前頁面, 加載不同的文件進(jìn)行展示. 至于頁面為什么這么靈活, 隨便找個(gè)頁面看一下就知道了. index.php:
拼圖式生成頁面. 可針對(duì)每一個(gè)位置進(jìn)行定制, 并將其進(jìn)行組裝. 所以每個(gè)主題都有很高的靈活性, 可以自己設(shè)置頁面, 也可以選擇丟棄某些內(nèi)容而不展示.
另外, HTML在加載頁面的時(shí)候, 會(huì)對(duì)幾個(gè)模板進(jìn)行查找, 如在訪問: 計(jì)算機(jī)是如何進(jìn)行時(shí)間同步的 這篇文章的時(shí)候, get_single_template 方法會(huì)依次查找下面幾個(gè)文件:
- single-post-計(jì)算機(jī)是如何進(jìn)行時(shí)間同步的.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
若某個(gè)文件存在, 就會(huì)直接加載. 有沒有悟到什么. 這玩意不就可以做緩存嘛. 但是, 不好意思, 在執(zhí)行這步操作之前, 該查詢的數(shù)據(jù)就已經(jīng)查過了, 所以這個(gè)緩存加了等于沒加, 沒什么卵用.
鉤子函數(shù)
如果WordPress只是能夠拼圖式組裝頁面, 那還不夠靈活, 因?yàn)橹荒軐?duì)頁面進(jìn)行操作, 而無法影響執(zhí)行流程. 對(duì)執(zhí)行流程的影響, 就是它的各種鉤子函數(shù)了. WordPress的鉤子函數(shù)通過do_action和apply_filters兩個(gè)方法進(jìn)行調(diào)用,
看過方法add_action發(fā)現(xiàn), 它就是簡單的調(diào)用了add_filter方法. 也就是說這兩個(gè)方法內(nèi)部是同一個(gè)方法. 個(gè)人理解, do_action注重與流程的插入, 既向主流程中加入一段邏輯, 沒有返回值. 而 apply_filters方法有返回值, 更注重對(duì)數(shù)據(jù)的處理吧.
在WordPress中, 隨處可見各種鉤子的調(diào)用, 初始化的時(shí)候、加載插件、插件加載完成、加載主題等等等等.
舉個(gè)例子, 有一個(gè)緩存插件, 就是通過在添加init鉤子函數(shù), 將頁面內(nèi)容 echo之后, 直接執(zhí)行die函數(shù), 以達(dá)到快速返回的效果.
不過在查看源碼的過程中, 有一個(gè)問題, 所有鉤子函數(shù)的調(diào)用, 都是直接使用字符串調(diào)用的, 如 do_action('init'). 這種通用的變量, 不應(yīng)該寫個(gè)常量列表的么?
不過好在官方維護(hù)了一份鉤子函數(shù)的列表, 列出了所有的鉤子, 同時(shí)進(jìn)行了說明并指出調(diào)用的具體地址. 需要的時(shí)候可以看一下. 我數(shù)了一下, 目前一共1470個(gè)鉤子. https://developer.wordpress.org/reference/hooks/
可以說, WordPress就是通過各種鉤子以及拼圖式頁面, 分別實(shí)現(xiàn)展示和流程的個(gè)性化定制. 而這個(gè)鉤子函數(shù)倒也不是什么新鮮玩意, 接口的監(jiān)聽器、各種beforeAction afterAction等等, 在平常開發(fā)過程中也經(jīng)常用到. 只是沒有用到這么極致罷.
其他細(xì)節(jié)
配置加載
WordPress的配置是存儲(chǔ)在MySQL中的, 而請(qǐng)求加載配置文件的方式是執(zhí)行sql查詢:
SELECT option_name, option_value FROM $wpdb->options WHERE autoload = 'yes'
直接將表中的所有配置, 一次性讀出來, 而且, 取出來的數(shù)據(jù)還不少嘞, 給你個(gè)直觀感受, 我將結(jié)果保存到txt文件, 文件大小1.4mb.
如果說這個(gè)查詢可以增加緩存, 或者通過配置文件引入的話, 能夠省去一些消耗. 但是, 如果想通過插件的方式修改配置讀取, 不好意思, 這個(gè)不可以. 因?yàn)?配置的首次讀取是在調(diào)用wp_not_installed()函數(shù)時(shí), 而此時(shí)插件還沒加載呢. 如果想修改的話, 貌似只能修改源碼了,
在加載配置的時(shí)候, 在請(qǐng)求緩存中先讀了一次:
故可以預(yù)先將配置放到請(qǐng)求緩存中. 在調(diào)用方法wp_start_object_cache()加載緩存之后, 立刻調(diào)用了wp_cache_add( 'alloptions', $alloptions, 'options' );方法, 可以將全局配置預(yù)先放到緩存中, 實(shí)驗(yàn)了一下, 確實(shí)可行. 如果追求性能極致的話, 可以考慮.
配置存儲(chǔ)
看到數(shù)據(jù)庫配置表wp_options中啟用插件的值時(shí), 我完全摸不到頭腦, 存儲(chǔ)的內(nèi)容是這樣的:
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";}這這這, 這是啥? 看不懂, 但又好像能看懂. 于是我追蹤了這個(gè)值的解析, 就是下面這個(gè)函數(shù):
解析后的數(shù)據(jù)是:
{"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" }是不是一下就懂了? 存儲(chǔ)的是通過serialize函數(shù)進(jìn)行對(duì)象序列化之后的值, 于是, 弱弱的問一下, 直接存json字符串不好么?
全局變量定義
在WordPress中到處都充斥著各種全局變量. 我在查看緩存文件的時(shí)候, 看到了這段代碼:
但奇怪的是, 我全局搜索變量$wp_object_cache, 卻沒有找到定義的地方. 最終我一點(diǎn)一點(diǎn)找到了它定義的地方.
而這種功能風(fēng)格到處都是, 如果想找到一個(gè)變量都有哪些地方使用了, 很不好找. 而且, 直接引用全局變量的方式, 也導(dǎo)致變量之后很難修改. 在源碼中就看到了這么一個(gè)活生生的例子:
這種風(fēng)格導(dǎo)致一個(gè)后果, 一個(gè)變量一旦定義, 就摘不掉了.
數(shù)據(jù)庫查詢記錄
在查看數(shù)據(jù)庫查詢的時(shí)候, 看到了這樣的代碼:
也就是說, 如果定義了SAVEQUERIES常量, 且為true, 那么就會(huì)將查詢的sql記錄下來. 在log_query方法中, 記錄到了queries變量中.
這個(gè)操作對(duì)于數(shù)據(jù)庫的調(diào)優(yōu)還是比較方便的. 在配置文件中定義常量, 在最終拿到所有的sql及執(zhí)行時(shí)間
總結(jié)
對(duì)于這種充斥著全局變量和鉤子函數(shù)的內(nèi)容, 閱讀起來有一丟丟的疲憊, 經(jīng)常看著看著就看丟了. 不過還是發(fā)現(xiàn)了很多有意思的地方.
本來是想看看它為什么這么靈活, 結(jié)果發(fā)現(xiàn)其實(shí)在平常的開發(fā)過程中已經(jīng)用到了, 不過WordPress對(duì)一些內(nèi)容的處理還是給了我一些啟發(fā).
比如這種拼圖式的頁面組成, 可以將頁面的展示和數(shù)據(jù)處理分離. 而在開發(fā)接口的時(shí)候, 是不是也可以借鑒類似的思路. 這種方式有一個(gè)問題, 就是即使頁面沒有用到的數(shù)據(jù), 在查詢的時(shí)候也都查詢出來了, 對(duì)于接口這種追求性能的情況, 肯定是不能忍受的. 或者可以將需要使用的數(shù)據(jù)讓展示方給出配置? 不過這樣的話, 耦合度又高了, 靈活度也下降了, 難搞.
不過最重要的是, 這破玩意就是我現(xiàn)在在用的呀, 不好好了解一下怎么行. 以后如果有定制化需求, 咱也不至于無從下手了.
總結(jié)
以上是生活随笔為你收集整理的WordPress架构简单剖析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java lambda max_在Jav
- 下一篇: kotlin将对象转换为map_将网站转