转载请注明出处:http://blog.csdn.net/jh_zzz
以 index.php 为例:
/** 初始化组件 */
Typecho_Widget:: widget('Widget_Init' );
Init 的 execute 中会初始化 Typecho_Plugin ,这里 $options -> plugins 是从数据库读出来后反序列化的:
Typecho_Plugin:: init($options -> plugins);
init 中分别将 plugins 中的 activated 和 handles 单独保存,打印出来形式是这样的:
[activated] => Array
(
[HelloWorld] => Array
(
[handles] => Array
(
[admin/menu.php:navBar] => Array
(
[0] => Array
(
[0] => HelloWorld_Plugin
[1] => render
)
)
)
)
)
[handles] => Array
(
[admin/menu.php:navBar] => Array
(
[0] => Array
(
[0] => HelloWorld_Plugin
[1] => render
)
)
)
继续看 index.php :
/** 注册一个初始化插件 */
Typecho_Plugin:: factory('index.php' )-> begin();
… 略过 …
/** 注册一个结束插件 */
Typecho_Plugin:: factory('index.php' )-> end();
Typecho_Plugin:: factory 会根据 ’index.php’ 创建一个新的 Typecho_Plugin 。接下来的 begin() , end() 实际上都是不存在的,于是魔鬼方法 __call 被执行,
$component = $this -> _handle . ':' . $component ;
$last = count($args );
$args [$last ] = $last > 0 ? $args [0 ] : false ;
if (isset (self:: $_plugins ['handles' ][$component ])) {
$args [$last ] = NULL ;
$this -> _signal = true ;
foreach (self:: $_plugins ['handles' ][$component ] as $callback ) {
$args [$last ] = call_user_func_array($callback , $args );
}
}
__call 查找对应 index.php:begin 的 Typecho_Plugin ,如果找到的话,就会调用相应的方法。例如如果找到的是HelloWorld_Plugin ,则 HelloWorld_Plugin.render() 会被执行。
(
[0] => HelloWorld_Plugin
[1] => render
)
简单说一下 Plugin 是如何加载的,在 config.inc.php 中首先设置了包含路径,插件路径也在其中:
/** 设置包含路径 */
@ set_include_path(get_include_path() . PATH_SEPARATOR .
__TYPECHO_ROOT_DIR__ . '/var' . PATH_SEPARATOR .
__TYPECHO_ROOT_DIR__ . __TYPECHO_PLUGIN_DIR__ );
HelloWorld_Plugin 此时尚未被加载,所以当执行到 HelloWorld_Plugin.render() 时 ,Typecho_Common::__autoLoad 函数被执行,这里会自动加载指定的插件文件:
@ include_once str_replace('_' , '/' , $className ) . '.php' ;
例如对于 HelloWorld_Plugin ,文件就是 HelloWorld/Plugin.php ,因为 usr/plugin 目录已经在包含的路径中,所以这个文件可以正常加载。
当初我学习 php 的时候还是 php3 ,现在一些新特性我都不知道,这一段我看了半天才搞清楚,这次读这些代码了解了不少 php 的新特性:)