天天看點

typecho流程原理和插件機制淺析(第一彈)typecho流程原理和插件機制淺析(第一彈)

typecho流程原理和插件機制淺析(第一彈)

兜兜

 393 2014年03月28日 釋出

  • 推薦 5 推薦
  • 收藏 24 收藏,3.5k 浏覽

雖然新版本0.9在多次跳票後終于釋出了,在漫長的等待裡始終有一批人不離不棄,其中不乏一些主題和插件開發者,還有一些忠實的粉絲,但是就是這樣一個blog系統還是由于缺乏相關文檔和主題插件使很多想要擺脫wp的使用者難以跨出最後一步,很多想要學習插件開發的人也因為對機制不了解找不到頭緒,今天就簡單介紹一下typecho的執行流程和插件機制,并配合一些簡單的例子來幫助那些找不到頭緒的人,大牛可以路過了!

簡要流程分析

Typecho是單入口程式,一切通路都通過index.php,是以還要從index.php的代碼開始。(以0.9正式版為例,代碼隻貼流程必須部分)

if (!@include_once 'config.inc.php') {
    file_exists('./install.php') ? header('Location: install.php') : print('Missing Config File');
    exit;
}

/** 初始化元件 */
Typecho_Widget::widget('Widget_Init');

/** 注冊一個初始化插件 */
Typecho_Plugin::factory('index.php')->begin();

/** 開始路由分發 */
Typecho_Router::dispatch();

/** 注冊一個結束插件 */
Typecho_Plugin::factory('index.php')->end();
           

整個index.php隻做了三件事

  • 加載config.inc.php(config.inc.php設定了相關目錄、包含路徑、加載系統基礎類庫、 程式初始化

    Typecho_Common::init();

    、最後設定資料庫連接配接參數,此處自行檢視)
  • 執行

    Typecho_Widget::widget('Widget_Init');

  • Typecho_Router::dispatch();

那麼程式初始化又做了些什麼呢?

function __autoLoad($className)
        {
            /**
             * 自動載入函數并不判斷此類的檔案是否存在, 我們認為當你顯式的調用它時, 你已經确認它存在了
             * 如果真的無法被加載, 那麼系統将出現一個嚴重錯誤(Fetal Error)
             * 如果你需要判斷一個類能否被加載, 請使用 Typecho_Common::isAvailableClass 方法
             */
            @include_once str_replace('_', '/', $className) . '.php';
        }
           

設定自動載入,将

Typecho_Widget

_

替換為

/

,并加上

.php

Typecho/Widget.php

,并

include_once 'Typecho/Widget.php';

Typecho_Widght

類的

Widget

靜态函數,參數為

Widget_Init

public static function widget($alias, $params = NULL, $request = NULL, $enableResponse = true)
    {
        list($className) = explode('@', $alias);

        if (!isset(self::$_widgetPool[$alias])) {
            $fileName = str_replace('_', '/', $className) . '.php';
            require_once $fileName;

            /** 如果類不存在 */
            if (!class_exists($className)) {
                /** Typecho_Exception */
                require_once 'Typecho/Widget/Exception.php';
                throw new Typecho_Widget_Exception($className);
            }

            /** 初始化request */
            if (!empty($request)) {
                $requestObject = new Typecho_Request();
                $requestObject->setParams($request);
            } else {
                $requestObject = Typecho_Request::getInstance();
            }

            /** 初始化response */
            $responseObject = $enableResponse ? Typecho_Response::getInstance()
            : Typecho_Widget_Helper_Empty::getInstance();

            /** 初始化元件 */
            $widget = new $className($requestObject, $responseObject, $params);

            $widget->execute();
            self::$_widgetPool[$alias] = $widget;
        }

        return self::$_widgetPool[$alias];
    }
           

同樣,将

Widget_Init

_

/

.php

Widget/Init.php

require_once 'Widget/Init.php';

并且執行

Widget_Init

execute

函數

