Php có điều kiện bao gồm

Đã có rất nhiều hướng dẫn về PDO, nhưng thật không may, hầu hết chúng không giải thích được lợi ích thực sự của PDO, hoặc thậm chí khuyến khích các thực hành khá tồi. Hai ngoại lệ duy nhất là phptherightway. com và hashphp. org, nhưng họ bỏ lỡ rất nhiều thông tin quan trọng. Kết quả là, một nửa số tính năng của PDO vẫn chưa được biết đến và hầu như không bao giờ được sử dụng bởi các nhà phát triển PHP, những người luôn cố gắng phát minh lại bánh xe đã tồn tại trong PDO

Không giống như những hướng dẫn đó, hướng dẫn này được viết bởi một người đã sử dụng PDO trong nhiều năm, tìm hiểu kỹ về nó và trả lời hàng nghìn câu hỏi trên Stack Overflow (người mang huy hiệu PDO vàng duy nhất). Theo sứ mệnh của trang web này, bài viết này sẽ bác bỏ những ảo tưởng và thực hành xấu khác nhau, đồng thời chỉ ra cách đúng đắn

Mặc dù hướng dẫn này dựa trên trình điều khiển mysql, nhưng nói chung, thông tin này có thể áp dụng cho bất kỳ trình điều khiển nào được hỗ trợ

Tại sao PDO?

điều đầu tiên đầu tiên. Tại sao lại là PDO?

PDO là Lớp trừu tượng truy cập cơ sở dữ liệu. Sự trừu tượng, tuy nhiên, là gấp đôi. một cái được biết đến rộng rãi nhưng ít quan trọng hơn, trong khi một cái khác ít người biết đến nhưng quan trọng nhất

Mọi người đều biết rằng PDO cung cấp giao diện hợp nhất để truy cập nhiều cơ sở dữ liệu khác nhau. Mặc dù bản thân tính năng này rất tuyệt vời, nhưng nó không tạo ra vấn đề lớn đối với ứng dụng cụ thể, nơi chỉ có một phụ trợ cơ sở dữ liệu được sử dụng. Và, bất chấp một số tin đồn, không thể chuyển đổi phụ trợ cơ sở dữ liệu bằng cách thay đổi một dòng trong cấu hình PDO - do các hương vị SQL khác nhau (để làm như vậy, người ta cần sử dụng ngôn ngữ truy vấn trung bình như DQL). Do đó, đối với nhà phát triển LAMP bình thường, điểm này không đáng kể và đối với anh ta, PDO chỉ là một phiên bản phức tạp hơn của hàm

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
2 quen thuộc. Tuy nhiên, không phải vậy;

PDO tóm tắt không chỉ API cơ sở dữ liệu mà còn cả các hoạt động cơ bản phải lặp lại hàng trăm lần trong mọi ứng dụng, khiến mã của bạn cực kỳ ƯỚT. Không giống như mysql và mysqli, cả hai đều là API trần cấp thấp không nhằm mục đích sử dụng trực tiếp (mà chỉ làm vật liệu xây dựng cho một số lớp trừu tượng cấp cao hơn),

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
3 đã là một sự trừu tượng như vậy rồi. Mặc dù vẫn chưa hoàn thiện, nhưng ít nhất có thể sử dụng được

Những lợi ích PDO thực sự là

  • bảo mật (các câu lệnh được chuẩn bị sẵn có thể sử dụng được)
  • khả năng sử dụng (nhiều chức năng trợ giúp để tự động hóa các hoạt động thường ngày)
  • khả năng sử dụng lại (API hợp nhất để truy cập vô số cơ sở dữ liệu, từ SQLite đến Oracle)

Lưu ý rằng mặc dù PDO là trình điều khiển db gốc tốt nhất, nhưng đối với ứng dụng web hiện đại, hãy xem xét sử dụng ORM với Trình tạo truy vấn hoặc bất kỳ thư viện trừu tượng cấp cao nào khác, chỉ thỉnh thoảng dự phòng cho vanilla PDO. Các ORM tốt là Doctrine, Eloquent, RedBean và Yii. thực tế tăng cường. hào quang. SQL là một ví dụ điển hình về trình bao bọc PDO với nhiều tính năng bổ sung

Dù bằng cách nào, thật tốt khi biết các công cụ cơ bản trước. Vì vậy, chúng ta hãy bắt đầu

Đang kết nối. DSN

PDO có một phương thức kết nối ưa thích được gọi là DSN. Mặc dù vậy, không có gì phức tạp - thay vì một danh sách tùy chọn đơn giản và đơn giản, PDO yêu cầu bạn nhập các chỉ thị cấu hình khác nhau ở ba vị trí khác nhau

  • $sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
    4,
    $sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
    5,
    $sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
    6 và
    $sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
    7, cũng như
    $sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
    8 và
    $sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
    9 ít được sử dụng hơn đi vào DSN;
  • $stmt = $pdo->prepare('SELECT * FROM users WHERE email = ? AND status=?');
    $stmt->execute([$email, $status]);
    $user = $stmt->fetch();
    // or
    $stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email AND status=:status');
    $stmt->execute(['email' => $email, 'status' => $status]);
    $user = $stmt->fetch();
    0 và
    $stmt = $pdo->prepare('SELECT * FROM users WHERE email = ? AND status=?');
    $stmt->execute([$email, $status]);
    $user = $stmt->fetch();
    // or
    $stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email AND status=:status');
    $stmt->execute(['email' => $email, 'status' => $status]);
    $user = $stmt->fetch();
    1 đi đến nhà xây dựng;
  • tất cả các tùy chọn khác đi vào mảng tùy chọn

trong đó DSN là một chuỗi được phân cách bằng dấu chấm phẩy, bao gồm các cặp

$stmt = $pdo->prepare('SELECT * FROM users WHERE email = ? AND status=?');
$stmt->execute([$email, $status]);
$user = $stmt->fetch();
// or
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email AND status=:status');
$stmt->execute(['email' => $email, 'status' => $status]);
$user = $stmt->fetch();
2, bắt đầu từ tên trình điều khiển và dấu hai chấm

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
1

Lưu ý rằng điều quan trọng là phải tuân theo định dạng thích hợp - không được sử dụng dấu cách hoặc dấu ngoặc kép hoặc cách trang trí khác trong DSN mà chỉ được sử dụng các tham số, giá trị và dấu phân cách, như được trình bày trong sách hướng dẫn

Đây là một ví dụ cho mysql

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
2

Với tất cả các biến đã nói ở trên được đặt đúng cách, chúng ta sẽ có phiên bản PDO thích hợp trong biến

$stmt = $pdo->prepare('SELECT * FROM users WHERE email = ? AND status=?');
$stmt->execute([$email, $status]);
$user = $stmt->fetch();
// or
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email AND status=:status');
$stmt->execute(['email' => $email, 'status' => $status]);
$user = $stmt->fetch();
3

