今天让我们来看一个插件开发的反例 - 显示在线用户
Tillreetree (99) 开发者 管理团队 11小时前

原始代码:

<div class="container">
<div class="row">
	<div class="col-lg-12">
		<div class="card card-friendlink link-bottom">
			<div class="card-header">在线用户--<?php
			$arronline=assoc_unique(online_list_cache(),'uid');//获取在线用户信息并且根据uid值去重复
			echo count($arronline);
			?></div>
			<div class="card-body p-a-sm p-b-xs">
					<?php 
$rew=$conf['url_rewrite_on']==0 ? '?':'';//伪静态
foreach($arronline as $online_user) { //Changed By Eveson 
echo "<a class=\"mr-2 float-left\" href=\"".getlistn().$rew."user-{$online_user['uid']}.htm\" target=\"_blank\" >{$online_user['username']}</a>";//此处感觉应该引入js或者html文件
}
function assoc_unique($arr, $key) {  //根据指定的key值为数组去重
        $tmp_arr = array();  
        foreach($arr as $k => $v) {  
            if(in_array($v[$key], $tmp_arr)) {  
                unset($arr[$k]);  
            } else {  
                $tmp_arr[] = $v[$key];  
            }  
        }  
        sort($arr);  
        return $arr;  
} 
function getlistn(){//返回修罗主程序所处相对目录 
return substr($_SERVER['PHP_SELF'],0,strlen($_SERVER['PHP_SELF'])-10);   
}
                    
                    ?>
			</div>
		</div>
	</div>
	</div>

这是一个典型的“面条式”代码示例,虽然功能上可以实现,但从插件开发的角度来看,它存在多个严重的问题,是我们在开发中应该避免的反面教材。

问题在哪:

  1. 原始代码将assoc_unique和getlistn函数定义在HTML输出逻辑之后,导致PHP解析时可能会先调用未声明的函数,引发致命错误(Fatal error: Call to undefined function)

  2. 路径计算逻辑脆弱:getlistn()通过硬编码截取$_SERVER['PHP_SELF']末尾10字符(大约为“/index.php”的长度,算上符号10个字符),实际路径长度可能变化(如子目录部署),导致生成错误URL,实际上整个xiuno只需要相对路径即可

  3. 手动拼接$rew变量判断伪静态,不如使用统一的URL生成函数

  4. 代码结构混乱:PHP函数定义与HTML模板混杂,降低可维护性;xiuno bbs推荐你直接用PHP作为模板引擎,但不是说你可以这样过度混乱的去写

  5. 重复定义风险:原始代码未检查函数是否存在(我们不能做假设性的判断)

  6. 过时语法:使用已废弃的float-left等旧版Bootstrap类

修改版:

<?php 

if(!function_exists('assoc_unique')){
	function assoc_unique($arr, $key) {  //根据指定的key值为数组去重
        $tmp_arr = array();  
        foreach($arr as $k => $v) {  
            if(in_array($v[$key], $tmp_arr)) {  
                unset($arr[$k]);  
            } else {  
                $tmp_arr[] = $v[$key];  
            }  
        }  
        sort($arr);  
        return $arr;  
	} 
}

//获取在线用户信息并且根据uid值去重复
$arronline=assoc_unique(online_list_cache(),'uid');
?>

<div class="row">
	<div class="col-lg-12">
		<div class="card card-friendlink link-bottom">
			<div class="card-header">在线用户 (<?php echo count($arronline); ?>) </div>
			<div class="card-body" hx-boost="true" hx-target="#body" hx-swap="innerHTML">
				<?php foreach($arronline as $online_user) : ?>
                                <a class="btn btn-link" href="<?= url('user-' . $online_user['uid']) ?>"><?= htmlspecialchars($online_user['username'], ENT_QUOTES, 'UTF-8') ?></a>
				<?php endforeach; ?>
			</div>
		</div>
	</div>
</div>

修改版的优化思路:

  1. 将PHP数据处理逻辑完全移至HTML模板之前,结构清晰,一目了然。

  2. 使用 if(!function_exists(...)) 包装函数定义,有效避免了函数重定义冲突。

  3. 使用安全的URL生成函数:使用xiuno bbs唯一指定URL生成函数 url() ,它能智能地根据当前配置(如是否开启伪静态等)生成正确的URL,彻底解决了手动拼接的隐患。这是与主程序交互的正确方式。

  4. 使用防御性编程:虽然我们从来都没在用户名上吃瘪,且所有人都会输入正常的用户名,但以防万一
  5. 使用更优雅的模板语法:采用 foreach(...) : ... endforeach; 替代大括号{},在HTML环境中更清晰。使用短标签 <?= 让输出语句更简洁。

    1. 以及,短标签 <?= ... ?> 是PHP一直可用的方式,不需要开启short_open_tag即可使用
  6. 重新改进HTML结构与样式:使用 btn-link 来给链接增加边距,并且不再需要任何float就可以正确排版,视觉效果更好。移除了不必要的内联样式。

  7. 添加了HTMX属性,这不是必须的,但这个例子是来自于我正在开发的HTMX现代化计划的一部分,所以就留着了

通过这样的重构,代码从一段“能用但危险”的脚本转变为了一个结构清晰、健壮可靠且易于维护的插件组件。

最新回复 (1)
广告推荐
Tillreetree
开发者 管理团队
广告推荐