<?php
/**
 * Typecho Blog Platform
 *
 * @copyright  Copyright (c) 2008 Typecho team (http://www.typecho.org)
 * @license    GNU General Public License 2.0
 * @version    $Id$
 */

/**
 * 初始化子產品
 *
 * @package Widget
 */
class Widget_Init extends Typecho_Widget
{
    /**
     * 入口函數,初始化路由器
     *
     * @access public
     * @return void
     */
    public function execute()
    {
        /** 對變量指派 */
        $options = $this->widget('Widget_Options'); 

        /** cookie初始化 */
        Typecho_Cookie::setPrefix($options->siteUrl);

        /** 初始化charset */
        Typecho_Common::$charset = $options->charset;

        /** 初始化exception */
        Typecho_Common::$exceptionHandle = 'Widget_ExceptionHandle';

        /** 設定路徑 */
        if (defined('__TYPECHO_PATHINFO_ENCODING__')) {
            $pathInfo = $this->request->getPathInfo(__TYPECHO_PATHINFO_ENCODING__, $options->charset);
        } else {
            $pathInfo = $this->request->getPathInfo();
        }

        Typecho_Router::setPathInfo($pathInfo);

        /** 初始化路由器 */
        Typecho_Router::setRoutes($options->routingTable);

        /** 初始化插件 */
        Typecho_Plugin::init($options->plugins);

        /** 初始化回執 */
        $this->response->setCharset($options->charset);
        $this->response->setContentType($options->contentType);

        /** 預設時區 */
        if (function_exists("ini_get") && !ini_get("date.timezone") && function_exists("date_default_timezone_set")) {
            @date_default_timezone_set('UTC');
        }

        /** 初始化時區 */
        Typecho_Date::setTimezoneOffset($options->timezone);

        /** 開始會話, 減小負載隻針對背景打開session支援 */
        if ($this->widget('Widget_User')->hasLogin()) {
            @session_start();
        }

        /** 監聽緩沖區 */
        ob_start();
    }
}
           