Lưu ý quan trọng cho người dùng tiện ích mở rộng mysql muộn

  1. Không giống như các hàm
    $stmt = $pdo->prepare('SELECT * FROM users WHERE email = ? AND status=?');
    $stmt->execute([$email, $status]);
    $user = $stmt->fetch();
    // or
    $stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email AND status=:status');
    $stmt->execute(['email' => $email, 'status' => $status]);
    $user = $stmt->fetch();
    4 cũ, có thể được sử dụng ở bất kỳ đâu trong mã, đối tượng
    $sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
    3 được lưu trữ trong một biến thông thường, có nghĩa là nó không thể truy cập được bên trong các hàm - vì vậy, người ta phải làm cho nó có thể truy cập được, bằng cách chuyển nó qua các tham số hàm hoặc
  2. Kết nối chỉ được thực hiện một lần. Không có kết nối trong mọi chức năng. Không có kết nối trong mọi hàm tạo của lớp. Nếu không, nhiều kết nối sẽ được tạo, điều này cuối cùng sẽ giết chết máy chủ cơ sở dữ liệu của bạn. Do đó, một phiên bản PDO duy nhất phải được tạo và sau đó được sử dụng thông qua toàn bộ quá trình thực thi tập lệnh
  3. Điều rất quan trọng là đặt bộ ký tự thông qua DSN - đó là cách thích hợp duy nhất vì nó cho PDO biết bộ ký tự nào sẽ được sử dụng. Do đó, hãy quên việc chạy truy vấn
    $stmt = $pdo->prepare('SELECT * FROM users WHERE email = ? AND status=?');
    $stmt->execute([$email, $status]);
    $user = $stmt->fetch();
    // or
    $stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email AND status=:status');
    $stmt->execute(['email' => $email, 'status' => $status]);
    $user = $stmt->fetch();
    6 theo cách thủ công, thông qua
    $stmt = $pdo->prepare('SELECT * FROM users WHERE email = ? AND status=?');
    $stmt->execute([$email, $status]);
    $user = $stmt->fetch();
    // or
    $stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email AND status=:status');
    $stmt->execute(['email' => $email, 'status' => $status]);
    $user = $stmt->fetch();
    7 hoặc
    $stmt = $pdo->prepare('SELECT * FROM users WHERE email = ? AND status=?');
    $stmt->execute([$email, $status]);
    $user = $stmt->fetch();
    // or
    $stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email AND status=:status');
    $stmt->execute(['email' => $email, 'status' => $status]);
    $user = $stmt->fetch();
    8. Chỉ khi phiên bản PHP của bạn quá lỗi thời (cụ thể là dưới 5. 3. 6), bạn phải sử dụng truy vấn
    $stmt = $pdo->prepare('SELECT * FROM users WHERE email = ? AND status=?');
    $stmt->execute([$email, $status]);
    $user = $stmt->fetch();
    // or
    $stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email AND status=:status');
    $stmt->execute(['email' => $email, 'status' => $status]);
    $user = $stmt->fetch();
    6 và luôn tắt chế độ mô phỏng

Bạn có thể tìm thêm chi tiết về Mysql trong chương tương ứng, Kết nối với MySQL

Chạy truy vấn. PDO. truy vấn()

Có hai cách để chạy truy vấn trong PDO. Nếu không có biến nào sẽ được sử dụng trong truy vấn, bạn có thể sử dụng PDO. phương thức truy vấn (). Nó sẽ chạy truy vấn của bạn và trả về đối tượng đặc biệt của lớp PDOStatement có thể được so sánh gần đúng với tài nguyên, được trả về bởi

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
00, đặc biệt là theo cách bạn có thể lấy các hàng thực tế từ nó

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
1

Ngoài ra, phương thức

$stmt = $pdo->prepare('SELECT * FROM users WHERE email = ? AND status=?');
$stmt->execute([$email, $status]);
$user = $stmt->fetch();
// or
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email AND status=:status');
$stmt->execute(['email' => $email, 'status' => $status]);
$user = $stmt->fetch();
7 cho phép chúng ta sử dụng một chuỗi phương thức gọn gàng cho các truy vấn CHỌN, sẽ được hiển thị bên dưới

báo cáo chuẩn bị. Bảo vệ khỏi việc tiêm SQL

Đây là lý do chính và quan trọng duy nhất khiến bạn bị tước chức năng

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
00 yêu quý của mình và bị ném vào thế giới khắc nghiệt của Đối tượng dữ liệu. PDO đã chuẩn bị sẵn các câu lệnh hỗ trợ sẵn có. Câu lệnh đã chuẩn bị là cách thích hợp duy nhất để chạy truy vấn, nếu bất kỳ biến nào sẽ được sử dụng trong đó. Lý do tại sao nó lại quan trọng như vậy được giải thích chi tiết trong Hướng dẫn phòng chống SQL injection của The Hitchhiker's

Vì vậy, đối với mọi truy vấn bạn chạy, nếu ít nhất một biến sẽ được sử dụng, bạn phải thay thế nó bằng một trình giữ chỗ, sau đó chuẩn bị truy vấn của bạn rồi thực hiện nó, chuyển các biến riêng biệt

Tóm lại, nó không khó như vẻ ngoài của nó. Trong hầu hết các trường hợp, bạn chỉ cần hai chức năng - chuẩn bị() và thực thi()

Trước hết, bạn phải thay đổi truy vấn của mình, thêm các trình giữ chỗ thay cho các biến. Nói, một mã như thế này

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
4

sẽ trở thành

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
5

hoặc

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';

Lưu ý rằng PDO hỗ trợ các trình giữ chỗ vị trí (

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
03) và được đặt tên (
$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
04), cái sau luôn bắt đầu từ dấu hai chấm và chỉ có thể được viết bằng các chữ cái, chữ số và dấu gạch dưới. Cũng lưu ý rằng không có trích dẫn nào được sử dụng xung quanh trình giữ chỗ

Có một truy vấn với trình giữ chỗ, bạn phải chuẩn bị nó, sử dụng phương thức

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
05. Hàm này sẽ trả về cùng một đối tượng
$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
06 mà chúng ta đã nói ở trên, nhưng không có bất kỳ dữ liệu nào được đính kèm với nó

Cuối cùng, để thực thi truy vấn, bạn phải chạy phương thức

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
07 của đối tượng này, truyền các biến vào đó, ở dạng mảng. Và sau đó, bạn sẽ có thể lấy dữ liệu kết quả ra khỏi câu lệnh (nếu có)

________số 8

Như bạn có thể thấy, đối với các trình giữ chỗ vị trí, bạn phải cung cấp một mảng thông thường với các giá trị, trong khi đối với các trình giữ chỗ được đặt tên, nó phải là một mảng kết hợp, trong đó các khóa phải khớp với các tên trình giữ chỗ trong truy vấn. Bạn không thể kết hợp các trình giữ chỗ theo vị trí và được đặt tên trong cùng một truy vấn

Xin lưu ý rằng các trình giữ chỗ theo vị trí cho phép bạn viết mã ngắn hơn, nhưng nhạy cảm với thứ tự của các đối số (phải giống hệt như thứ tự của các trình giữ chỗ tương ứng trong truy vấn). Mặc dù các trình giữ chỗ được đặt tên làm cho mã của bạn dài dòng hơn, nhưng chúng cho phép thứ tự ràng buộc ngẫu nhiên

Cũng lưu ý rằng mặc dù ảo tưởng phổ biến, nhưng không cần "

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
08" trong các phím

Sau khi thực hiện, bạn có thể bắt đầu lấy dữ liệu của mình, sử dụng tất cả các phương pháp được hỗ trợ, như được mô tả trong bài viết này

Nhiều ví dụ có thể được tìm thấy trong bài viết tương ứng

phương pháp ràng buộc

Truyền dữ liệu vào

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
07 (như được hiển thị ở trên) nên được coi là phương pháp mặc định và thuận tiện nhất. Khi phương thức này được sử dụng, tất cả các giá trị sẽ được liên kết dưới dạng chuỗi (lưu giá trị
$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
50, giá trị này sẽ được gửi đến truy vấn như hiện tại, tôi. e. như SQL
$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
50), nhưng hầu hết thời gian đều ổn và sẽ không gây ra vấn đề gì

