Mặc dù không có quá nhiều lý do để tạo một trình bao bọc [vì PDO đã là một trình bao bọc], nhưng vẫn có một số vấn đề có thể gây lỗi cho lập trình viên
Vấn đề #1, dài dòng
Vấn đề chính với cả câu lệnh chuẩn bị PDO và mysqli là cơ chế được thiết kế để thực hiện nhiều lần, khi
5 và
$data = $pdo->prepare[$sql]->execute[$params]->fetch[];
6 chỉ được gọi một lần và sau đó
$data = $pdo->prepare[$sql]->execute[$params]->fetch[];
7 được gọi nhiều lần với các bộ dữ liệu khác nhau. Đó là lý do tại sao mã quá dài dòng
$data = $pdo->prepare[$sql]->execute[$params]->fetch[];
Tuy nhiên, trong thực tế, việc thực thi nhiều lần hiếm khi được sử dụng, trong khi hầu hết các câu lệnh chuẩn bị sẵn chỉ được sử dụng để thực hiện truy vấn một lần. Kết quả là, đối với mỗi truy vấn đơn lẻ, chúng tôi buộc phải viết đi viết lại cùng một quy trình lặp đi lặp lại
$stmt = $pdo->prepare["SELECT * FROM users WHERE sex=?"];
$stmt->execute[[$sex]];
$data = $stmt->fetchAll[];
Sẽ tốt hơn nếu
$data = $pdo->prepare[$sql]->execute[$params]->fetch[];
8 trả về câu lệnh, cho phép xâu chuỗi phương thức gọn gàng$data = $pdo->prepare[$sql]->execute[$params]->fetch[];
Nhưng than ôi -
$data = $pdo->prepare[$sql]->execute[$params]->fetch[];
8 đang trả về một giá trị booleanDù bằng cách nào, ngay cả cách tiếp cận như vậy cũng sẽ không cần thiết trong hầu hết thời gian, vì chúng ta không cần các cuộc gọi chuẩn bị và thực hiện riêng biệt
Để giải quyết sự bất tiện này, sẽ là một ý kiến hay nếu có một chức năng tương tự như Postgres'
function pdo[$pdo, $sql, $args = NULL]
{
if [!$args]
{
return $pdo->query[$sql];
}
$stmt = $pdo->prepare[$sql];
$stmt->execute[$args];
return $stmt;
}
0 để đóng gói thủ tục chuẩn bị/thực thi và trả về câu lệnhMột chức năng PDO đơn giản
Giải pháp đơn giản nhất là tạo một hàm chấp nhận một đối tượng PDO, một truy vấn SQL và một mảng tùy chọn với các tham số cho exec[] và trả về một đối tượng
function pdo[$pdo, $sql, $args = NULL]
{
if [!$args]
{
return $pdo->query[$sql];
}
$stmt = $pdo->prepare[$sql];
$stmt->execute[$args];
return $stmt;
}
1function pdo[$pdo, $sql, $args = NULL]
{
if [!$args]
{
return $pdo->query[$sql];
}
$stmt = $pdo->prepare[$sql];
$stmt->execute[$args];
return $stmt;
}
Nó sẽ phục vụ nếu mã của bạn chủ yếu là thủ tục. Do bạn có thể xâu chuỗi bất kỳ phương thức
function pdo[$pdo, $sql, $args = NULL]
{
if [!$args]
{
return $pdo->query[$sql];
}
$stmt = $pdo->prepare[$sql];
$stmt->execute[$args];
return $stmt;
}
1 nào trực tiếp vào lệnh gọi của hàm này, hầu hết các truy vấn sẽ chỉ trở thành một lớp lót
// getting the number of rows in the table
$count = pdo[$pdo, "SELECT count[*] FROM users"]->fetchColumn[];// the user data based on email
$user = pdo[$pdo, "SELECT * FROM users WHERE email=?", [$email]]->fetch[];// getting many rows from the table
$data = pdo[$pdo, "SELECT * FROM users WHERE salary > ?", [$salary]]->fetchAll[];// getting the number of affected rows from DELETE/UPDATE/INSERT
$deleted = pdo[$pdo, "DELETE FROM users WHERE id=?", [$id]]->rowCount[];// insert
pdo[$pdo, "INSERT INTO users VALUES [null, ?,?,?]", [$name, $email, $password]];// named placeholders are also welcome though I find them a bit too verbose
pdo[$pdo, "UPDATE users SET name=:name WHERE id=:id", ['id'=>$id, 'name'=>$name]];
// using a sophisticated fetch mode, indexing the returned array by id
$indexed = pdo[$pdo, "SELECT id, name FROM users"]->fetchAll[PDO::FETCH_KEY_PAIR];
Một lớp PDO đơn giản
Tuy nhiên, bước tiếp theo sẽ là tạo một lớp chứa tất cả mã kết nối PDO, cũng như hàm hữu ích
function pdo[$pdo, $sql, $args = NULL]
{
if [!$args]
{
return $pdo->query[$sql];
}
$stmt = $pdo->prepare[$sql];
$stmt->execute[$args];
return $stmt;
}
3. Lưu ý rằng vì mục đích sử dụng, lớp này chỉ có thể được sử dụng với cơ sở dữ liệu mysql
class DB
{
public $pdo;public function __construct[$db, $username = NULL, $password = NULL, $host = '127.0.0.1', $port = 3306, $options = []]
{
$default_options = [
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
];
$options = array_replace[$default_options, $options];
$dsn = "mysql:host=$host;dbname=$db;port=$port;charset=utf8mb4";
try {
$this->pdo = new \PDO[$dsn, $username, $password, $options];
} catch [\PDOException $e] {
throw new \PDOException[$e->getMessage[], [int]$e->getCode[]];
}
}
public function run[$sql, $args = NULL]
{
if [!$args]
{
return $this->pdo->query[$sql];
}
$stmt = $this->pdo->prepare[$sql];
$stmt->execute[$args];
return $stmt;
}
}
Bây giờ lớp này có thể được bao gồm trong tất cả các lớp khác dưới dạng tham số hàm tạo trong tất cả các lớp khác yêu cầu tương tác cơ sở dữ liệu. Lưu ý rằng biến PDO được đặt ở chế độ công khai. Đó là bởi vì chúng tôi sẽ cần truy cập chức năng PDO đầy đủ thông qua biến này
Để sử dụng lớp này, trước tiên hãy tạo một thể hiện, như thế này
$db = new DB[$dbname, $user, $password];
và sau đó được sử dụng giống như chức năng nhưng thay vì khá vụng về
function pdo[$pdo, $sql, $args = NULL]
{
if [!$args]
{
return $pdo->query[$sql];
}
$stmt = $pdo->prepare[$sql];
$stmt->execute[$args];
return $stmt;
}
4, chúng ta có thể viết nó thành function pdo[$pdo, $sql, $args = NULL]
{
if [!$args]
{
return $pdo->query[$sql];
}
$stmt = $pdo->prepare[$sql];
$stmt->execute[$args];
return $stmt;
}
5$db->run["INSERT INTO users VALUES [null, ?,?,?]", [$name, $email, $password]];
$id = $db->pdo->lastInsertId[];
Mở rộng PDO
Một cách khác để truy cập chức năng PDO đầy đủ là mở rộng đối tượng của chúng ta từ PDO
Hãy mở rộng PDO và thêm một phương thức mới có tên là
function pdo[$pdo, $sql, $args = NULL]
{
if [!$args]
{
return $pdo->query[$sql];
}
$stmt = $pdo->prepare[$sql];
$stmt->execute[$args];
return $stmt;
}
3 [vì tôi thích đặt tên ngắn hơn cho các hàm thường được gọi]. Ngoài ra, để thuận tiện, chúng ta có thể thêm các tùy chọn kết nối cần thiết nhất vào hàm tạoclass MyPDO extends PDO
{
public function __construct[$dsn, $username = NULL, $password = NULL, $options = []]
{
$default_options = [
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
];
$options = array_replace[$default_options, $options];
parent::__construct[$dsn, $username, $password, $options];
}
public function run[$sql, $args = NULL]
{
if [!$args]
{
return $this->query[$sql];
}
$stmt = $this->prepare[$sql];
$stmt->execute[$args];
return $stmt;
}
}
và bây giờ chúng tôi đã có một lớp MyPDO mới hoạt động như PDO cũ theo bất kỳ cách nào tiết kiệm cho việc bổ sung một phương thức mới cho phép chúng tôi chạy một truy vấn đã chuẩn bị trong một cuộc gọi
$data = $pdo->run["SELECT * FROM users WHERE sex=?",[$sex]]->fetchAll[];
Ngoài ra, chúng tôi chỉ bao gồm các tùy chọn cấu hình hữu ích nhất theo mặc định, mặc dù chúng có thể bị ghi đè
Vấn đề #2, tính khả dụng
Một vấn đề khác là tính khả dụng của phiên bản PDO. Cũng giống như bất kỳ biến nào khác, nó bị ràng buộc với phạm vi của nó và theo mặc định không có sẵn trong bất kỳ hàm hoặc phương thức nào của lớp. Có thể có cách tiếp cận để giải quyết vấn đề này. Hãy xem xét một số trong số họ
Cách OOP thực sự
Để đơn giản, Dependency injection là viết tắt của việc chuyển tất cả các dịch vụ cần thiết thông qua hàm tạo của lớp
Vì vậy, nếu mã của bạn là hướng đối tượng, thì bạn có thể sử dụng giải pháp lớp MyPDO ở trên, chuyển thể hiện của nó xung quanh bằng cách sử dụng hàm tạo của các lớp khác
class User
{
/* @var MyPDO */
protected $db;protected $data;
public function __construct[MyPDO $db]
{
$this->db = $db;
}public function find[$id]
{
$this->data = $this->db->run["SELECT * FROM users WHERE id = ?", [$id]]->fetch[];
}
}
Và sau đó sử dụng nó theo cách này
$data = $pdo->prepare[$sql]->execute[$params]->fetch[];
0Lưu ý rằng phương pháp này sẽ hoạt động miễn là tất cả các lớp của bạn được khởi tạo thủ công. Trong trường hợp một số lớp được khởi tạo động, bạn sẽ cần một Bộ chứa tiêm phụ thuộc, nó sẽ lưu trữ một thể hiện duy nhất của lớp kết nối cơ sở dữ liệu và đưa nó vào tất cả các lớp đã tạo nếu chúng cần
Giải pháp tĩnh cho Mã hướng đối tượng
Nhưng trong một mã được tổ chức kém, thật khó để vượt qua phiên bản cơ sở dữ liệu theo cách này. Đối với điều này, có một sự đánh đổi giữa cách đúng đắn và một kẻ độc thân cùn. một lớp có thể trả về thể hiện của nó thông qua một hàm tĩnh
$data = $pdo->prepare[$sql]->execute[$params]->fetch[];
1Vì vậy, bây giờ chúng ta có thể thay đổi lớp
function pdo[$pdo, $sql, $args = NULL]
{
if [!$args]
{
return $pdo->query[$sql];
}
$stmt = $pdo->prepare[$sql];
$stmt->execute[$args];
return $stmt;
}
7 theo cách này$data = $pdo->prepare[$sql]->execute[$params]->fetch[];
2Nó sẽ kém linh hoạt hơn trong trường hợp bạn sẽ cần các nhà cung cấp cơ sở dữ liệu khác nhau cho các phiên bản Người dùng khác nhau nhưng ít nhất nó đang sử dụng biến lớp
function pdo[$pdo, $sql, $args = NULL]
{
if [!$args]
{
return $pdo->query[$sql];
}
$stmt = $pdo->prepare[$sql];
$stmt->execute[$args];
return $stmt;
}
8 tập trungSingleton cùn, cho mã thủ tục của bạn
Nếu bạn đến đây chỉ để tìm kiếm sự thay thế cho hàm mysql_query cũ tốt sẽ được sử dụng trong mã tất cả thủ tục của mình, bạn có thể sử dụng mẫu Singleton bị coi thường
$data = $pdo->prepare[$sql]->execute[$params]->fetch[];
3chỉ cần đặt mã này vào tệp có tên, chẳng hạn như,
function pdo[$pdo, $sql, $args = NULL]
{
if [!$args]
{
return $pdo->query[$sql];
}
$stmt = $pdo->prepare[$sql];
$stmt->execute[$args];
return $stmt;
}
9, đặt nó ở đâu đó trong trang web của bạn và đừng quên đưa nó vào bất cứ nơi nào bạn cần cơ sở dữ liệuví dụ
Các ví dụ dưới đây chứng minh việc sử dụng phương pháp đơn lẻ ở trên. Mã đã sẵn sàng để sử dụng. Bạn có thể sao chép và dán mã bên dưới và chạy nó như bình thường. Chỉ cần đừng quên tạo một 'cơ sở dữ liệu. php' từ chương trên