我知道这方面有很多问题,我已经阅读了很多。我想在我的项目中询问这个问题,看看你可能有什么建议。
我有一个相当大的 Web 应用程序,其中包含许多类,例如用户和文章(我认为是主要类)以及较小的类,例如图像和评论。现在在一个页面上,比如说一篇文章,它可以包含许多图像和评论的实例。有道理吗?现在说一个文章页面,我调用一个静态方法,它返回一个文章对象数组。
这是背景,所以这里是问题。
由于构建了大量的应用程序,我开始意识到拥有一个包含设置和共享功能的核心系统类将非常有用。在那里,我用一个新的核心类扩展了我的所有类。看起来相对简单且实现起来很快。我知道 CodeIgniter 做了类似的事情。我现在觉得虽然我的应用程序变得有点乱。
问题 这是一个好主意吗?创建 core 的实例正是我在调用文章实例时想要的,但是当我使用静态方法创建多个实例时,或者在页面上调用多个图像或评论时呢?我不必要地调用了核心类,对吗?实际上它只需要每页调用一次(例如构造函数定义了数据库中的各种设置,我不想每次都这样,显然每页一次),但是所有类的所有实例都应该可以访问核心类。听起来就像我想要单例方法,但我知道这在 PHP 中是浪费时间。
这是一个 想法 我的代码在这一点上的样子。我尽量保持简单。
class core {
public function __construct(){
...define some settings which are retrieve from the database
}
public function usefulFunction(){
}
}
class user extends core {
public function __construct(){
parent::__construct();
}
public function getUser($user_id){
$db = new database();
$user = /* Get user in assoc array from db */
$this->__setAll($user);
}
public static function getUsers(){
$db = new database();
$users = /* Get users from database in assoc array from db */
foreach($users as $user) {
$arrUsers[] = new self();
$arrUsers[]->__setAll($user);
}
return $arrUsers;
}
private function __setAll($attributes) {
foreach($attributes as $key => $value)
{
$this->__set($key, $value);
}
}
public function __set($key, $value) {
$this->$key = $value;
}
}
我遇到的另一个问题是有效地使用/共享数据库连接。目前,需要数据库连接的类中的每个方法都会创建一个新的数据库实例,因此在一个页面上我可能会这样做 5 或 10 次。依赖注入(inject)原则之类的东西听起来要好得多。
问题 现在,如果我将数据库的实例传递给新的用户类,我知道我需要这样的东西......
class user{
protected $db;
public function __construct($db){
$this->db = $db;
}
... etc
}
$db = new database();
$user = new user($db);
...但是当我想运行静态函数 users::getUsers() 时,访问数据库实例的最佳方法是什么?我是否需要在每个静态方法中将其作为变量传递? (许多类中有许多静态方法)。这似乎不是最好的方法,但也许没有其他方法。
问题 如果按照第 1 部分中的建议将我的所有类从核心类中扩展出来,我可以在那里创建一个数据库实例并访问它吗?
问题 我还有各种包含函数(不是 oop)的文件,它们就像帮助文件。这些访问数据库的最佳方式是什么?我再次在每个函数中创建了一个新实例。我真的不想将数据库作为参数传递给每个人。我应该使用全局变量,将这些帮助文件转换为类并使用依赖注入(inject)或其他不同的东西吗?
我知道那里有很多建议,但是关于 PHP 的大多数信息和教程都已过时,而且似乎从未涵盖如此复杂的内容……如果您可以称其为复杂的话?
关于如何最好地布置我的类(class)结构的任何建议。我知道这看起来很多,但肯定这是大多数开发人员每天都面临的问题。如果您需要更多信息,请告诉我并感谢您的阅读!
最佳答案
你在评论中问我应该详细说明为什么这是一个坏主意。我想强调以下内容来回答这个问题:
Ask yourself if you really need it.
为需求做设计决策,而不仅仅是因为你能做到。在您的情况下,问问自己是否需要核心类(class)。正如您在评论中已经被问到的那样,您实际上并不真正需要它,所以答案很明确:这样做不好,因为它不需要并且不需要它会引入很多副作用。
由于这些副作用,您不想这样做。那么从零到英雄,我们来做如下进化:
您有两部分代码/功能。一部分会发生变化,另一部分是一些基本功能(框架、库)不会发生变化。您现在需要将它们放在一起。让我们将其简化,并将框架简化为单个函数:
function usefulFunction($with, $four, $useful, $parameters)
{
...
}
让我们将应用程序的第二部分——改变的部分——减少到单个
User
类(class):class User extends DatabaseObject
{
...
}
我已经在这里介绍了一个很小但很重要的变化:
User
类不是从 Core
扩展的不再,但来自 DatabaseObject
因为如果我正确阅读了您的代码,它的功能是表示数据库表中的一行,可能即用户表。我已经做了这个改变,因为有一个非常重要的规则。每当您在代码中命名某些内容时,例如一个类,请使用一个会说话的好名字。名字是为某物命名。名称
Core
除了你认为它是重要的、一般的、基本的或深入的,或者它是铁水之外,绝对没有说什么。没有头绪。因此,即使您是为设计命名,也要选择一个好名字。我想,DatabaseObject
这只是一个非常快速的决定,甚至不知道你的代码,所以我很确定你知道那个类的真实名称,你也有责任给它真实的名字。它应得的,要慷慨。但是让我们把这个细节放在一边,因为它只是一个细节,与您想要解决的一般问题没有太大关系。让我们说坏名字是一种症状,而不是原因。我们现在扮演豪斯博士并编目症状,但只是为了找到原因。
目前发现的症状:
我们可以诊断:迷失方向吗? :)
因此,要避免这种情况,请始终做需要的事情并选择简单的工具来编写代码。例如,提供通用功能(您的框架)的最简单方法就像使用
include
一样简单。命令: include 'my-framework.php';
usefuleFunction('this', 'time', 'really', 'useful');
这个非常简单的拖线脚本演示了:应用程序中的一部分负责提供所需的功能(也称为加载),另一部分正在使用这些功能(这只是我们从一开始就知道的程序代码,对吗?)。
这个映射/缩放到一些更面向对象的示例,其中可能是 User 对象扩展?完全一样:
include 'my-framework.php';
$user = $services->store->findUserByID($_GET['id']);
这里的区别只是内部
my-framework.php
more 被加载,以便经常变化的部分可以使用不变的东西。例如,可以提供一个表示服务定位器的全局变量(此处为 $services
)或提供自动加载。你保持的越简单,你就会进步得越好,最后你将面临真正的决定。通过这些决定,您将更直接地看到不同之处。
如果您想对“数据库类”进行更多讨论/指导,请考虑阅读企业应用程序架构模式一书中关于如何处理这些问题的不同方法的非常好的章节,这本书的标题有点长,但它有一章很好地讨论了该主题,并允许您选择合适的模式来轻松访问数据库。如果你从一开始就让事情变得简单,你不仅进步得更快,而且你以后也更容易改变它们。
然而,如果你从一些从基类扩展的复杂系统开始(甚至可能一次做多件事),事情从一开始就不容易改变,这会让你坚持这样的决定,因为你想要的时间更长到那时。
关于PHP5 OOP 类结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11699522/