您应该具有以下组件:
>业务对象,在您的应用中模拟并表达一个特定的“事物”:
class Link { ... }
class User { ... }
这些不会“做”任何事情,它们只是在那里形式化您的数据结构.这些对象具有getter和setter方法来获取和设置各个属性,这些属性也在那里得到验证:
public function setUrl($url) {
if (!/* validate the URL here*/) {
throw new InvalidArgumentException("$url is not a valid URL");
}
$this->url = $url;
}
所需的最低数据是构造函数的一部分.这可确保您的数据完整性在整个应用程它允许您声明当您有Link实例时,它表示的数据是链接的最小有效数据.
>数据库链接.只有连接到数据库的必要的东西,仅此而已.一个原始的PDO或mysqli对象就可以了.
>数据对象映射器,它接受数据库链接并知道如何在数据库中存储业务对象以及如何检索它们:
class LinkStorage {
protected $db;
public function __construct(PDO $db) {
$this->db = $db;
}
}
该类具有如何从数据库中检索内容的各种方法:
public function getById($id) {
$stmt = $this->db->prepare('SELECT ... FROM ... WHERE id = :id');
$stmt->execute(compact('id'));
if (!$data = $stmt->fetch()) {
throw new RuntimeException("Record with id $id does not exist");
}
return new Link($data['url']);
}
您可以通过这种方式封装各种不同的查询,例如:
/**
* Returns all links by a particular user.
* @param User $user
* @return Link[]
*/
public function getAllFromUser(User $user) {
...
}
用法很简单:
$db = new PDO(...);
$linkStorage = new LinkStorage($db);
$userStorage = new UserStorage($db);
$user = $userStorage->getById($id);
$links = $linkStorage->getAllFromUser($user);
然后将这种代码封装在服务类中,该服务类包含您可以在应用程序中执行的所有可能的“操作”. registerUser(array $data),getLinksOfUser($id),newLinkFromPostData(array $data)等.
我刚才描述的基本上是MVC风格应用程序的模型部分.另外两个部分是调用服务方法的控制器,以及从服务方法中检索输出数据的视图.这种方法可以将职责分开并隔离,并允许您将更高级别的逻辑和功能放在一起,就像构建块一样.业务对象是最低的构建块,它们的结构需要牢固且定义良好,以便其余的工作.数据对象映射器只关心将这些对象放入数据库并再次将它们取回.然后,服务以各种复杂的方式将所有这些组合在一起并使事情发生.
你不应该对此有任何循环依赖,因为责任是完全分开的.您的个人依赖关系可能仍然有些复杂.如果实例化类变得太麻烦,你会想看看工厂:
$factory = new Factory;
$userStorage = $factory->newUserStorage();
实例化的所有复杂性都封装在这个工厂中.更进一步的是依赖注入容器,您可以在其中配置,例如,XML文件以指定哪个类依赖于什么,然后DI容器将为您处理它.