• 推荐 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里还根据不同的访问类型调用了不同的查询函数,这个以后再说!

typecho流程原理和插件机制浅析(第一弹)的更多相关文章

  1. typecho流程原理和插件机制浅析(第二弹)

    typecho流程原理和插件机制浅析(第二弹) 兜兜 393 2014年04月02日 发布 推荐 1 推荐 收藏 14 收藏,3.7k 浏览 上一次说了 Typecho 大致的流程,今天简单说一下插件 ...

  2. Cocoapods插件机制浅析

    原文链接 背景 虽然做iOS开发的过程中使用过 Cocoapods, 但是对里面的细节了解其实不算太多,直到这两年做织女项目时,通过对Cocoapods进行Qt支持改造才开始深入了解部分细节,这个过程 ...

  3. Dubbo原理和源码解析之“微内核+插件”机制

    github新增仓库 "dubbo-read"(点此查看),集合所有<Dubbo原理和源码解析>系列文章,后续将继续补充该系列,同时将针对Dubbo所做的功能扩展也进行 ...

  4. Atitit 插件机制原理与设计微内核 c# java 的实现attilax总结

    Atitit 插件机制原理与设计微内核 c# java 的实现attilax总结 1. 微内核与插件的优点1 2. 插件的注册与使用2 2.1. Ioc容器中注册插件2 2.2. 启动器微内核启动3 ...

  5. mybatis插件机制及分页插件原理

    MyBatis 插件原理与自定义插件: MyBatis 通过提供插件机制,让我们可以根据自己的需要去增强MyBatis 的功能.需要注意的是,如果没有完全理解MyBatis 的运行原理和插件的工作方式 ...

  6. mybatis(六)插件机制及分页插件原理

    转载:https://www.cnblogs.com/wuzhenzhao/p/11120848.html MyBatis 通过提供插件机制,让我们可以根据自己的需要去增强MyBatis 的功能.需要 ...

  7. WordPress 插件机制的简单用法和原理(Hook 钩子)

    WordPress 的插件机制实际上只的就是这个 Hook 了,它中文被翻译成钩子,允许你参与 WordPress 核心的运行,是一个非常棒的东西,下面我们来详细了解一下它. PS:本文只是简单的总结 ...

  8. php插件机制实现原理

    插件,亦即Plug-in,是指一类特定的功能模块(通常由第三方开发者实现) 它的特点: 1. 随时安装.卸载.激活.禁用 2. 无论什么状态都不影响系统核心模块的运行, 3. 是一种非侵入式的模块化设 ...

  9. Omi框架学习之旅 - 插件机制之omi-finger 及原理说明

    以前那篇我写的alloyfinger源码解读那篇帖子,就说过这是一个很好用的手势库,hammer能做的,他都能做到, 而且源码只有350来行代码,很容易看懂. 那么怎么把这么好的库作为omi库的一个插 ...

随机推荐

  1. margin和padding那点事及常见浏览器margin padding相关Bug

    用Margin还是用Padding 何时应当使用margin: 需要在border外侧添加空白时. 空白处不需要背景(色)时. 上下相连的两个盒子之间的空白,需要相互抵消时.如15px + 20px的 ...

  2. 网易前端JavaScript编码规范

    在多年开发邮箱webmail过程中,网易邮箱前端团队积累了不少心得体会,我们开发了很多基础js库,实现了大量前端效果组件,开发了成熟的opoa框架以及api组件,在此向大家做一些分享.今天想先和大家聊 ...

  3. 完美搞定《DOCKER IN ACTION》第二章示例

    起来!!!命令如下: 建立第一个web docker docker run --detach --name web nginx:latest 建立第二个web_test docker docker r ...

  4. oracle DBA坚持写博客的7大理由

    对于Oracle DBA来说,甚至IT技术人员来说.坚持写博客是个好习惯.以下是我建议大家写博客的七个理由. 帮助整理思路 最近我做出了一个决定,那就是: 我要坚持天天写博客,记录每天所学的重要东西. ...

  5. Android种 adb是什么(转)

    提到adb.exe,一直关注我们Android系列教程的朋友们应该不会感到陌生,因为无论取得 Root权限或者刷机的时候我们都通过adb直接操作管理Android手机,但是可能大多数对于adb仅仅局限 ...

  6. Codeforces Round #313 (Div. 2) D. Equivalent Strings

    D. Equivalent Strings Time Limit: 2 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/559/ ...

  7. img 默认是行内元素,它旁边的空格是会保留的

    img 默认是行内元素,它旁边的空格是会保留的.因此图片宽度设置百分百后下面会有点找不出原因的间隙. 解决办法:img{display:block}

  8. 几种php 删除数组元素方法

    几种php教程 删除数组元素方法在很多情况下我们的数组会出现重复情况,那我们删除数组中一些重复的内容怎么办,这些元素我必须保持他唯一,所以就想办法来删除它们,下面利用了遍历查询来删除重复数组元素的几种 ...

  9. 判断checkbox是否被选中事件

    第一种////////////////////////////////////////////////////////<input type="checkbox" value ...

  10. servlet中cookie的使用

    ---恢复内容开始--- Cookie是存储在客户端计算机上的文本文件,并保留了它们的各种信息跟踪的目的. Java Servlet透明支持HTTP Cookie. 涉及标识返回用户有三个步骤: 服务 ...