这是一个非常好的问题,触及了 Dedecms(织梦)早期版本一个设计上的特点,也反映了一个常见的编程实践。

(图片来源网络,侵删)
在 Dedecms 的早期版本中,PHP 文件(如 arclist.lib.php)被称为“类文件”,但它们通常不使用 PHP 的 class 关键字来定义类,这背后有几个主要原因:
历史原因与编程风格演变
- 时代背景:Dedecms 最早发布于 PHP 4 时代,在 PHP 4 中,面向对象编程的支持相对较弱,语法也比较笨拙,许多早期的 PHP 开发者,尤其是习惯了过程式编程的开发者,更倾向于使用函数和全局变量来组织代码。
- “类文件”的命名是一种约定俗成:在 Dedecms 的目录结构中,
/include/目录下存放了许多功能相关的 PHP 文件,它们以.lib.php如arclist.lib.php,channelunit.class.php),这些文件封装了特定的、可复用的功能块,开发团队为了方便区分和记忆,就将这些“功能库文件”或“类库文件”统称为“类文件”,但这并不等同于它们在代码结构上是一个class。
可以理解为,这里的“类”是一个广义的“分类”或“库”的概念,而不是严格的面向对象中的“类”(Class)。
过程式编程 vs. 面向对象编程
Dedecms 的核心代码大量采用了过程式编程的风格。
-
过程式风格(以
arclist.lib.php为例):
(图片来源网络,侵删)- 它定义了一系列函数(如
lib_arclist())。 - 当你需要调用这个功能时,你直接包含这个文件,然后调用它的函数。
- 数据和逻辑是分离的,函数通过参数接收数据,处理后返回结果。
// 在其他PHP文件中的调用方式 require_once(DEDEINC.'/arc.archives.class.php'); $arc = new Archives($aid); // 注意,这个是真正的类文件 // 对于 arclist.lib.php,通常是这样被调用的(在模板引擎或标签中) // 标签解析器会去执行 arclist.lib.php 中的 lib_arclist 函数
- 它定义了一系列函数(如
-
面向对象风格(以
archives.class.php为例):- Dedecms 中也有一些真正的类文件,
archives.class.php(文章处理类)、channelunit.class.php(模型单元类)等。 - 这些文件使用了
class关键字,将数据和操作数据的方法封装在一起。 - 使用时,你需要先
new一个对象,然后通过对象来调用方法。
// 在其他PHP文件中的调用方式 require_once(DEDEINC.'/arc.archives.class.php'); $arc = new Archives($aid); // 实例化一个对象 $arc->PrintFields(); // 调用对象的方法
- Dedecms 中也有一些真正的类文件,
你可以把 Dedecms 的“类文件”看作一个功能工具箱,里面装满了各种工具(函数),而真正的“类文件”则像一个精密仪器,你先把它组装起来(实例化),然后才能使用它的特定功能(方法)。
全局变量与“全局神级”对象 $dsql
这是理解 Dedecms 代码结构的一个关键点,Dedecms 大量依赖全局变量,尤其是数据库连接对象 $dsql。
- 全局共享的
$dsql:几乎所有的.lib.php文件在执行时,都会直接使用全局变量$dsql来进行数据库查询,这个$dsql对象通常在include/common.inc.php中被初始化。 - 无需“注入”依赖:因为可以直接使用全局变量,所以这些函数式库文件不需要像现代 OOP 框架那样,通过“依赖注入”的方式将数据库连接对象作为参数传进来,这使得代码编写起来更直接,但也导致了代码的强耦合和可测试性差。
一个典型的 lib 文件结构是这样的:

(图片来源网络,侵删)
// /include/taglib/arclist.lib.php
// 函数定义
function lib_arlist(&$ctag, &$refObj)
{
// 1. 从全局获取数据库连接对象
global $dsql;
// 2. 解析标签属性,获取参数
$attlist = "typeid|0,row|10,titlelen|28";
FillAttsDefault($ctag->CAttribute->Items, $attlist);
$typeid = $ctag->GetAtt('typeid');
$row = $ctag->GetAtt('row');
// 3. 使用 $dsql 执行SQL查询
$innertext = $ctag->GetInnerText();
$orwheres = '';
$query = "SELECT id, title, pubdate FROM `dede_archives` WHERE typeid='$typeid' $orwheres ORDER BY id DESC LIMIT 0, $row";
$dsql->SetQuery($query);
$dsql->Execute();
// 4. 循环处理数据并返回
$artlist = '';
while($row = $dsql->GetArray()){
$artlist .= sprintf($innertext, $row['id'], $row['title'], MyDate('Y-m-d', $row['pubdate']));
}
return $artlist;
}
这个函数没有 class,直接依赖全局 $dsql,非常典型。
| 特性 | “类文件”(如 arclist.lib.php) |
真正的类文件(如 archives.class.php) |
|---|---|---|
| 代码风格 | 过程式编程 | 面向对象编程 |
| 核心结构 | 定义一系列函数 | 使用 class 定义类 |
| 数据交互 | 主要依赖全局变量(如 $dsql) |
主要通过对象属性和方法参数 |
| 实例化方式 | 直接 include 文件,然后调用函数 |
new ClassName() 实例化对象,然后调用 ->method() |
| 命名意义 | 广义的“功能库文件” | 狭义的“面向对象类文件” |
| 目的 | 提供可复用的功能函数集 | 封装特定业务逻辑和状态 |
为什么现在 Dedecms 也开始用 class 了?
随着 PHP 5/7/8 的发展和现代编程思想的普及,Dedecms 的后续版本也在逐步重构,将越来越多的功能从过程式代码迁移到面向对象的结构中,以提高代码的可维护性、可扩展性和复用性,所以你现在会看到越来越多的 .class.php 文件,这是系统演进的结果。
希望这个解释能帮助你彻底理解 Dedecms 中这个看似矛盾的设计!
