现在的位置: 首页 > 综合 > 正文

discuz 插件核心函数hookscript分析.

2013年05月21日 ⁄ 综合 ⁄ 共 3432字 ⁄ 字号 评论关闭
function hookscript($script, $hscript, $type = 'funcs', $param = array(), $func = '', $scriptextra = '') {
    # 本函数是插件勾注的枋心函数. 对插件开发极为重要.  我们一一分析.
    # hookscript($script, $hscript, $type = 'funcs', $param = array(), $func = '', $scriptextra = '')
    # hookscript($script, $hscript, $type = 'funcs', $param = array(), $func = '', $scriptextra = '')
    # hookscript(方法名, 类型(比如全局,主题, 移动等等..), 调用类型, 参数, 可以勾搭一个副方法, 特殊参数);
	global $_G; // 引入核心数组, 默认是共计4KB大的数组, 
	static $pluginclasses; // 静态货插件类数组, 以便计算执行文件是否已经被引入过.
	if($hscript == 'home') { // 当$hscript 等于home时, 做些变量的转换, 特殊参数就在这儿有效. 
		if($script == 'space') {
			$scriptextra = !$scriptextra ? $_GET['do'] : $scriptextra;
			$script = 'space'.(!empty($scriptextra) ? '_'.$scriptextra : '');
		} elseif($script == 'spacecp') {
			$scriptextra = !$scriptextra ? $_GET['ac'] : $scriptextra;
			$script .= !empty($scriptextra) ? '_'.$scriptextra : '';
		}
	}
    
    # 判断插件是否有定义或者开启. 否则退出.
	if(!isset($_G['setting'][HOOKTYPE][$hscript][$script][$type])) {
		return;
	}
    # 判断插件是否有缓存, 假如没有则退出.
	if(!isset($_G['cache']['plugin'])) {
		loadcache('plugin');
	}

    # 循环取出module数组, module数组里面包涵着文件路径.
	foreach((array)$_G['setting'][HOOKTYPE][$hscript][$script]['module'] as $identifier => $include) {
	    // pluginrunlist 这儿检测了方法是否被禁用, 否则跳过一次.
		if($_G['pluginrunlist'] && !in_array($identifier, $_G['pluginrunlist'])) {
			continue;
		}
        // 权限的判断. 
		$hooksadminid[$identifier] = !$_G['setting'][HOOKTYPE][$hscript][$script]['adminid'][$identifier] || ($_G['setting'][HOOKTYPE][$hscript][$script]['adminid'][$identifier] && $_G['adminid'] > 0 && $_G['setting']['hookscript'][$hscript][$script]['adminid'][$identifier] >= $_G['adminid']);
		if($hooksadminid[$identifier]) { // 只有权限判断通过, 才会引入文件. 个人觉得应该将$pluginclasses数组运用起来.
			@include_once DISCUZ_ROOT.'./source/plugin/'.$include.'.class.php';
		}
	}
    
    # 判断方法集是为数组, (is_array有必要用@抑制错误吗?)
	if(@is_array($_G['setting'][HOOKTYPE][$hscript][$script][$type])) {
		$_G['inhookscript'] = true; // 只能标明调用成功了.
        // 处理附加调用的方法增加, 以便让循环中可以使用.
		$funcs = !$func ? $_G['setting'][HOOKTYPE][$hscript][$script][$type] : array($func => $_G['setting'][HOOKTYPE][$hscript][$script][$type][$func]);         
        // 循环所有的方法. 多维数组, 考虑到一个类型的hook可能有多个实现方法.
		foreach($funcs as $hookkey => $hookfuncs) {
			foreach($hookfuncs as $hookfunc) {
			     // $hookfunc[0] 为 类型也可理解为类的名字.
                 // $hookfunc[1] 为 执行方法
				if($hooksadminid[$hookfunc[0]]) {
					# 这儿需要重组一下类的名字.
                    $classkey = (HOOKTYPE != 'hookscriptmobile' ? '' : 'mobile').'plugin_'.($hookfunc[0].($hscript != 'global' ? '_'.$hscript : ''));
					
                    # 判断类没有被加载就退出. false参数是为了不检查引入.
                    if(!class_exists($classkey, false)) {
						continue;
					}
                    # 判断如果没实例化过, 就实例化一次. 
					if(!isset($pluginclasses[$classkey])) {
						$pluginclasses[$classkey] = new $classkey;
					}
                    # 判断$hookfunc[1]方法不存在实例中. 就退出.
					if(!method_exists($pluginclasses[$classkey], $hookfunc[1])) {
						continue;
					}
                    # 然后调用$hookfunc[1]方法, 并且植入方法. 
					$return = $pluginclasses[$classkey]->$hookfunc[1]($param);
                    // $param = var_export($param,true);
                    // echo "{$classkey}->$hookfunc[1]($param)<br />"; 可通过这两行打印具体.
                    
                    # 判断 类型具有某特征, 并且在pluginhooks数组中存在, 然后退出. 
					if(substr($hookkey, -7) == '_extend' && !empty($_G['setting']['pluginhooks'][$hookkey])) {
						continue;
					}
                    
                    # 判断返回值为数组时就进入.
					if(is_array($return)) {
					   # $hookkey 判断 是否存在插件hook当中. 并且要是数组. 接着循环, 将返回值做不同的赋值释放.  
						if(!isset($_G['setting']['pluginhooks'][$hookkey]) || is_array($_G['setting']['pluginhooks'][$hookkey])) {
							foreach($return as $k => $v) {
								$_G['setting']['pluginhooks'][$hookkey][$k] .= $v;
							}
						} else {
							foreach($return as $k => $v) {
								$_G['setting']['pluginhooks'][$hookkey][$k] = $v;
							}
						}
					} else {
					   #假如返回值不是数组, 则换种方法释放返回值.
						if(!is_array($_G['setting']['pluginhooks'][$hookkey])) {
							$_G['setting']['pluginhooks'][$hookkey] .= $return;
						} else {
							foreach($_G['setting']['pluginhooks'][$hookkey] as $k => $v) {
								$_G['setting']['pluginhooks'][$hookkey][$k] .= $return;
							}
						}
					}
				}
			}
		}
	}
    # 变个变量是什么意思, 上面定义true, 这儿定义false, 是在计算流程是否完成吗? 
	$_G['inhookscript'] = false;
}

抱歉!评论已关闭.