实体 类 的用途和好处是什么?
What are the uses and benefits of entity classes?
我经常遇到类似下面的代码(参考Slim tutorial at github)。
TicketMapper.php
class TicketMapper extends Mapper
{
public function getTickets() {
$sql = "SELECT t.id, t.title, t.description, c.component
from tickets t
join components c on (c.id = t.component_id)";
$stmt = $this->db->query($sql);
$results = [];
while($row = $stmt->fetch()) {
$results[] = new TicketEntity($row);
}
return $results;
}
/**
* Get one ticket by its ID
*
* @param int $ticket_id The ID of the ticket
* @return TicketEntity The ticket
*/
public function getTicketById($ticket_id) {
$sql = "SELECT t.id, t.title, t.description, c.component
from tickets t
join components c on (c.id = t.component_id)
where t.id = :ticket_id";
$stmt = $this->db->prepare($sql);
$result = $stmt->execute(["ticket_id" => $ticket_id]);
if($result) {
return new TicketEntity($stmt->fetch());
}
}
public function save(TicketEntity $ticket) {
$sql = "insert into tickets
(title, description, component_id) values
(:title, :description,
(select id from components where component = :component))";
$stmt = $this->db->prepare($sql);
$result = $stmt->execute([
"title" => $ticket->getTitle(),
"description" => $ticket->getDescription(),
"component" => $ticket->getComponent(),
]);
if(!$result) {
throw new Exception("could not save record");
}
}
}
TicketEntity.php
class TicketEntity
{
protected $id;
protected $title;
protected $description;
protected $component;
/**
* Accept an array of data matching properties of this class
* and create the class
*
* @param array $data The data to use to create
*/
public function __construct(array $data) {
// no id if we're creating
if(isset($data['id'])) {
$this->id = $data['id'];
}
$this->title = $data['title'];
$this->description = $data['description'];
$this->component = $data['component'];
}
public function getId() {
return $this->id;
}
public function getTitle() {
return $this->title;
}
public function getDescription() {
return $this->description;
}
public function getShortDescription() {
return substr($this->description, 0, 20);
}
public function getComponent() {
return $this->component;
}
}
我目前的做法不使用实体 classes,我的映射器方法只是 return stdClass,如下所示:
class TicketMapper extends Mapper
{
public function getTickets() {
$sql = "...";
$stmt = $this->db->query($sql);
return $stmt->fetchAll(PDO::FETCH_OBJ);
}
public function getTicketById($ticket_id) {
$sql = "...";
$stmt = $this->db->prepare($sql);
$result = $stmt->execute(["ticket_id" => $ticket_id]);
return $stmt->fetch(); //Assuming my PDO is configured to return an object only
}
public function save($ticket) {/* no change */}
}
为什么数据库结果经常包含在某些实体中 class?有没有什么标准可以决定是否这样做?
封装:class 是一个有用的数据包,其中包含代码和相关数据,与其他所有内容隔离开来。这使得在不搜索确切变量的情况下更容易移动它,而不会与现有 code/data.
发生冲突
当然 classes 还有其他用途,但在像 PHP 这样的脚本环境中,我认为最大的优点是。
代码重用
继承
更易于维护
等做一些研究,这是一件有趣的事情
data mapper 的要点是充当业务逻辑和存储之间的持久层。它在实体对象中填充或存储数据。
这些实体有几个目标:
封装:您能够跟踪和控制实体包含的数据如何被访问和更改
验证:确保实体的状态匹配业务规则和检测能力,如果实体已经进入(或即将进入)无效状态
contracts:您可以使用类型提示来定义哪些其他模块(类、函数)可以使用此实体以及它可以接受哪些类型的东西作为参数。您还可以选择定义此实体的替代品必须实现的接口
行为:一个实体通常会有关联的行为(或业务逻辑),例如:$article->markAsApproved()
操作不会是微不足道的 setter 而是使一个原子状态改变。
至于标准……好吧……"are you using OOP or not" 最接近。 stdClass
只是一个没有任何行为的美化数组。
您可能应该观看 this lecture。
我经常遇到类似下面的代码(参考Slim tutorial at github)。
TicketMapper.php
class TicketMapper extends Mapper
{
public function getTickets() {
$sql = "SELECT t.id, t.title, t.description, c.component
from tickets t
join components c on (c.id = t.component_id)";
$stmt = $this->db->query($sql);
$results = [];
while($row = $stmt->fetch()) {
$results[] = new TicketEntity($row);
}
return $results;
}
/**
* Get one ticket by its ID
*
* @param int $ticket_id The ID of the ticket
* @return TicketEntity The ticket
*/
public function getTicketById($ticket_id) {
$sql = "SELECT t.id, t.title, t.description, c.component
from tickets t
join components c on (c.id = t.component_id)
where t.id = :ticket_id";
$stmt = $this->db->prepare($sql);
$result = $stmt->execute(["ticket_id" => $ticket_id]);
if($result) {
return new TicketEntity($stmt->fetch());
}
}
public function save(TicketEntity $ticket) {
$sql = "insert into tickets
(title, description, component_id) values
(:title, :description,
(select id from components where component = :component))";
$stmt = $this->db->prepare($sql);
$result = $stmt->execute([
"title" => $ticket->getTitle(),
"description" => $ticket->getDescription(),
"component" => $ticket->getComponent(),
]);
if(!$result) {
throw new Exception("could not save record");
}
}
}
TicketEntity.php
class TicketEntity
{
protected $id;
protected $title;
protected $description;
protected $component;
/**
* Accept an array of data matching properties of this class
* and create the class
*
* @param array $data The data to use to create
*/
public function __construct(array $data) {
// no id if we're creating
if(isset($data['id'])) {
$this->id = $data['id'];
}
$this->title = $data['title'];
$this->description = $data['description'];
$this->component = $data['component'];
}
public function getId() {
return $this->id;
}
public function getTitle() {
return $this->title;
}
public function getDescription() {
return $this->description;
}
public function getShortDescription() {
return substr($this->description, 0, 20);
}
public function getComponent() {
return $this->component;
}
}
我目前的做法不使用实体 classes,我的映射器方法只是 return stdClass,如下所示:
class TicketMapper extends Mapper
{
public function getTickets() {
$sql = "...";
$stmt = $this->db->query($sql);
return $stmt->fetchAll(PDO::FETCH_OBJ);
}
public function getTicketById($ticket_id) {
$sql = "...";
$stmt = $this->db->prepare($sql);
$result = $stmt->execute(["ticket_id" => $ticket_id]);
return $stmt->fetch(); //Assuming my PDO is configured to return an object only
}
public function save($ticket) {/* no change */}
}
为什么数据库结果经常包含在某些实体中 class?有没有什么标准可以决定是否这样做?
封装:class 是一个有用的数据包,其中包含代码和相关数据,与其他所有内容隔离开来。这使得在不搜索确切变量的情况下更容易移动它,而不会与现有 code/data.
发生冲突当然 classes 还有其他用途,但在像 PHP 这样的脚本环境中,我认为最大的优点是。
代码重用
继承
更易于维护
等做一些研究,这是一件有趣的事情
data mapper 的要点是充当业务逻辑和存储之间的持久层。它在实体对象中填充或存储数据。
这些实体有几个目标:
封装:您能够跟踪和控制实体包含的数据如何被访问和更改
验证:确保实体的状态匹配业务规则和检测能力,如果实体已经进入(或即将进入)无效状态
contracts:您可以使用类型提示来定义哪些其他模块(类、函数)可以使用此实体以及它可以接受哪些类型的东西作为参数。您还可以选择定义此实体的替代品必须实现的接口
行为:一个实体通常会有关联的行为(或业务逻辑),例如:
$article->markAsApproved()
操作不会是微不足道的 setter 而是使一个原子状态改变。
至于标准……好吧……"are you using OOP or not" 最接近。 stdClass
只是一个没有任何行为的美化数组。
您可能应该观看 this lecture。