Tuy nhiên, đôi khi tốt hơn là đặt loại dữ liệu một cách rõ ràng. Các trường hợp có thể xảy ra là

  • Mệnh đề GIỚI HẠN (hoặc bất kỳ mệnh đề SQL nào khác không thể chấp nhận toán hạng chuỗi) nếu chế độ mô phỏng được BẬT
  • các truy vấn phức tạp với kế hoạch truy vấn không tầm thường có thể bị ảnh hưởng bởi loại toán hạng sai
  • các loại cột đặc biệt, như
    $sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
    52 hoặc
    $sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
    53 yêu cầu toán hạng của loại chính xác được ràng buộc (lưu ý rằng để ràng buộc một giá trị BIGINT với PDO. PARAM_INT bạn cần cài đặt dựa trên mysqlnd)

Trong trường hợp như vậy, ràng buộc rõ ràng phải được sử dụng, mà bạn có thể lựa chọn hai hàm, bindValue() và bindParam(). Cái trước phải được ưu tiên hơn, bởi vì, không giống như

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
54, nó không có tác dụng phụ để giải quyết

Truy vấn các phần bạn có thể liên kết

Điều rất quan trọng là phải hiểu phần truy vấn nào bạn có thể liên kết bằng cách sử dụng câu lệnh đã chuẩn bị và phần nào bạn không thể. Trên thực tế, danh sách này quá ngắn. chỉ chuỗi và chữ số có thể được ràng buộc. Vì vậy, bạn có thể nói rằng miễn là dữ liệu của bạn có thể được biểu diễn trong truy vấn dưới dạng số hoặc chuỗi ký tự được trích dẫn - nó có thể bị ràng buộc. Đối với tất cả các trường hợp khác, bạn hoàn toàn không thể sử dụng các câu lệnh đã chuẩn bị PDO. không phải là mã định danh hoặc danh sách được phân tách bằng dấu phẩy hoặc một phần của chuỗi ký tự được trích dẫn hoặc bất kỳ phần truy vấn tùy ý nào khác không thể bị ràng buộc bằng cách sử dụng câu lệnh đã chuẩn bị

Cách giải quyết cho các trường hợp sử dụng thường xuyên nhất có thể được tìm thấy trong phần tương ứng của bài viết

báo cáo chuẩn bị. Nhiều lần thực hiện

Đôi khi bạn có thể sử dụng các câu lệnh đã chuẩn bị để thực hiện nhiều truy vấn đã chuẩn bị. Nó nhanh hơn một chút so với việc thực hiện lặp đi lặp lại cùng một truy vấn, vì nó chỉ phân tích cú pháp truy vấn một lần. Tính năng này sẽ hữu ích hơn nếu có thể thực thi một câu lệnh được chuẩn bị trong một phiên bản PHP khác. Nhưng than ôi - nó không phải là. Vì vậy, bạn bị giới hạn chỉ lặp lại cùng một truy vấn trong cùng một phiên bản, điều này hiếm khi cần thiết trong các tập lệnh PHP thông thường và điều này hạn chế việc sử dụng tính năng này đối với các lần chèn hoặc cập nhật lặp lại

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
0

Lưu ý rằng tính năng này được đánh giá cao một chút. Nó không chỉ hiếm khi được đề cập đến, mà hiệu suất đạt được cũng không lớn - việc phân tích cú pháp truy vấn hiện nay thực sự nhanh chóng

Lưu ý rằng bạn chỉ có thể nhận được lợi thế này khi tắt chế độ mô phỏng

Chạy các câu lệnh SELECT INSERT, UPDATE hoặc DELETE

cố lên mọi người. Hoàn toàn không có gì đặc biệt trong các truy vấn này. Đối với PDO, tất cả đều giống nhau. Không quan trọng bạn đang chạy truy vấn nào

Giống như đã trình bày ở trên, điều bạn cần là chuẩn bị một truy vấn với các trình giữ chỗ, sau đó thực hiện truy vấn đó, gửi các biến một cách riêng biệt. Đối với truy vấn

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
55 và
$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
56, quy trình về cơ bản là giống nhau. Sự khác biệt duy nhất là (vì các truy vấn DML không trả về bất kỳ dữ liệu nào), bạn có thể sử dụng chuỗi phương thức và do đó gọi ngay
$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
07 cùng với
$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
58

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
5

Tuy nhiên, nếu bạn muốn lấy số lượng hàng bị ảnh hưởng, mã sẽ phải giống nhau ba dòng

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
6

Nhiều ví dụ có thể được tìm thấy trong bài viết tương ứng

Lấy dữ liệu ra khỏi câu lệnh. cho mỗi()

Cách cơ bản và trực tiếp nhất để lấy nhiều hàng từ một câu lệnh là vòng lặp

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
59. Nhờ giao diện Traversable, có thể lặp lại
$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
06 bằng cách sử dụng toán tử
$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
59

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
20

Lưu ý rằng phương pháp này thân thiện với bộ nhớ, vì nó không tải tất cả các hàng kết quả trong bộ nhớ mà cung cấp từng hàng một (mặc dù hãy ghi nhớ vấn đề này)

Lấy dữ liệu ra khỏi câu lệnh. tìm về()

Chúng ta đã thấy chức năng này rồi, nhưng hãy xem xét kỹ hơn. Nó tìm nạp một hàng từ cơ sở dữ liệu và di chuyển con trỏ bên trong trong tập kết quả, do đó, các cuộc gọi tiếp theo đến hàm này sẽ trả về tất cả các hàng kết quả từng cái một. Điều này làm cho phương pháp này tương tự như

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
62 nhưng nó hoạt động theo một cách hơi khác. thay vì nhiều chức năng riêng biệt (
$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
63,
$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
64, v.v.), chỉ có một, nhưng hành vi của nó có thể được thay đổi bởi một tham số. Có nhiều chế độ tìm nạp trong PDO và chúng ta sẽ thảo luận về chúng sau, nhưng đây là một số chế độ dành cho người mới bắt đầu

  • $sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
    65 trả về mảng liệt kê
  • $sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
    66 trả về mảng kết hợp
  • $sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
    67 - cả hai điều trên
  • $sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
    68 trả về đối tượng
  • $sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
    69 cho phép cả ba phương thức (kết hợp số và đối tượng) mà không cần bộ nhớ

Từ những điều trên, bạn có thể biết rằng chức năng này phải được sử dụng trong hai trường hợp

  1. Khi chỉ có một hàng được mong đợi - để có được hàng duy nhất đó. Ví dụ,

    $sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
    21

    Sẽ cung cấp cho bạn một hàng từ câu lệnh, ở dạng mảng kết hợp

  2. Khi chúng ta cần xử lý dữ liệu trả về bằng cách nào đó trước khi sử dụng. Trong trường hợp này, nó phải được chạy qua vòng lặp while thông thường, giống như vòng lặp được hiển thị ở trên

Một chế độ hữu ích khác là

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
200, chế độ này có thể tạo đối tượng của một lớp cụ thể

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
22

sẽ tạo ra một mảng chứa đầy các đối tượng của lớp Tin tức, thiết lập các thuộc tính của lớp từ các giá trị được trả về. Lưu ý rằng trong chế độ này

  • các thuộc tính được đặt trước khi gọi hàm tạo
  • đối với tất cả các thuộc tính không xác định phương pháp ma thuật
    $sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
    201 sẽ được gọi
  • nếu không có phương thức
    $sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
    201 trong lớp thì thuộc tính mới sẽ được tạo
  • các thuộc tính riêng tư cũng sẽ được lấp đầy, điều này hơi bất ngờ nhưng khá tiện dụng

