关于类:PHP OOP模块化CMS对象设计

PHP OOP Modular CMS Objects design

本问题已经有最佳答案,请猛点这里访问。

我想听听您对如何在模块化CMS系统中设计对象的建议。我已经找了好几个小时了,但还是找不到正确的答案。

如何设计与事物交互的类?假设我有这些课程:

1
2
3
4
cDb() // for database interactions
cUser() // for all user actions
cSession() // for interactions with session data.
cAnotherObject // multiple another objects from future modules

如果我以某种方式扩展它们,那么最后,我会得到一个这样的对象:

1
$myvar = new cLatestClass();

[会话扩展CDB,CUSER扩展CSession…等

如果是这样,如何处理模块中动态加载的类?仅仅使用多个var来固定物体会更好吗?

1
2
3
$user = new cUser();
$session = new cSessions();
 ... etc.

我真的希望这里有人能回答我,希望能教我如何正确地做。


首先,我建议退后一步,学习什么是面向对象。创造了"面向对象编程"一词的Alan Kay曾经这样描述:

I thought of objects being like biological cells and/or individual
computers on a network, only able to communicate with messages.
(source)

在PHP(以及大多数面向对象语言中)中,这些消息通常是方法调用,或者在公共属性的情况下,是获取和设置它们的值。

因此,把系统中的对象想象成一个更大的有机体中的单个细胞,它们协同工作以实现更大的目标,而不是试图将所有需要的行为混合到一个对象中。

这是一个大主题,许多书都写在上面,但就你在问题中提到的对象而言,我首先要区分它们所属的不同类别。一个数据库或会话对象可以被认为是一种"服务",其他对象(例如,如果您使用的是MVC框架,您的控制器)将依赖于它。正如其他人所提到的,依赖注入是处理此类服务的一个很好的解决方案,但在大多数情况下,我不建议将其用于类似用户类的东西,因为每个用户都应该有一个实例(当然不是字面意义上的——您只需要将特定的用户对象加载到您需要处理特定请求的内存中,在许多情况下,只是当前用户的一个实例)。

为了了解更多关于依赖注入的信息,我建议在这篇文章中,MartinFowler创造了这个术语,并且在这里他提到了一个更简单的替代服务定位器的依赖注入容器。

(依赖注入容器方法更健壮,但也更复杂;幸运的是,它有一个好的开源库)。

用户、文章和类别都是CMS中域对象的示例。这些是MVC"M"(模型)的一部分(也称为域模型)。当然,您仍然需要一种方法来将这些对象进出数据库,因此您可能还需要某种类型的存储库或查询类(存储库类可以视为服务)。并不是所有的PHP系统都有真正的域对象;许多系统只是有返回数组或stdclass对象的类似存储库的类(简单的匿名对象,创建如下:$someObj = new stdClass),这意味着这些系统没有真正的面向对象编程,但通常有实际的原因做出这样的决定。

面向对象编程的真正目的比我上面提到的要深:它是关于在一个系统中设计对象来反映我们的心理模型(一个包含最终用户和程序员视角的联合心理模型)。这是另一个很好的引述,这一次来自Trygve Reenskaug,他发明了MVC模式:

I think of the difference between procedure oriented and object
oriented programming as being that procedure oriented answers the
question:"What happens?". Object oriented answers an additional
question:"Who does it?" (source)

最后,我建议阅读一本专门介绍PHP中面向对象编程的书。一个很好的例子是Matt Zandstra的PHP对象、模式和实践。


Should I somehow extend them all, so in the end, I end up with one object like this:

不,你当然不应该。扩展类时,您应该有一个is-a关系。

会话不是数据库。用户当然不是会话。您所看到的可能是依赖注入。

假设您的User类需要一个数据库连接。看起来像是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class User
{
    private $dbConnection;

    public function __construct(\PDO $dbConnection)
    {
        $this->dbConnection = $dbConnection;
    }

    public function doSomethingWithDb()
    {
        $this->dbConnection->query('SELECT...');
    }
}

$dbConnection = new PDO('/* dsn string */', 'user', 'pass');
$user = new User($dbConnection);

如果您将数据库查询从User类中提取出来,这样就更好了,这样您就不必全部使用数据库了。

同样作为一个cs注释:为什么你要用c来预习你的类?

关于您的模块系统。这将取决于您将如何设置模块,但您可能需要查看依赖项注入容器以将动态模块连接在一起。