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