Lưu ý rằng chế độ mặc định là

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
67, nhưng bạn có thể thay đổi chế độ này bằng cách sử dụng tùy chọn cấu hình
$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
204 như minh họa trong ví dụ kết nối. Do đó, một khi được đặt, nó có thể được bỏ qua hầu hết thời gian

loại trả lại

Chỉ khi PDO được xây dựng dựa trên mysqlnd và tắt chế độ mô phỏng, thì PDO sẽ trả về các giá trị

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
205 và
$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
206 với các loại tương ứng. Giả sử, nếu chúng ta tạo một bảng

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
23

Và sau đó truy vấn nó từ PDO dựa trên mysqlnd khi tắt mô phỏng, đầu ra sẽ là

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
24

Nếu không, hành vi quen thuộc của

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
62 sẽ được tuân theo - tất cả các giá trị được trả về dưới dạng chuỗi chỉ có
$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
50 được trả về là
$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
50

Nếu vì lý do nào đó bạn không thích hành vi này và chỉ thích kiểu cũ với chuỗi và NULL, thì bạn có thể sử dụng tùy chọn cấu hình sau để ghi đè lên nó

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
25

Lưu ý rằng đối với loại

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
210, chuỗi luôn được trả về, do bản chất của loại này nhằm giữ lại giá trị chính xác, không giống như các loại FLOAT và DOUBLE cố ý không chính xác

Lấy dữ liệu ra khỏi câu lệnh. tìm nạpColumn()

Một hàm trợ giúp gọn gàng trả về giá trị của một trường duy nhất của hàng được trả về. Rất tiện dụng khi chúng tôi chỉ chọn một trường

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
26

Lấy dữ liệu ra khỏi câu lệnh ở hàng chục định dạng khác nhau. tìm nạp tất cả ()

Đó là chức năng thú vị nhất, với hầu hết các tính năng đáng kinh ngạc. Chủ yếu là nhờ sự tồn tại của nó, người ta có thể gọi PDO là trình bao bọc, vì chức năng này có thể tự động hóa nhiều thao tác được thực hiện thủ công

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
211 trả về một mảng bao gồm tất cả các hàng được truy vấn trả về. Từ thực tế này, chúng ta có thể đưa ra hai kết luận

  1. Không nên sử dụng chức năng này nếu nhiều* hàng đã được chọn. Trong trường hợp như vậy, nên sử dụng một vòng lặp while thông thường để tìm nạp từng hàng một thay vì lấy tất cả chúng dưới dạng một mảng cùng một lúc.
    * "nhiều" có nghĩa là nhiều hơn mức phù hợp để hiển thị trên trang web trung bình.
  2. Chức năng này chủ yếu hữu ích trong một ứng dụng web hiện đại không bao giờ xuất dữ liệu ngay trong quá trình tìm nạp mà chuyển dữ liệu đó sang mẫu

Bạn sẽ ngạc nhiên về số lượng định dạng khác nhau mà hàm này có thể trả về dữ liệu (và người dùng PHP trung bình biết rất ít về chúng), tất cả được kiểm soát bởi các biến

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
212. một số trong số họ là

Lấy một mảng đơn giản

Theo mặc định, hàm này sẽ chỉ trả về mảng liệt kê đơn giản bao gồm tất cả các hàng được trả về. Các hằng số định dạng hàng, chẳng hạn như

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
65,
$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
66,
$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
68, v.v. có thể thay đổi định dạng hàng

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
27

Lấy một cột

Thường rất thuận tiện để lấy mảng một chiều đơn giản ra khỏi truy vấn, nếu chỉ một cột trong số nhiều hàng được tìm nạp. của bạn đây

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
28

Nhận các cặp khóa-giá trị

Định dạng này cũng cực kỳ hữu ích, khi chúng ta cần lấy cùng một cột, nhưng được lập chỉ mục không phải theo số theo thứ tự mà theo trường khác. Đây là hằng số

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
216

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
29

Lưu ý rằng bạn chỉ phải chọn hai cột cho chế độ này, cột đầu tiên phải là duy nhất

Bắt các hàng được lập chỉ mục theo trường duy nhất

Tương tự như trên, nhưng không nhận được một cột mà là hàng đầy đủ, chưa được lập chỉ mục bởi một trường duy nhất, nhờ hằng số

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
217

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
10

Lưu ý rằng cột đầu tiên được chọn phải là duy nhất (trong truy vấn này, giả định rằng cột đầu tiên là id, nhưng để chắc chắn hơn, hãy liệt kê nó một cách rõ ràng)

Nhận các hàng được nhóm theo một số trường

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
218 sẽ nhóm các hàng thành một mảng lồng nhau, trong đó các chỉ mục sẽ là các giá trị duy nhất từ ​​cột đầu tiên và các giá trị sẽ là các mảng tương tự như các mảng được trả về bởi
$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
219 thông thường. Ví dụ, đoạn mã sau sẽ tách nam khỏi nữ và đặt chúng vào các mảng khác nhau

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
11

Vì vậy, đây là giải pháp lý tưởng cho nhu cầu phổ biến như "nhóm sự kiện theo ngày" hoặc "nhóm hàng hóa theo danh mục". Một số trường hợp sử dụng thực tế

Các chế độ khác

Tất nhiên, có một

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
220 dành cho những người hâm mộ lập trình chức năng

Nhiều chế độ sắp ra mắt

xử lý lỗi. ngoại lệ

Mặc dù có một số chế độ xử lý lỗi trong PDO, chế độ thích hợp duy nhất là

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
221. Vì vậy, người ta phải luôn đặt nó theo cách này, bằng cách thêm dòng này sau khi tạo phiên bản PDO,

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
12

hoặc như một tùy chọn kết nối, như minh họa trong ví dụ trên. Và đây là tất cả những gì bạn cần để báo cáo lỗi cơ bản

Báo cáo lỗi PDO

TL;DR.
Mặc dù tất cả các hướng dẫn khác nói gì, bạn không cần toán tử

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
222 để báo cáo lỗi PDO. Chỉ bắt một ngoại lệ nếu bạn có một tình huống xử lý khác ngoài việc chỉ báo cáo nó. Nếu không, chỉ cần để nó nổi lên thành một trình xử lý trên toàn trang web (lưu ý rằng bạn không cần phải viết một trình xử lý nào, có một trình xử lý tích hợp cơ bản trong PHP, khá tốt).

Ngoại lệ duy nhất (không nhằm mục đích chơi chữ) là việc tạo phiên bản PDO, trong trường hợp có lỗi, phiên bản này có thể tiết lộ thông tin xác thực kết nối (đó sẽ là một phần của dấu vết ngăn xếp). Để ẩn chúng, chúng ta có thể gói mã kết nối vào một toán tử

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
222 và sau đó ném một
$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
224 mới chỉ chứa thông báo chứ không chứa thông tin đăng nhập

Một câu nói dài về vấn đề này