真正的初始化是在Typecho_Init,其中最重要的兩項任務就是

  • 擷取 pathinfo (比如通路文章

    http://localhost/archives/1/

    ,則 pathinfo 為

    /archives/1/

  • 從資料庫讀取系統路由表(

    option

    routingTable

    字段)

舉例系統安裝完成預設路由

[index] => Array
                (
                    [url] => /
                    [widget] => Widget_Archive
                    [action] => render
                    [regx] => |^[/]?$|
                    [format] => /
                    [params] => Array
                        (
                        )

                )

            [archive] => Array
                (
                    [url] => /blog/
                    [widget] => Widget_Archive
                    [action] => render
                    [regx] => |^/blog[/]?$|
                    [format] => /blog/
                    [params] => Array
                        (
                        )

                )

            [do] => Array
                (
                    [url] => /action/[action:alpha]
                    [widget] => Widget_Do
                    [action] => action
                    [regx] => |^/action/([_0-9a-zA-Z-]+)[/]?$|
                    [format] => /action/%s
                    [params] => Array
                        (
                            [0] => action
                        )

                )

            [post] => Array
                (
                    [url] => /archives/[cid:digital]/
                    [widget] => Widget_Archive
                    [action] => render
                    [regx] => |^/archives/([0-9]+)[/]?$|
                    [format] => /archives/%s/
                    [params] => Array
                        (
                            [0] => cid
                        )

                )

            [attachment] => Array
                (
                    [url] => /attachment/[cid:digital]/
                    [widget] => Widget_Archive
                    [action] => render
                    [regx] => |^/attachment/([0-9]+)[/]?$|
                    [format] => /attachment/%s/
                    [params] => Array
                        (
                            [0] => cid
                        )

                )

            [category] => Array
                (
                    [url] => /category/[slug]/
                    [widget] => Widget_Archive
                    [action] => render
                    [regx] => |^/category/([^/]+)[/]?$|
                    [format] => /category/%s/
                    [params] => Array
                        (
                            [0] => slug
                        )

                )

            [tag] => Array
                (
                    [url] => /tag/[slug]/
                    [widget] => Widget_Archive
                    [action] => render
                    [regx] => |^/tag/([^/]+)[/]?$|
                    [format] => /tag/%s/
                    [params] => Array
                        (
                            [0] => slug
                        )

                )

            [author] => Array
                (
                    [url] => /author/[uid:digital]/
                    [widget] => Widget_Archive
                    [action] => render
                    [regx] => |^/author/([0-9]+)[/]?$|
                    [format] => /author/%s/
                    [params] => Array
                        (
                            [0] => uid
                        )

                )

            [search] => Array
                (
                    [url] => /search/[keywords]/
                    [widget] => Widget_Archive
                    [action] => render
                    [regx] => |^/search/([^/]+)[/]?$|
                    [format] => /search/%s/
                    [params] => Array
                        (
                            [0] => keywords
                        )

                )

            [index_page] => Array
                (
                    [url] => /page/[page:digital]/
                    [widget] => Widget_Archive
                    [action] => render
                    [regx] => |^/page/([0-9]+)[/]?$|
                    [format] => /page/%s/
                    [params] => Array
                        (
                            [0] => page
                        )

                )

            [archive_page] => Array
                (
                    [url] => /blog/page/[page:digital]/
                    [widget] => Widget_Archive
                    [action] => render
                    [regx] => |^/blog/page/([0-9]+)[/]?$|
                    [format] => /blog/page/%s/
                    [params] => Array
                        (
                            [0] => page
                        )

                )

            [category_page] => Array
                (
                    [url] => /category/[slug]/[page:digital]/
                    [widget] => Widget_Archive
                    [action] => render
                    [regx] => |^/category/([^/]+)/([0-9]+)[/]?$|
                    [format] => /category/%s/%s/
                    [params] => Array
                        (
                            [0] => slug
                            [1] => page
                        )

                )

            [tag_page] => Array
                (
                    [url] => /tag/[slug]/[page:digital]/
                    [widget] => Widget_Archive
                    [action] => render
                    [regx] => |^/tag/([^/]+)/([0-9]+)[/]?$|
                    [format] => /tag/%s/%s/
                    [params] => Array
                        (
                            [0] => slug
                            [1] => page
                        )

                )

            [author_page] => Array
                (
                    [url] => /author/[uid:digital]/[page:digital]/
                    [widget] => Widget_Archive
                    [action] => render
                    [regx] => |^/author/([0-9]+)/([0-9]+)[/]?$|
                    [format] => /author/%s/%s/
                    [params] => Array
                        (
                            [0] => uid
                            [1] => page
                        )

                )

            [search_page] => Array
                (
                    [url] => /search/[keywords]/[page:digital]/
                    [widget] => Widget_Archive
                    [action] => render
                    [regx] => |^/search/([^/]+)/([0-9]+)[/]?$|
                    [format] => /search/%s/%s/
                    [params] => Array
                        (
                            [0] => keywords
                            [1] => page
                        )

                )

            [archive_year] => Array
                (
                    [url] => /[year:digital:4]/
                    [widget] => Widget_Archive
                    [action] => render
                    [regx] => |^/([0-9]{4})[/]?$|
                    [format] => /%s/
                    [params] => Array
                        (
                            [0] => year
                        )

                )

            [archive_month] => Array
                (
                    [url] => /[year:digital:4]/[month:digital:2]/
                    [widget] => Widget_Archive
                    [action] => render
                    [regx] => |^/([0-9]{4})/([0-9]{2})[/]?$|
                    [format] => /%s/%s/
                    [params] => Array
                        (
                            [0] => year
                            [1] => month
                        )

                )

            [archive_day] => Array
                (
                    [url] => /[year:digital:4]/[month:digital:2]/[day:digital:2]/
                    [widget] => Widget_Archive
                    [action] => render
                    [regx] => |^/([0-9]{4})/([0-9]{2})/([0-9]{2})[/]?$|
                    [format] => /%s/%s/%s/
                    [params] => Array
                        (
                            [0] => year
                            [1] => month
                            [2] => day
                        )

                )

            [archive_year_page] => Array
                (
                    [url] => /[year:digital:4]/page/[page:digital]/
                    [widget] => Widget_Archive
                    [action] => render
                    [regx] => |^/([0-9]{4})/page/([0-9]+)[/]?$|
                    [format] => /%s/page/%s/
                    [params] => Array
                        (
                            [0] => year
                            [1] => page
                        )

                )

            [archive_month_page] => Array
                (
                    [url] => /[year:digital:4]/[month:digital:2]/page/[page:digital]/
                    [widget] => Widget_Archive
                    [action] => render
                    [regx] => |^/([0-9]{4})/([0-9]{2})/page/([0-9]+)[/]?$|
                    [format] => /%s/%s/page/%s/
                    [params] => Array
                        (
                            [0] => year
                            [1] => month
                            [2] => page
                        )

                )

            [archive_day_page] => Array
                (
                    [url] => /[year:digital:4]/[month:digital:2]/[day:digital:2]/page/[page:digital]/
                    [widget] => Widget_Archive
                    [action] => render
                    [regx] => |^/([0-9]{4})/([0-9]{2})/([0-9]{2})/page/([0-9]+)[/]?$|
                    [format] => /%s/%s/%s/page/%s/
                    [params] => Array
                        (
                            [0] => year
                            [1] => month
                            [2] => day
                            [3] => page
                        )

                )

            [comment_page] => Array
                (
                    [url] => [permalink:string]/comment-page-[commentPage:digital]
                    [widget] => Widget_Archive
                    [action] => render
                    [regx] => |^(.+)/comment\-page\-([0-9]+)[/]?$|
                    [format] => %s/comment-page-%s
                    [params] => Array
                        (
                            [0] => permalink
                            [1] => commentPage
                        )

                )

            [feed] => Array
                (
                    [url] => /feed[feed:string:0]
                    [widget] => Widget_Archive
                    [action] => feed
                    [regx] => |^/feed(.*)[/]?$|
                    [format] => /feed%s
                    [params] => Array
                        (
                            [0] => feed
                        )

                )

            [feedback] => Array
                (
                    [url] => [permalink:string]/[type:alpha]
                    [widget] => Widget_Feedback
                    [action] => action
                    [regx] => |^(.+)/([_0-9a-zA-Z-]+)[/]?$|
                    [format] => %s/%s
                    [params] => Array
                        (
                            [0] => permalink
                            [1] => type
                        )

                )

            [page] => Array
                (
                    [url] => /[slug].html
                    [widget] => Widget_Archive
                    [action] => render
                    [regx] => |^/([^/]+)\.html[/]?$|
                    [format] => /%s.html
                    [params] => Array
                        (
                            [0] => slug
                        )
           

這個在代碼裡标為

routingTable

的東西其實就是程式對不同

pathinfo

的解析規則。

剩下的活就交給

index.php

裡的

Typecho_Router::dispatch();

這句的注釋是

/** 開始路由分發 */

接着上邊 

pathinfo

 =

/archives/1/

的例子

dispatch

函數将路由表裡的

[regx]

裡的正規表達式一一進行正則比對,發現與

[post]

的比對,并

1

提取作為參數

cid

的值,并将參數

cid=1

作為參數送出給

Widget_Archive

render

函數,

Widget_Archive

類根據類型

post

cid=1

進行資料查詢和模闆渲染發送給用戶端,至此一個簡單的執行流程就完成了!

細心的讀者可能會發現,為什麼系統路由裡的怎麼都是

[widget] => Widget_Archive
[action] => render
           

這是因為typecho在類

Widget_Archive

裡還根據不同的通路類型調用了不同的查詢函數,這個以後再說!