数据库表类中实体类的使用与优化
在开发过程中,我们常常需要从数据库中获取数据并进行处理。传统方式下,数据库返回的数据通常是数组形式,这在处理数据时可能会带来一些不便。本文将介绍如何使用实体类来优化数据处理,提高代码的可读性和可维护性。
1. 从数组到实体类的转变
数据库返回的数据为数组形式,例如在
getUser()
方法返回的
$author
数组,我们需要将其数据复制到新创建的
Author
类的实例中。这种复制操作显然效率不高,我们可以通过在
saveEdit
方法外部构造
Author
对象,并让
getUser
返回构造好的对象来避免这个问题。
public function saveEdit() {
$authorObject = $this->authentication->getUser();
$joke = $_POST['joke'];
$joke['jokedate'] = new \DateTime();
$authorObject->addJoke($joke);
header('location: /joke/list');
}
目前,
getUser
方法调用了
DatabaseTable
类的
findById
方法,该方法返回的是一个数组。不过,我们可以使用
fetchObject
方法来返回指定类的实例,例如
Author
类。
return $query->fetchObject('Author', [$jokesTable]);
这里有两个参数:
1. 要实例化的类的名称。
2. 创建对象时提供给构造函数的参数数组。
2. 改进
DatabaseTable
类
为了更灵活地使用不同的实体类,我们可以修改
DatabaseTable
类的构造函数,使其接受两个可选参数:要创建的类的名称和提供给它的任何参数。
class DatabaseTable {
private $pdo;
private $table;
private $primaryKey;
private $className;
private $constructorArgs;
public function __construct(\PDO $pdo, string $table, string $primaryKey, string $className = '\stdClass', array $constructorArgs = []) {
$this->pdo = $pdo;
$this->table = $table;
$this->primaryKey = $primaryKey;
$this->className = $className;
$this->constructorArgs = $constructorArgs;
}
}
同时,修改
findById
方法以使用新的类变量:
public function findById($value) {
$query = 'SELECT * FROM `' . $this->table . '` WHERE `' . $this->primaryKey . '` = :value';
$parameters = [
'value' => $value
];
$query = $this->query($query, $parameters);
return $query->fetchObject($this->className, $this->constructorArgs);
}
PDO
的
fetchAll
方法也可以通过提供相应参数来返回对象:
return $result->fetchAll(\PDO::FETCH_CLASS, $this->className, $this->constructorArgs);
3. 修改
IjdbRoutes
类
在
IjdbRoutes
类中,我们需要更新
DatabaseTable
类的实例化,为
$authorsTable
实例提供类名和参数。
$this->jokesTable = new \Ninja\DatabaseTable($pdo, 'joke', 'id');
$this->authorsTable = new \Ninja\DatabaseTable($pdo, 'author', 'id', '\Ijdb\Entity\Author', [$this->jokesTable]);
这样,当使用
$authorsTable
实例检索记录时,返回的
$author
变量将是
Author
类的实例,我们可以直接调用该类的方法。
4. 解决
saveEdit
方法的问题
由于
getUser
现在返回的是
Author
类的实例,我们可以直接使用该实例,避免手动创建和设置属性。
public function saveEdit() {
$author = $this->authentication->getUser();
$joke = $_POST['joke'];
$joke['jokedate'] = new \DateTime();
$author->addJoke($joke);
header('location: /joke/list');
}
同时,我们还需要修改
Authentication
类,以使用对象而不是数组。在
isLoggedIn
方法和
login
方法中,将数组访问语法改为对象访问语法。
// isLoggedIn 方法修改
$passwordColumn = $this->passwordColumn;
if (!empty($user) && $user[0]->$passwordColumn === $_SESSION['password']) {
// login 方法修改
public function login($username, $password) {
$user = $this->users->find($this->usernameColumn, strtolower($username));
if (!empty($user) && password_verify($password, $user[0]->{$this->passwordColumn})) {
session_regenerate_id();
$_SESSION['username'] = $username;
$_SESSION['password'] = $user[0]->{$this->passwordColumn};
return true;
} else {
return false;
}
}
5. 修复笑话列表页面的问题
当前笑话列表页面显示错误,原因是
$author
和
$joke
不再是数组,而是对象。我们需要将数组访问语法改为对象访问语法。
$author = $this->authorsTable->findById($joke->authorId);
$jokes[] = [
'id' => $joke->id,
'joketext' => $joke->joketext,
'jokedate' => $joke->jokedate,
'name' => $author->name,
'email' => $author->email
];
同时,修改方法的返回语句和
delete
方法以使用对象语法。
return ['template' => 'jokes.html.php',
'title' => $title,
'variables' => [
'totalJokes' => $totalJokes,
'jokes' => $jokes,
'userId' => $author->id ?? null
]
];
// delete 方法修改
if ($joke->authorId != $author->id)
6. 创建
Joke
实体类
为了更好地处理笑话数据,我们创建
Joke
实体类。
<?php
namespace Ijdb\Entity;
class Joke
{
public $id;
public $authorId;
public $jokedate;
public $joketext;
private $authorsTable;
public function __construct(\Ninja\DatabaseTable $authorsTable)
{
$this->authorsTable = $authorsTable;
}
public function getAuthor()
{
return $this->authorsTable->findById($this->authorId);
}
}
7. 使用
Joke
类并解决依赖问题
要使用新的
Joke
类,我们需要更新
IjdbRoutes
类,将
authorsTable
实例作为构造函数参数传递。但这会导致一个问题,即
authorsTable
实例的构造函数需要
jokesTable
实例,而
jokesTable
实例的构造函数又需要
authorsTable
实例,形成了一个死循环。
我们可以使用引用(reference)来解决这个问题。
$this->jokesTable = new \Ninja\DatabaseTable($pdo, 'joke', 'id', '\Ijdb\Entity\Joke', [&$this->authorsTable]);
$this->authorsTable = new \Ninja\DatabaseTable($pdo, 'author', 'id', '\Ijdb\Entity\Author', [&$this->jokesTable]);
8. 简化列表控制器操作
现在,我们可以直接将整个
Joke
对象传递到模板中,并在模板中读取作者信息。
// 移除冗余代码
$jokes = [];
foreach ($result as $joke) {
$author = $this->authorsTable->findById($joke->authorId);
$jokes[] = [
'id' => $joke->id,
'joketext' => $joke->joketext,
'jokedate' => $joke->jokedate,
'name' => $author->name,
'email' => $author->email
];
}
// 替换代码
$result = $this->jokesTable->findAll();
$jokes = $this->jokesTable->findAll();
9. 更新模板
更新
jokes.html.php
模板,使用新的对象语法。
<p><?=$totalJokes?> jokes have been submitted to the Internet Joke Database.</p>
<?php foreach ($jokes as $joke): ?>
<blockquote>
<p>
<?=htmlspecialchars($joke->joketext, ENT_QUOTES, 'UTF-8')?>
(by <a href="mailto:<?=htmlspecialchars($joke->getAuthor()->email, ENT_QUOTES, 'UTF-8'); ?>">
<?=htmlspecialchars($joke->getAuthor()->name, ENT_QUOTES, 'UTF-8'); ?></a> on
<?php
$date = new DateTime($joke->jokedate);
echo $date->format('jS F Y');
?>)
<?php if ($userId == $joke->authorId): ?>
<a href="/joke/edit?id=<?=$joke->id?>">Edit</a>
<form action="/joke/delete" method="post">
<input type="hidden" name="id" value="<?=$joke->id?>">
<input type="submit" value="Delete">
</form>
<?php endif; ?>
</p>
</blockquote>
<?php endforeach; ?>
10. 整理编辑笑话页面
由于我们改变了
DatabaseTable
类的工作方式,“编辑笑话”页面出现了问题。我们需要打开
editjoke.html.php
模板,将数组语法替换为对象语法来访问笑话的属性。
通过以上步骤,我们成功地将数据库返回的数组数据转换为实体类对象,提高了代码的可读性和可维护性,同时也优化了数据处理的流程。
流程图
graph TD;
A[开始] --> B[修改DatabaseTable类构造函数];
B --> C[修改findById和fetchAll方法];
C --> D[更新IjdbRoutes类实例化];
D --> E[修改saveEdit方法];
E --> F[修改Authentication类];
F --> G[修复笑话列表页面];
G --> H[创建Joke实体类];
H --> I[解决依赖问题];
I --> J[简化列表控制器操作];
J --> K[更新模板];
K --> L[整理编辑笑话页面];
L --> M[结束];
总结
本文详细介绍了如何使用实体类来优化数据库数据处理,包括从数组到实体类的转变、改进
DatabaseTable
类、解决依赖问题以及更新模板等步骤。通过这些优化,我们可以提高代码的质量和可维护性,使开发过程更加高效。
操作步骤总结
-
修改
DatabaseTable类的构造函数,添加类名和构造函数参数。 -
修改
findById和fetchAll方法,使用fetchObject和fetchAll返回对象。 -
更新
IjdbRoutes类,提供类名和参数。 -
修改
saveEdit方法,使用对象而不是数组。 -
修改
Authentication类,使用对象访问语法。 - 修复笑话列表页面,将数组语法改为对象语法。
-
创建
Joke实体类。 - 使用引用解决依赖问题。
- 简化列表控制器操作,直接传递对象到模板。
- 更新模板,使用对象语法。
- 整理编辑笑话页面,替换数组语法为对象语法。
数据库表类中实体类的使用与优化(续)
11. 深入理解引用的作用
在前面的步骤中,我们使用了引用(reference)来解决
authorsTable
和
jokesTable
实例化时的依赖问题。引用就像是 Windows 中的快捷方式,或者 macOS 或 Linux 中的符号链接。它本身不存储具体的数据,而是指向另一个变量。
以下是一个简单的引用示例:
$originalVariable = 1;
$reference = &$originalVariable;
$originalVariable = 2;
echo $reference;
在这个示例中,
$reference
是
$originalVariable
的引用。当
$originalVariable
的值被修改为 2 时,
$reference
的值也会变为 2。这是因为
$reference
指向的是
$originalVariable
的内存地址,读取
$reference
的值时,实际上是读取
$originalVariable
的值。
在我们的应用中,通过在
IjdbRoutes
类中使用引用,确保了
authorsTable
和
jokesTable
实例在需要时已经被创建,避免了依赖循环的问题。
12. 优化后的代码优势分析
通过将数据库返回的数组数据转换为实体类对象,我们获得了许多优势。
| 优势 | 说明 |
|---|---|
| 提高代码可读性 |
实体类对象的属性和方法具有明确的含义,使得代码更易于理解。例如,
$joke->getAuthor()->name
比
$joke['email']
更直观地表达了我们要获取的信息。
|
| 增强可维护性 | 如果数据库表结构发生变化,我们只需要在实体类中进行相应的修改,而不需要在整个代码库中查找和修改数组访问的地方。 |
| 更好的扩展性 |
可以在实体类中添加新的方法和属性,以满足不断变化的业务需求。例如,我们可以在
Joke
类中添加一个
getCategory
方法,用于获取笑话的类别。
|
| 模板灵活性 | 控制器只需要提供一个笑话列表,模板可以根据需要读取任何信息,包括作者信息。如果数据库中添加了新的列,我们可以直接在模板中显示该值,而不需要修改控制器。 |
13. 可能遇到的问题及解决方案
在使用实体类优化数据库数据处理的过程中,可能会遇到一些问题。以下是一些常见问题及解决方案:
| 问题 | 解决方案 |
|---|---|
| 依赖循环 |
使用引用(reference)来解决
authorsTable
和
jokesTable
实例化时的依赖问题。
|
| 模板语法错误 |
确保在模板中使用正确的对象访问语法,例如将
$joke['joketext']
改为
$joke->joketext
。
|
| 方法调用错误 | 确保实体类中定义了所需的方法,并且在调用时使用正确的方法名和参数。 |
14. 进一步优化建议
虽然我们已经对代码进行了优化,但仍然有一些可以进一步改进的地方。
- 缓存机制 :在获取作者信息时,可以考虑使用缓存机制,避免频繁的数据库查询。例如,使用 Redis 缓存作者信息,当需要获取作者信息时,先从缓存中查找,如果缓存中不存在,再从数据库中查询。
-
错误处理
:在实体类的方法中添加更完善的错误处理机制,例如在
getAuthor方法中,如果数据库查询失败,应该返回一个默认值或者抛出一个自定义的异常。 -
代码复用
:可以将一些通用的方法提取到基类中,提高代码的复用性。例如,创建一个
Entity基类,将一些通用的方法(如getProperty、setProperty等)放在基类中,让Author和Joke类继承该基类。
15. 总结与展望
通过本文的介绍,我们学习了如何使用实体类来优化数据库数据处理,从数组到实体类的转变,以及如何解决依赖问题和更新模板。这些优化措施提高了代码的可读性、可维护性和扩展性,使开发过程更加高效。
在未来的开发中,我们可以继续探索更多的优化方法,如使用缓存机制、完善错误处理和提高代码复用性等。同时,我们也可以将这些优化方法应用到其他项目中,提高项目的整体质量。
流程图
graph TD;
A[开始] --> B[理解引用作用];
B --> C[分析优化后代码优势];
C --> D[解决可能遇到的问题];
D --> E[提出进一步优化建议];
E --> F[总结与展望];
F --> G[结束];
操作步骤总结
- 理解引用的概念和作用,使用引用解决依赖循环问题。
- 分析优化后代码的优势,包括提高可读性、可维护性和扩展性等。
- 识别可能遇到的问题,并采取相应的解决方案。
- 提出进一步的优化建议,如缓存机制、错误处理和代码复用等。
- 总结优化过程,展望未来的开发方向。
通过以上步骤,我们可以更好地掌握使用实体类优化数据库数据处理的方法,提高代码的质量和开发效率。
超级会员免费看
1318

被折叠的 条评论
为什么被折叠?