Mặc dù ảo tưởng phổ biến, bạn không bao giờ nên bắt lỗi để báo cáo chúng. Một mô-đun (như lớp cơ sở dữ liệu) không được báo cáo lỗi của nó. Chức năng này phải được ủy quyền cho một trình xử lý trên toàn ứng dụng. Tất cả những gì chúng ta cần là đưa ra một lỗi (ở dạng ngoại lệ) - điều mà chúng ta đã làm. Đó là tất cả. Bạn cũng không nên "luôn gói các thao tác PDO của mình trong một

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
225" như hướng dẫn phổ biến nhất từ ​​tutsplus khuyến nghị. Hoàn toàn ngược lại, việc bắt một ngoại lệ nên là một trường hợp ngoại lệ (ý định chơi chữ)

Trên thực tế, không có gì đặc biệt trong các ngoại lệ PDO - chúng đều là lỗi giống nhau. Vì vậy, bạn phải xử lý chúng giống hệt như các lỗi khác. Nếu bạn đã có trình xử lý lỗi trước đó, thì bạn không nên tạo một trình xử lý lỗi dành riêng cho PDO. Nếu bạn không quan tâm - cũng không sao cả, vì PHP rất tốt với việc xử lý lỗi cơ bản và sẽ thực hiện các ngoại lệ PDO.

Xử lý ngoại lệ là một trong những vấn đề với hướng dẫn PDO. Lần đầu tiên làm quen với các ngoại lệ khi bắt đầu với PDO, các tác giả xem xét các ngoại lệ dành riêng cho thư viện này và bắt đầu xử lý ngoại lệ một cách siêng năng (nhưng không đúng cách) chỉ cho PDO. Điều này là hoàn toàn vô nghĩa. Nếu trước đây một người không chú ý đặc biệt đến bất kỳ trường hợp ngoại lệ nào, thì họ đã không nên thay đổi thói quen đối với PDO. Nếu một người không sử dụng

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
222 trước đây, thì họ nên tiếp tục sử dụng điều đó, cuối cùng học cách sử dụng các ngoại lệ và khi nào thích hợp để bắt chúng

Vì vậy, bây giờ bạn có thể nói rằng hướng dẫn sử dụng PHP là sai, nói rằng

Nếu ứng dụng của bạn không bắt được ngoại lệ được ném từ hàm tạo PDO, hành động mặc định được thực hiện bởi công cụ zend là chấm dứt tập lệnh và hiển thị dấu vết quay lại. Dấu vết quay lại này có thể sẽ tiết lộ toàn bộ chi tiết kết nối cơ sở dữ liệu, bao gồm tên người dùng và mật khẩu

Tuy nhiên, không có cái gọi là "hiển thị dấu vết quay lại". Những gì công cụ zend thực sự làm chỉ là chuyển đổi một ngoại lệ chưa được xử lý thành một lỗi nghiêm trọng. Và sau đó, lỗi nghiêm trọng này được xử lý giống như bất kỳ lỗi nào khác - vì vậy nó sẽ chỉ được hiển thị nếu lệnh

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
227 thích hợp được đặt. Do đó, mặc dù bạn có thể hoặc không thể bắt gặp một ngoại lệ, nhưng nó hoàn toàn không liên quan gì đến việc hiển thị thông tin nhạy cảm, bởi vì đó là một cài đặt cấu hình hoàn toàn khác để đáp ứng với điều này. Vì vậy, đừng bắt các ngoại lệ PDO để báo cáo chúng. Thay vào đó, hãy định cấu hình máy chủ của bạn đúng cách

Trên máy chủ phát triển, chỉ cần bật hiển thị lỗi

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
13

Trong khi trên máy chủ sản xuất, tắt hiển thị lỗi trong khi bật lỗi đăng nhập

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
14
  • hãy nhớ rằng có những lỗi khác cũng không nên tiết lộ cho người dùng

Bạn có thể chỉ muốn bắt lỗi PDO trong hai trường hợp

  1. Nếu bạn đang viết trình bao bọc cho PDO và bạn muốn bổ sung thông tin lỗi bằng một số dữ liệu bổ sung, chẳng hạn như chuỗi truy vấn. Trong trường hợp này, hãy bắt ngoại lệ, thu thập thông tin cần thiết và ném lại một Ngoại lệ khác
  2. Nếu bạn có một kịch bản nhất định để xử lý lỗi trong phần mã cụ thể. Một số ví dụ

    • nếu lỗi có thể được bỏ qua, bạn có thể sử dụng thử. bắt cho cái này. Tuy nhiên, đừng biến nó thành thói quen. Bắt trống trong mọi khía cạnh hoạt động như toán tử triệt tiêu lỗi, và nó cũng xấu xa không kém
    • nếu có một hành động phải được thực hiện trong trường hợp thất bại, tôi. e. phục hồi giao dịch
    • nếu bạn đang đợi xử lý một lỗi cụ thể. Trong trường hợp này, hãy nắm bắt ngoại lệ, xem lỗi có phải là lỗi bạn đang tìm không, rồi xử lý lỗi này. Nếu không, chỉ cần ném lại - vì vậy nó sẽ nổi bong bóng lên trình xử lý theo cách thông thường

E. g

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
15

Tuy nhiên, nói chung, không cần điều trị riêng cho các trường hợp ngoại lệ PDO. Nói tóm lại, để có lỗi PDO được báo cáo chính xác

  1. Đặt PDO ở chế độ ngoại lệ
  2. Không sử dụng
    $sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
    222 để báo lỗi
  3. Định cấu hình PHP để báo cáo lỗi thích hợp
    • trên một trang web trực tiếp thiết lập
      $sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
      229 và
      $sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
      230
    • trên một trang web đang phát triển, bạn có thể muốn đặt
      $sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
      231
    • tất nhiên,
      $sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
      232 phải được đặt thành E_ALL trong cả hai trường hợp

Do đó, bạn sẽ luôn được thông báo về tất cả các lỗi cơ sở dữ liệu mà không cần thêm một dòng mã nào. đọc thêm

Lấy số lượng hàng với PDO

Bạn không cần nó

Mặc dù PDO cung cấp một hàm để trả về số hàng mà truy vấn tìm thấy,

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
233, nhưng bạn hầu như không cần đến nó. Có thật không

Nếu bạn nghĩ kỹ, bạn sẽ thấy đây là chức năng bị lạm dụng nhiều nhất trên web. Hầu hết thời gian nó không được sử dụng để đếm bất cứ thứ gì, mà chỉ là một lá cờ - chỉ để xem liệu có bất kỳ dữ liệu nào được trả về hay không. Nhưng đối với trường hợp như vậy, bạn có dữ liệu. Chỉ cần lấy dữ liệu của bạn, sử dụng

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
234 hoặc
$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
219 - và nó sẽ đóng vai trò như một lá cờ như vậy. Nói, để xem có người dùng nào có tên như vậy không, chỉ cần chọn một hàng

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
16

Chính xác điều tương tự với việc nhận một hàng hoặc một mảng có hàng

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
17

Hãy nhớ rằng ở đây bạn không cần số đếm, số hàng thực tế, mà là cờ boolean. Vì vậy, bạn đã nhận nó

Chưa kể trường hợp sử dụng phổ biến thứ hai cho chức năng này không bao giờ được sử dụng. Người ta không bao giờ nên sử dụng

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
236 để đếm hàng trong cơ sở dữ liệu. Thay vào đó, người ta phải yêu cầu cơ sở dữ liệu đếm chúng và trả về kết quả trong một hàng

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
18

là cách thích hợp duy nhất

