zoukankan      html  css  js  c++  java
  • typecho流程原理和插件机制浅析(第一弹)

    •  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_Initexecute函数

    <?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/
    • 从数据库读取系统路由表(optionroutingTable字段)

    举例系统安装完成默认路由

                [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类根据类型postcid=1进行数据查询和模板渲染发送给客户端,至此一个简单的执行流程就完成了!

    细心的读者可能会发现,为什么系统路由里的怎么都是

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

    这是因为typecho在类Widget_Archive里还根据不同的访问类型调用了不同的查询函数,这个以后再说!

  • 相关阅读:
    django-5.Django 管理后台
    django-3.模板引擎
    django-2.视图与url配置
    django- 1.环境与初始化项目
    css层叠样式表
    bootstrap table 个人心得
    attr和prop的区别 chosen插件
    extract-text-webpack-plugin
    Git常用命令大全,迅速提升你的Git水平
    dropload.js 局部区域加载坑
  • 原文地址:https://www.cnblogs.com/u0mo5/p/4583917.html
Copyright © 2011-2022 走看看