typecho制作qq卡片时的问题
摘要:关于typecho制作qq卡片时的问题,以及typecho模板中functions.php何时载入,还有$this变量的探究
引子:在写typecho的制作qq卡片时,发现会报一些奇怪的问题,错误如下:
Call to a member function siteurl() on null
Error: Call to a member function siteurl() on null in /www/usr/themes/initial-master/functions.php:242
Stack trace:
#0 /www/usr/themes/initial-master/header.php(21): qqpostThumb(Object(Widget_Archive))
#1 /www/var/Widget/Archive.php(1935): require('/www/usr/themes...')
#2 /www/usr/themes/initial-master/post.php(2): Widget_Archive->need('header.php')
#3 /www/var/Widget/Archive.php(2020): require_once('/www/usr/themes...')
#4 /www/var/Typecho/Router.php(135): Widget_Archive->render()
#5 /www/index.php(21): Typecho_Router::dispatch()
#6 {main}</code></pre>
错误代码是在header.php中添加了qqpostThumb2($this),当时我是想把$this传进去,然后在functions.php里调用,
//functions.php中的代码大意
function qqpostTumb2($a)
{
$b=$a->options->siteurl()
}
很诡异但是如果添加qqpostThumb2($this->options),把$this传进去,然后在functions.php里调用,
//functions.php中的代码大意
function qqpostTumb2($a)
{
$b=$a->siteurl()
}
这样就没问题,那么问题出现在哪里,为什么qqpostThumb2($this->options)可以而qqpostThumb2($this)不可以?
下面是调试过程(从index.php开始):
- /www/index.php(21): Typecho_Router::dispatch() //index.php调用Typecho_Router::dispatch()分配路由
分配路由过后进入 /www/var/Typecho/Router.php文件,定位到133行
相关代码:$widget = Typecho_Widget::widget($route['widget'], NULL, $params); //在这一行代码载入functions.php文件 if (isset($route['action'])) { $widget->{$route['action']}(); //$route['action']要进行的操作,比如文章是$widget->render() } //$route['widget']为Widget_Archive,Typecho_Widget::widget函数内会创建一个Widget_Archive类的实例,然后实例调用execute方法.
找到/www/var/Typecho/Widget.php文件定位到189行,即是Typecho_Widget::widget函数代码
/** * 工厂方法,将类静态化放置到列表中 * * @access public * @param string $alias 组件别名 * @param mixed $params 传递的参数 * @param mixed $request 前端参数 * @param boolean $enableResponse 是否允许http回执 * @return Typecho_Widget * @throws Typecho_Exception */ public static function widget($alias, $params = NULL, $request = NULL, $enableResponse = true) { $parts = explode('@', $alias); $className = $parts[0]; $alias = empty($parts[1]) ? $className : $parts[1]; if (isset(self::$_widgetAlias[$className])) { $className = self::$_widgetAlias[$className]; } if (!isset(self::$_widgetPool[$alias])) { /** 如果类不存在 */ if (!class_exists($className)) { 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(); //这里execute()函数里面载入functions.php self::$_widgetPool[$alias] = $widget; } return self::$_widgetPool[$alias]; }
$widget是一个Widget_Archive类,找到/www/var/Widget/Archive.php文件,查看
execute函数的第1372行,可见在这里载入的function.php/** 初始化皮肤函数 */ $functionsFile = $this->_themeDir . 'functions.php'; if ((!$this->_invokeFromOutside || $this->parameter->type == 404) && file_exists($functionsFile)) { require_once $functionsFile; if (function_exists('themeInit')) { themeInit($this); } }
require_once $functionsFile导入的就是主题模板里的functions文件,themeInit()是functions.php里的初始化函数,functions.php是从这导入的。
- 返回到第二步中的$widget = Typecho_Widget::widget($route['widget'], NULL, $params)处;执行完Typecho_Widget::widget后进入$widget->{$route['action']},这个时候因为请求页面类型是文章页所以是
$widget->render(),然后在/www/var/Widget/Archive.php的第2020行处require /www/usr/themes/initial-matser/post.php,由于post.php里调用了$this->need("header.php"),need()自定义函数作用相当于require函数,所以又导入了header.php,然后调用functions里的函数qqpostThumb($this)。
至于为什么qqpostThumb2($this->options)和qqpostThumb2($this),那是因为$this->options是一个protected类型变量而functions.php是require进去的所以不能访问$this>options这个变量。期间用到的一些文件:
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。