về bản chất

  • nếu bạn cần biết có bao nhiêu hàng trong bảng, hãy sử dụng truy vấn
    $sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
    237
  • nếu bạn cần biết liệu truy vấn của mình có trả về bất kỳ dữ liệu nào hay không - hãy kiểm tra dữ liệu đó
  • nếu bạn vẫn cần biết có bao nhiêu hàng đã được trả về bởi một số truy vấn (mặc dù tôi khó có thể hình dung ra một trường hợp nào đó), thì bạn có thể sử dụng
    $sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
    236 hoặc chỉ cần gọi
    $sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
    239 trên mảng được trả về bởi
    $sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
    219 (nếu có)

Do đó, bạn có thể nói rằng câu trả lời hàng đầu cho câu hỏi này trên Stack Overflow về cơ bản là vô nghĩa và có hại - một lệnh gọi tới ____1236 không bao giờ có thể được thay thế bằng truy vấn ____1242 - mục đích của chúng về cơ bản là khác nhau, trong khi chỉ chạy một truy vấn bổ sung để lấy số lượng hàng

Các hàng bị ảnh hưởng và id chèn

PDO đang sử dụng cùng một chức năng để trả về cả số hàng được trả về bởi câu lệnh SELECT và số hàng bị ảnh hưởng bởi các truy vấn DML -

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
233. Do đó, để có được số lượng hàng bị ảnh hưởng, chỉ cần gọi hàm này sau khi thực hiện truy vấn

Một câu hỏi thường gặp khác là do mysql sẽ không cập nhật hàng, nếu giá trị mới giống với giá trị cũ. Do đó, số hàng bị ảnh hưởng có thể khác với số hàng khớp với mệnh đề WHERE. Đôi khi cần phải biết số sau này

Mặc dù bạn có thể yêu cầu

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
236 trả về số hàng khớp thay vì số hàng bị ảnh hưởng bằng cách đặt tùy chọn
$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
245 thành TRUE, nhưng vì đây là tùy chọn chỉ dành cho kết nối và do đó bạn không thể thay đổi hành vi của nó trong thời gian chạy, nên bạn sẽ chỉ phải tuân theo

Lưu ý rằng

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
245 không được đảm bảo để hoạt động, như được mô tả trong nhận xét bên dưới

Thật không may, không có bản sao PDO nào cho hàm

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
247 mà đầu ra có thể dễ dàng được phân tích cú pháp và tìm thấy số mong muốn. Đây là một trong những nhược điểm nhỏ của PDO

Có thể lấy mã định danh được tạo tự động từ trường trình tự hoặc trường auto_inclement trong mysql từ PDO. chức năng lastInsertId. Câu trả lời cho câu hỏi thường gặp, "liệu chức năng này có an toàn để sử dụng trong môi trường đồng thời không?" . vâng, nó an toàn. Chỉ là một giao diện cho hàm mysql_insert_id() của MySQL C API, nó hoàn toàn an toàn

Báo cáo đã chuẩn bị và mệnh đề THÍCH

Mặc dù nhìn chung PDO dễ sử dụng, nhưng vẫn có một số vấn đề và tôi sẽ giải thích một số

Một trong số họ đang sử dụng trình giữ chỗ với mệnh đề SQL

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
248. Lúc đầu, người ta sẽ nghĩ rằng một truy vấn như vậy sẽ làm

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
19

nhưng họ sẽ sớm biết rằng nó sẽ tạo ra lỗi. Để hiểu bản chất của nó, người ta phải hiểu rằng, như đã nói ở trên, trình giữ chỗ chỉ phải biểu thị một dữ liệu hoàn chỉnh theo nghĩa đen - một chuỗi hoặc một số cụ thể là. Và không có nghĩa là nó có thể đại diện cho một phần của một phần SQL theo nghĩa đen hoặc một phần tùy ý nào đó. Vì vậy, khi làm việc với LIKE, trước tiên chúng ta phải chuẩn bị nghĩa đen hoàn chỉnh của mình, sau đó gửi nó đến truy vấn theo cách thông thường

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
40

Câu lệnh chuẩn bị và mệnh đề IN

Giống như đã nói ở trên, không thể thay thế một phần truy vấn tùy ý bằng một trình giữ chỗ. Bất kỳ chuỗi nào bạn liên kết thông qua trình giữ chỗ sẽ được đưa vào truy vấn dưới dạng một chuỗi ký tự đơn. Ví dụ: một chuỗi

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
249 sẽ được ràng buộc dưới dạng một chuỗi, dẫn đến

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
41

tạo SQL để tìm kiếm chỉ một giá trị

Để làm cho đúng, người ta cần các giá trị riêng biệt, để làm cho một truy vấn giống như

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
42

Do đó, đối với các giá trị được phân tách bằng dấu phẩy, như đối với toán tử SQL

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
250, người ta phải tạo một bộ
$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
03 theo cách thủ công và đưa chúng vào truy vấn

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
43

Không thuận tiện lắm, nhưng so với mysqli thì nó ngắn gọn đến kinh ngạc

Trong trường hợp có các trình giữ chỗ khác trong truy vấn, bạn có thể sử dụng hàm

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
252 để nối tất cả các biến thành một mảng, thêm các biến khác của bạn ở dạng mảng, theo thứ tự chúng xuất hiện trong truy vấn của bạn

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
44

Trong trường hợp bạn đang sử dụng các trình giữ chỗ được đặt tên, mã sẽ phức tạp hơn một chút, vì bạn phải tạo một chuỗi các trình giữ chỗ được đặt tên, ví dụ:. g.

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
253. Vì vậy, mã sẽ là

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
45

May mắn thay, đối với các trình giữ chỗ được đặt tên, chúng tôi không phải tuân theo thứ tự nghiêm ngặt, vì vậy chúng tôi có thể hợp nhất các mảng của mình theo bất kỳ thứ tự nào

Bảo vệ tên bảng và trường

Trên Stack Overflow, tôi đã thấy quá nhiều người dùng PHP triển khai mã PDO nguy hiểm nhất, nghĩ rằng chỉ các giá trị dữ liệu phải được bảo vệ. Nhưng tất nhiên là không

Thật không may, PDO không có trình giữ chỗ cho số nhận dạng (tên bảng và trường), vì vậy nhà phát triển phải lọc chúng theo cách thủ công. Bộ lọc như vậy thường được gọi là "danh sách trắng" (nơi chúng tôi chỉ liệt kê các giá trị được phép) trái ngược với "danh sách đen" nơi chúng tôi liệt kê các giá trị không được phép. Đây là một ví dụ ngắn gọn

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
46

phương pháp tương tự nên được sử dụng cho hướng, mặc dù mã sẽ đơn giản hơn một chút

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
47

có được hai biến này theo cách này sẽ giúp chúng an toàn 100%

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
48

Cách tiếp cận tương tự phải được sử dụng mỗi khi một bảng tên trường sẽ được sử dụng trong truy vấn

Một vấn đề với mệnh đề LIMIT

Một vấn đề khác liên quan đến mệnh đề SQL

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
254. Khi ở chế độ mô phỏng (được bật theo mặc định), PDO sẽ thay thế trình giữ chỗ bằng dữ liệu thực, thay vì gửi riêng. Và với liên kết "lười biếng" (sử dụng mảng trong
$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
07), PDO coi mọi tham số là một chuỗi. Do đó, truy vấn
$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
256 đã chuẩn bị trở thành
$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
257, đây là cú pháp không hợp lệ khiến truy vấn không thành công

Có hai giải pháp

Một là tắt mô phỏng (vì MySQL có thể sắp xếp tất cả các trình giữ chỗ đúng cách). Để làm như vậy người ta có thể chạy mã này

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
49

Và các thông số có thể được giữ trong

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
07

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
50

