在之前的小实践中我们通过了解 PDO
完成了对数据库中表数据的读取显示。
接下来,会对之前的业务代码进行也重构优化,让程序结构更为清晰。
回顾
原先的 index.php
:
// index.php
<?php
require 'functions.php';
require 'Task.php';
$pdo = connectToDb();
$tasks = fetchAllTasks($pdo);
require "index.view.php";
在 functions.php
中定义了相应的函数:
-
connectToDb
用于连接数据库 -
fetchAllTasks
则是读取表中的数据
// functions.php
<?php
function connectToDb()
{
try {
return new PDO('mysql:host=127.0.0.1;dbname=mytodo', 'root', '');
} catch (PDOException $e) {
die('Could not connect.');
}
}
function fetchAllTasks($pdo)
{
$statement = $pdo->prepare('select * from todos');
$statement->execute();
return $statement->fetchAll(PDO::FETCH_OBJ);
}
function dd($data)
{
echo '<pre>';
die(var_dump($data));
echo '</pre>';
}
而 Task.php
这个类用于映射表中的行数据。
// Task.php
<?php
class Task
{
public $description;
public $completed;
}
页面呈现部分 index.view.php
是这样:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<ul>
<?php foreach ($tasks as $task) : ?>
<li>
<?php if ($task->completed) : ?>
<strike><?= $task->description; ?></strike>
<?php else: ?>
<?= $task->description; ?>
<?php endif; ?>
</li>
<?php endforeach; ?>
</ul>
</body>
</html>
重构代码
我们主要重构 index.php
中的业务逻辑:连接数据库,读取表中数据。
在项目目录下新建 database/Connection.php
文件,内容如下:
// databases/Connection.php
<?php
class Connection
{
public static function make()
{
try {
return new PDO('mysql:host=127.0.0.1;dbname=mytodo', 'root', '');
} catch (PDOException $e) {
die($e->getMessage());
}
}
}
这里将连接数据库封装到了名为 Connection
的类中,通过静态方法 make
来执行连接数据库的操作,try ... catch ...
代码块的作用是为了捕获连接数据库中存在的异常错误,出现错误则终止程序。
通过 make
方法成功执行后将会返回一个 PDO
的数据库连接实例。
了解更多有关 PHP 异常的信息,请查看 这里。
接下来,在项目目录下新建 database/QueryBuilder.php
,内容:
// database/QueryBuilder.php
<?php
class QueryBuilder
{
protected $pdo;
public function __construct($pdo)
{
$this->pdo = $pdo;
}
public function selectAll($table)
{
$statement = $this->pdo->prepare("select * from {$table}");
$statement->execute();
return $statement->fetchAll(PDO::FETCH_CLASS);
}
}
这是一个用于构建数据库查询语句的类,有个 selectAll
方法,这个类依赖一个 PDO
连接实例,类的构函数中传入的参数说明了这一点。selectAll
将会返回查询结果。
由于我们将 functions.php
中的代码进行了重构,重新定义了 Conneciton
和 QueryBuilder
类,引入这个文件也没有必要,同时,我们的读取的数据表信息以 Class
形式返回,如下:
object(stdClass)#4 (3) {
["id"]=>
string(1) "1"
["description"]=>
string(21) "Finish the screencast"
["completed"]=>
string(1) "1"
}
因此,Task.php
也可以去掉了。
调整后 index.php
如下:
// index.php
<?php
require 'database/Connection.php';
require 'database/QueryBuilder.php';
$pdo = Connection::make();
$query = new QueryBuilder($pdo);
$tasks = $query->selectAll('todos');
require "index.view.php";
运行程序刷新页面,程序显示的结果和重构之前一样。
还可以做得更好
我们可以将连接数据库,查构建数据库查询认为是程序启动项。所以,我们可以进一步的优化这一部分。
项目目录下新建 bootstrap.php
:
// bootstrap.php
<?php
require 'database/Connection.php';
require 'database/QueryBuilder.php';
return new QueryBuilder(
Connection::make()
);
没错,我们将数据库相关的类引入和实例化放到了一起。这样我们 index.php
将关注读取特定的表数据。
最终 index.php
如下:
// index.php
<?php
$database = require 'bootstrap.php';
$tasks = $database->selectAll('todos');
require "index.view.php";
刷新页面,程序依旧能按照我们的预期结果运行。
但是最终,重构让程序结构变得更加清晰了不是吗?