Một cách khác là liên kết các biến này một cách rõ ràng trong khi đặt loại tham số phù hợp

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
51

Một điều đặc biệt về

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
259. vì một số lý do, nó không thực thi kiểu truyền. Vì vậy, sử dụng nó trên một số có kiểu chuỗi sẽ gây ra lỗi nói trên

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
52

Nhưng thay đổi

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
260 trong ví dụ thành
$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
261 - và mọi thứ sẽ suôn sẻ

giao dịch

Để thực hiện thành công một giao dịch, bạn phải đảm bảo rằng chế độ lỗi được đặt thành ngoại lệ và tìm hiểu ba phương pháp chính tắc

  • $sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
    262 để bắt đầu giao dịch
  • $sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
    263 để cam kết một
  • $sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
    264 để hủy tất cả các thay đổi bạn đã thực hiện kể từ khi giao dịch bắt đầu

Ngoại lệ là điều cần thiết cho các giao dịch vì chúng có thể bị bắt. Vì vậy, trong trường hợp một trong các truy vấn không thành công, quá trình thực thi sẽ bị dừng và chuyển thẳng đến khối bắt, nơi toàn bộ giao dịch sẽ được khôi phục

Vì vậy, một ví dụ điển hình sẽ giống như

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
53

Xin lưu ý những điều quan trọng sau đây

  • Chế độ báo cáo lỗi PDO nên được đặt thành
    $sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
    221
  • bạn đã bắt được một
    $sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
    266, không phải
    $sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
    267, vì ngoại lệ cụ thể nào đã hủy bỏ việc thực thi không quan trọng
  • bạn nên ném lại một ngoại lệ sau khi khôi phục, để được thông báo về sự cố theo cách thông thường
  • cũng đảm bảo rằng một công cụ bảng hỗ trợ các giao dịch (tôi. e. đối với Mysql, nó phải là InnoDB, không phải MyISAM)
  • không có câu lệnh Ngôn ngữ định nghĩa dữ liệu (DDL) nào xác định hoặc sửa đổi lược đồ cơ sở dữ liệu giữa các truy vấn trong giao dịch của bạn, vì một truy vấn như vậy sẽ gây ra một cam kết ngầm

Gọi các thủ tục được lưu trữ trong PDO

Có một điều về thủ tục được lưu trữ mà bất kỳ lập trình viên nào cũng vấp phải lúc đầu. mọi thủ tục được lưu trữ luôn trả về một tập hợp kết quả bổ sung. một (hoặc nhiều) kết quả có dữ liệu thực và một kết quả trống. Điều đó có nghĩa là nếu bạn cố gắng gọi một thủ tục và sau đó tiếp tục với một truy vấn khác, thì lỗi "Không thể thực hiện các truy vấn trong khi các truy vấn không có bộ đệm khác đang hoạt động" sẽ xảy ra, bởi vì trước tiên bạn phải xóa kết quả trống thừa đó. Do đó, sau khi gọi một thủ tục lưu trữ nhằm mục đích chỉ trả về một tập kết quả, chỉ cần gọi

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
268 một lần (tất nhiên là sau khi tìm nạp tất cả dữ liệu trả về từ câu lệnh, nếu không nó sẽ bị loại bỏ)

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
54

Trong khi đối với các thủ tục được lưu trữ trả về nhiều tập kết quả, hành vi sẽ giống như khi thực hiện nhiều truy vấn

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
55

Tuy nhiên, như bạn có thể thấy ở đây có một thủ thuật khác phải được sử dụng. nhớ rằng tập hợp kết quả bổ sung? . Vì vậy, chúng tôi không thể chỉ sử dụng

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
269. Thay vào đó, chúng ta cũng phải kiểm tra kết quả trống. Vì mục đích nào thì
$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
270 thật tuyệt vời

Tính năng này là một trong những khác biệt cơ bản giữa mysql ext cũ và các thư viện hiện đại. sau khi gọi một thủ tục được lưu trữ với

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
00, không có cách nào để tiếp tục làm việc với cùng một kết nối, vì không có chức năng
$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
272 cho
$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
273. Người ta phải đóng kết nối và sau đó mở lại một kết nối mới để chạy các truy vấn khác sau khi gọi một thủ tục được lưu trữ

Việc gọi một thủ tục được lưu trữ là một trường hợp hiếm hoi khi sử dụng

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
54 là hợp lý, vì đó là cách duy nhất để xử lý các tham số
$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
275 và
$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
276. Ví dụ có thể được tìm thấy trong chương hướng dẫn tương ứng. Tuy nhiên, đối với mysql thì nó không hoạt động. Bạn phải dùng đến một biến SQL và một lệnh gọi bổ sung

Lưu ý rằng đối với các cơ sở dữ liệu khác nhau, cú pháp cũng có thể khác nhau. Ví dụ: để chạy thủ tục được lưu trữ đối với máy chủ Microsoft SQL, hãy sử dụng định dạng sau

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
56

ở đâu ? . Lưu ý rằng không nên sử dụng dấu ngoặc nhọn trong cuộc gọi

Chạy nhiều truy vấn với PDO

Lưu ý rằng không có lý do gì để đưa nhiều truy vấn vào một cuộc gọi và nói chung, bạn không cần chức năng này. Chạy từng truy vấn một bằng nhau về mọi mặt so với chạy chúng theo lô. Trường hợp sử dụng duy nhất cho chức năng này mà tôi có thể nghĩ đến là khi bạn cần thực thi kết xuất SQL hiện có và kiểm tra kết quả

Khi ở chế độ mô phỏng, PDO có thể chạy nhiều truy vấn trong cùng một câu lệnh, thông qua query() hoặc ________ 1277. Để truy cập kết quả của các truy vấn hệ quả, người ta phải sử dụng

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
268

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
57

Trong vòng lặp này, bạn sẽ có thể thu thập tất cả thông tin liên quan từ mọi truy vấn, chẳng hạn như hàng bị ảnh hưởng, id được tạo tự động hoặc lỗi đã xảy ra

Điều quan trọng là phải hiểu rằng tại thời điểm

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
07, PDO sẽ chỉ báo lỗi cho truy vấn đầu tiên. Nhưng nếu xảy ra lỗi ở bất kỳ truy vấn nào sau đó, để nhận được lỗi đó, người ta phải lặp lại các kết quả. Mặc dù có một số ý kiến ​​​​thiếu hiểu biết, PDO không thể và không nên báo cáo tất cả các lỗi cùng một lúc. Một số người không thể nắm bắt được toàn bộ vấn đề và không hiểu rằng thông báo lỗi không phải là kết quả duy nhất từ ​​truy vấn. Có thể có một tập dữ liệu được trả về hoặc một số siêu dữ liệu như id chèn. Để có được những thứ này, người ta phải lặp lại các tập kết quả, từng cái một. Nhưng để có thể đưa ra lỗi ngay lập tức, PDO sẽ phải tự động lặp lại và do đó loại bỏ một số kết quả. Đó sẽ là một điều vô nghĩa rõ ràng

Không giống như

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
280 PDO không thực hiện cuộc gọi không đồng bộ, vì vậy bạn không thể "bắn và quên" - gửi hàng loạt truy vấn tới mysql và đóng kết nối, PHP sẽ đợi cho đến khi truy vấn cuối cùng được thực thi

chế độ thi đua. PDO. ATTR_EMULATE_PREPARES

Một trong những tùy chọn cấu hình PDO gây tranh cãi nhất là

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
281. Nó làm gì?

  1. Nó có thể sử dụng câu lệnh chuẩn bị sẵn hoặc thực.
    Khi chuẩn bị() được gọi, truy vấn của bạn với các trình giữ chỗ sẽ được gửi tới mysql, với tất cả các dấu chấm hỏi bạn đặt vào (trong trường hợp các trình giữ chỗ có tên được sử dụng, chúng được thay thế bằng ?s như .
  2. Nó có thể sử dụng câu lệnh đã chuẩn bị được mô phỏng, khi truy vấn của bạn được gửi tới mysql dưới dạng SQL thích hợp, với tất cả dữ liệu tại chỗ, được định dạng đúng. Trong trường hợp này, chỉ có một vòng quay tới cơ sở dữ liệu xảy ra, với lệnh gọi
    $sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
    07. Đối với một số trình điều khiển (bao gồm cả mysql), chế độ mô phỏng được bật
    $sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
    283 theo mặc định

Cả hai phương pháp đều có nhược điểm và ưu điểm của chúng, và - tôi phải nhấn mạnh vào điều đó - cả hai đều an toàn như nhau, nếu được sử dụng đúng cách. Mặc dù giọng điệu khá hấp dẫn của bài viết phổ biến trên Stack Overflow, nhưng cuối cùng, nó nói rằng nếu bạn đang sử dụng các phiên bản PHP và MySQL được hỗ trợ đúng cách, bạn sẽ an toàn 100%. Tất cả những gì bạn phải làm là đặt mã hóa trong DSN, như được hiển thị trong ví dụ trên và các câu lệnh chuẩn bị được mô phỏng của bạn sẽ an toàn như câu lệnh thực

Lưu ý rằng khi chế độ gốc được sử dụng, dữ liệu không bao giờ xuất hiện trong truy vấn, được công cụ phân tích cú pháp nguyên trạng, với tất cả các trình giữ chỗ tại chỗ. Nếu bạn đang xem nhật ký truy vấn Mysql cho truy vấn đã chuẩn bị của mình, bạn phải hiểu rằng đó chỉ là truy vấn nhân tạo được tạo chỉ cho mục đích ghi nhật ký chứ không phải truy vấn thực đã được thực thi

Các vấn đề khác với chế độ mô phỏng như sau

Khi chế độ mô phỏng được BẬT

người ta có thể sử dụng một tính năng tiện dụng của các câu lệnh đã chuẩn bị được đặt tên - một trình giữ chỗ có cùng tên có thể được sử dụng bất kỳ số lần nào trong cùng một truy vấn, trong khi biến tương ứng chỉ được ràng buộc một lần. Vì một số lý do mơ hồ, chức năng này bị tắt khi tắt chế độ mô phỏng

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
58

Ngoài ra, khi mô phỏng là

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
283, PDO có thể chạy nhiều truy vấn trong một câu lệnh đã chuẩn bị

Ngoài ra, vì các câu lệnh chuẩn bị sẵn chỉ hỗ trợ một số loại truy vấn nhất định, nên bạn chỉ có thể chạy một số truy vấn với các câu lệnh chuẩn bị khi mô phỏng là

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
283. Đoạn mã sau sẽ trả về tên bảng trong chế độ mô phỏng và lỗi khác

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
59

Khi chế độ mô phỏng bị TẮT

Người ta có thể không bận tâm với các loại tham số, vì mysql sẽ sắp xếp tất cả các loại đúng cách. Do đó, chuỗi thậm chí có thể được liên kết với các tham số GIỚI HẠN, như đã được lưu ý trong chương tương ứng

Ngoài ra, chế độ này sẽ cho phép sử dụng lợi thế của tính năng thực thi một lần chuẩn bị nhiều lần

Thật khó để quyết định chế độ nào được ưu tiên hơn, nhưng vì lợi ích khả dụng, tôi muốn biến nó thành

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
286, để tránh rắc rối với mệnh đề
$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
254. Các vấn đề khác có thể được coi là không đáng kể khi so sánh

Mysqlnd và các truy vấn được đệm. Bộ dữ liệu khổng lồ

Gần đây, tất cả các tiện ích mở rộng PHP hoạt động với cơ sở dữ liệu mysql đã được cập nhật dựa trên thư viện cấp thấp có tên là

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
288, thay thế ứng dụng khách
$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
289 cũ. Do đó, một số thay đổi trong hành vi PDO, chủ yếu được mô tả ở trên và một thay đổi sau

Có một thứ gọi là truy vấn đệm. Mặc dù có thể bạn không để ý nhưng bạn đã sử dụng chúng suốt. Thật không may, đây là tin xấu cho bạn. không giống như các phiên bản PHP cũ, nơi bạn đang sử dụng các truy vấn được đệm gần như miễn phí, các phiên bản hiện đại được xây dựng dựa trên trình điều khiển mysqlnd sẽ không cho phép bạn làm điều đó nữa

Khi sử dụng libmysqlclient làm thư viện, giới hạn bộ nhớ của PHP sẽ không tính bộ nhớ được sử dụng cho các tập kết quả trừ khi dữ liệu được tìm nạp vào các biến PHP. Với mysqlnd, bộ nhớ được tính sẽ bao gồm toàn bộ kết quả

Toàn bộ nội dung là về tập kết quả, là viết tắt của tất cả dữ liệu được truy vấn tìm thấy

Khi truy vấn CHỌN của bạn được thực thi, có hai cách để cung cấp kết quả trong tập lệnh của bạn. một bộ đệm và không có bộ đệm. Khi sử dụng phương thức đệm, tất cả dữ liệu do truy vấn trả về sẽ được sao chép vào bộ nhớ của tập lệnh cùng một lúc. Trong khi ở chế độ không có bộ đệm, máy chủ cơ sở dữ liệu sẽ cung cấp từng hàng một

Vì vậy, bạn có thể biết rằng ở chế độ được lưu vào bộ đệm, tập kết quả luôn chiếm quá nhiều bộ nhớ trên máy chủ ngay cả khi quá trình tìm nạp hoàn toàn không bắt đầu. Đó là lý do tại sao không nên chọn bộ dữ liệu khổng lồ nếu bạn không cần tất cả dữ liệu từ nó

Tuy nhiên, khi các ứng dụng khách dựa trên libmysql cũ được sử dụng, vấn đề này không làm phiền người dùng PHP quá nhiều, vì bộ nhớ được sử dụng bởi tập kết quả không được tính trong

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
290 và
$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
291

Nhưng với mysqlnd, mọi thứ đã thay đổi và tập kết quả được trả về bởi truy vấn được lưu trong bộ đệm sẽ được tính vào cả

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
290 và
$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
291, bất kể bạn chọn cách nào để nhận kết quả

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
0

sẽ cho bạn

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
1

điều đó có nghĩa là với truy vấn được đệm, bộ nhớ sẽ được sử dụng ngay cả khi bạn đang tìm nạp từng hàng một

Vì vậy, hãy nhớ rằng nếu bạn đang chọn một lượng dữ liệu thực sự khổng lồ, hãy luôn đặt

$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
294 ​​thành
$sql = 'SELECT * FROM users WHERE email = :email AND status=:status';
295

Tất nhiên, có những nhược điểm. Một là khét tiếng

Không thể thực thi truy vấn trong khi các truy vấn không có bộ đệm khác đang hoạt động

thông báo lỗi có nghĩa là cho đến khi bạn không truy xuất tất cả các hàng đã chọn từ truy vấn không có bộ đệm, thì sẽ không thể chạy bất kỳ truy vấn nào khác đối với cùng một kết nối cơ sở dữ liệu