P H P  V I E T  N A M  P O R T A L
Xin chào, Khách. Vui lòng đăng nhập hoặc đăng ký tài khoản.
Bạn đã quên email kích hoạt?






     Trang chủ | Download | Tự học PHP | Kho tư liệu | Diễn đàn
Trang: [1] 2
  In  
Current Topic Rating: *****
You have not rated this topic. Select a rating:
Tác giảChủ đề: Làm việc với PDO (Php Data Objects)  (Đã đọc 15691 lần)
cmxq
Administrator
PHP Intermediate
*****
Posts: 1306


Xem hồ sơ Email
« on: February 07, 2008, 03:42:17 AM »

Phần I: Quảng cáo cho PDO Grin

Một trong những đồ chơi hoành tráng nhất trong phiên bản PHP "5 chấm" là sự ra đời của thư viện đối tượng PDO mở rộng, cho phép chúng ta thao tác với các CSDL khác nhau một cách nhẹ nhàng, đơn giản như là đi chơi Tết (Nói vậy chớ CMXQ thấy đi chơi tết cũng khó bỏ xừ, ít nhất là cái công đoạn rúc ra khỏi cái chăn ấm áp Grin).

Để chính thức khởi động PHPVN cho năm mới, CMXQ sẽ trùm chăn làm một serial về PDO. Điều kiện cần và đủ là:
- Biết qua một tí về ADO, BDO, ODBC hay cái quái gì có liên quan đến Data Object cũng được (để dễ so sánh với cái PDO này)
- Một cốc cafe G7 (cái này thì chắc ai cũng có sẵn).
- Nếu ở ngoài Bắc thì cần một cái chăn ấm nữa Grin

Nào, bây giờ chúng ta bắt đầu:

I. Giới thiệu về PDO

PDO là cụm từ viết tắt của PHP Data Objects, có nghĩa là Các đối tượng dữ liệu trong PHP (đại loại thế). Đây là một thành phần mở rộng của PHP nhằm cung cấp cho chúng ta một cách thức đơn giản đề truy cập vào các CSDL khác nhau trong PHP.

Nếu như các bạn đã từng lập trình trên .Net, các bạn sẽ thấy một cái gọi là ADO (bản cũ) và ADO.Net, còn nếu các bạn đã từng code bằng Delphi, nó cũng có một món đồ chơi tương tự gọi là BDO, còn trên Java là JDBC... Về cơ bản thì mấy cái này nó giông giống nhau, mà bản chất là cung cấp một mô hình trừu tượng để truy cập tới CSDL. (Có thể coi nó như là một lớp (layer) trong lập trình đa lớp).

Cơ chế làm việc của những cái này có thể được mô hình hoá như sau:

Ứng dụng <----> PDO <---> Trình điều khiển các CSDL <---> Các truy vấn tới CSDL và kết quả trả về từ CSDL <---> CSDL (Access, MySQL, SQL Server, Oracle....).

Chúng ta có thể hình dung rằng mỗi một Hệ quản trị CSDL có một cách quản lý dữ liệu khác nhau, chẳng ai giống ai. Vì vậy, để truy xuất vào một loại CSDL nào đó, chúng ta cần phải khai báo trình điều khiển CSDL tương ứng với loại CSDL đó. Sau khi đã khai báo trình điều khiển, chúng ta có thể kết nối tới CSDL đó, tiến hành các truy vấn (có thể dựa trên ngôn ngữ truy vấn SQL, qua các Stored Procedure... mà CSDL đó hỗ trợ), lấy kết quả về rồi dùng các lệnh khác của PHP xử lý kết quả và hiển thị cho NSD.

II. Cài đặt PDO

PDO chỉ xuất hiện trong PHP từ ver 5 chấm trở đi, vì vậy nếu như server của các bạn chỉ support dưới 5 chấm, hãy chịu khó update lên 5 chấm.

Sau khi cài đặt xong, chúng ta phải mở cái php.ini và enable thư viện này (nếu chưa có) cùng các trình điều khiển tới các CSDL liên quan.

VD dưới đây là dòng lệnh cấu hình trình điều khiển CSDL chạy trên Windows:

extension=php_pdo.dll
extension=php_pdo_firebird.dll
extension=php_pdo_informix.dll
extension=php_pdo_mssql.dll
extension=php_pdo_mysql.dll
extension=php_pdo_oci.dll
extension=php_pdo_oci8.dll
extension=php_pdo_odbc.dll
extension=php_pdo_pgsql.dll
extension=php_pdo_sqlite.dll

Chi tiết hơn trên các HĐH khác nhau thì các bạn chịu khó xem trên PHP Manual nhé. Giờ tớ phải đi pha cafe đã.
« Last Edit: February 07, 2008, 09:49:26 AM bởi cmxq » Logged

Trở về phpvn.org
Ai bán domain rẻ nhất?
cmxq
Administrator
PHP Intermediate
*****
Posts: 1306


Xem hồ sơ Email
« Trả lời #1 on: February 07, 2008, 09:36:49 AM »

I. Thiết lập kết nối tới CSDL

Đầu tiên, chúng ta cần phải biết rằng PDO thuần tuý là một lớp (class) được dùng để thao tác với CSDL. Vì vậy, nó cũng có các phương thức và thuộc tính như bất kỳ một lớp nào được xây dựng trên PHP.

PDO sử dụng một phương thức mặc định là __construct(). Phương thức này kiêm luôn nhiệm vụ tạo kết nối tới CSDL. Phương thức này có các tham số như sau:
PDO {
  PDO __construct(string dsn,
                  string username,
                  string password,
                  array driver_options);
}
Trong đó:
-  dsn (Data Source Name) là một chuỗi văn bản chứa các thông tin cần thiết để kết nối tới một CSDL xác định.
- username và password: chứa tên truy cập và mật khẩu của một tài khoản có quyền thao tác trên CSDL đó.
- driver_options là các tham số tuỳ chọn bổ sung nếu cần.

Cái DSN hơi khó nhớ một chút, và nó tuỳ thuộc vào loại CSDL. Nếu cần thiết thì các bạn chịu khó vào Google search. Ví dụ dưới đây là một chuỗi DSN kết nối tới CSDL MySQL:
'mysql:dbname=testdb;host=127.0.0.1';

Ví dụ:
Code:
<?php
$dbh 
= new PDO('mysql:host=localhost;dbname=thumotti''thumotti''thuhaiti');
?>

Đoạn mã trên tạo ra một biến $dbh (thể hiện của đối tượng PDO). Vì __construct là phương thức mặc định  của PDO nên trong đoạn mã trên chúng ta không cần phải gọi tên phương thức này ra.

II. Huỷ kết nối tới CSDL
Để huỷ kết nối, đơn giản chúng ta chỉ việc gán instance của đối tượng đó với giá trị null.
VD:

Code:
<?php
$dbh 
= new PDO('mysql:host=localhost;dbname=thumotti''thumotti''thuhaiti');
$dbh=null
?>

III. Sử dụng PDO để truy vấn SQL

Ở trên, các bạn đã biết cách kết nối và huỷ kết nối tới CSDL. Bây giờ chúng ta sẽ tiến hành thực hiện một truy vấn SQL thông qua PDO.

Để thực hiện một truy vấn SQL, chúng ta sử dụng một phương thức của PDO là exec().

PDO {
  int exec(string statement);
}

Trong đó, statement là một câu lệnh SQL. Chú ý rằng câu lệnh SQL này phải chạy được trên CSDL mà ta đang sử dụng, (do mỗi một hệ quản trị CSDL lại có một vài câu lệnh SQL đặc chủng nên ta cần phải chú ý điều này). Phương thức trên trả về kết quả là số "râu" (row - record hay bản ghi) bị ảnh hưởng bởi câu lệnh SQL

Ví dụ dưới đây sử dụng để xoá một vài bản ghi nào đó:

<?php
$dbh = new PDO('mysql:host=localhost;dbname=thumotti', 'thumotti', 'thuhaiti');

$count = $dbh->exec("DELETE FROM users WHERE user_id<100"); // Xoá bỏ những "tên" có "số" nhỏ hơn 100.

print("Đã xoá bỏ $count người khỏi CSDL.\n");
?>

Comment: Hic, các ông thầy bói kể ra cũng đúng, mỗi người ai cũng có một cái số cả. Nhỡ bị exec delete thì toi Grin

Vậy là chúng ta đã biết cách thực hiện một truy vấn. Tuy nhiên, đời vẫn còn dài, ít nhất chúng ta cần phải lấy thông tin từ CSDL ra rồi in nó nữa chứ. Dù sao thì hồi 2 đã hết, xin xem tiếp hồi 3 ... Grin

« Last Edit: February 07, 2008, 10:15:12 AM bởi cmxq » Logged

Trở về phpvn.org
Ai bán domain rẻ nhất?
cmxq
Administrator
PHP Intermediate
*****
Posts: 1306


Xem hồ sơ Email
« Trả lời #2 on: February 08, 2008, 09:38:53 AM »

Hic, đợi mãi không thấy ai rate nên đành phải post thêm bài nữa, sau bài này CMXQ quyết tâm lột bỏ chăn gối để đi chơi chờ rate Grin

Nếu như các bạn làm theo những bước ở trên thì chưa đủ, ta phải tìm cách lấy dữ liệu trả về từ các query (VD như truy vấn Select chẳng hạn).

Để làm điều này, trước tiên chúng ta phải sử dụng một phương thức khác của PDO là PDO->query(). Phương thức này có nhiệm vụ thực thi một truy vấn SQL và trả về tập kết quả. Thường thì tập kết quả này sẽ được một lớp đối tượng khác là PDO Statement xử lý. Đây là tập các phương thức chuyên dụng để xử lý kết quả trả về, nó cũng gần giống như cái recordset vậy.

PDO {
  PDOStatement query(string sql);
}

Các bạn cần chú ý phân biệt giữa hai phương thức exec() và query(). Exec() thực thi một truy vấn và trả về số các dòng bị ảnh hưởng bởi truy vấn, còn query() trả về một tập kết quả (thường là một recordset hoặc giá trị false). Người ta thường dùng exec() để truy vấn các câu lệnh như Insert, delete, update..., và dùng query() để truy vấn các câu lệnh Select.

Chúng ta có thể lấy kết quả ra theo hai cách: Lấy về từng dòng hay lấy về toàn bộ. Điểm đặc biệt là cũng như với các hàm xử lý MySQL, kết quả trả về thường được lưu trữ dưới dạng một mảng, rất thuận tiện và dễ dùng (hay nói ngắn gọn hơn là ... đại tiện Grin).

I. Lấy kết quả về theo từng dòng

Để lấy kết quả theo từng dòng (tương tự như hàm mysql_fetch_array()), chúng ta có thể sử dụng phương thức PDOStatement->fetch().

PDOStatement {
  mixed fetch(int fetch_style,
              int cursor_orientation,
              int cursor_offset);
}

Hàm này sử dụng 3 tham số tuỳ chọn:
- Fetch_style xác định cách thức lấy dữ liệu. Nó có thể nhận một trong các giá trị sau:
  • PDO::FETCH_ASSOC: Trả về một mảng được đánh chỉ số bởi tên cột (field) (Tương tự như MYSQL_ASSOC)
  • PDO::FETCH_BOTH (mặc định): trả về một mảng được đánh chỉ số bởi tên cột và chỉ số số nguyên bắt đầu từ 0. (tương tự như MYSQL_BOTH)
  • PDO::FETCH_NUM: trả về một mảng được đánh chỉ số bởi số thứ tự của cột (xuất hiện trên query SELECT), bắt đầu = 0 (Tương tự như MYSQL_NUM)

... và một vài giá trị khác, tham khảo thêm trong manual, nhưng vì chưa đến lúc sờ đến nên CMXQ không liệt kê ở đây.

Cũng tương tự như mysql_fetch_array, phương thức này lấy một dòng từ vị trí con trỏ hiện tại và đẩy con trỏ sang dòng kế tiếp.

Ví dụ:
Code:
$dbh = new PDO('mysql:host=localhost;dbname=thumotti', 'thumotti', 'thuhaiti');
$stmt = $dbh->query("SELECT * FROM user where user_id<10") or die();

echo "<table>";
while (($row = $stmt->fetch(PDO::FETCH_ASSOC))) {
  echo "<tr><td>${row['user_name']}<td>${row['e-mail']}\n";
}
echo "</table>";

II. Lấy toàn bộ dữ liệu và đưa vào mảng.

Để thực hiện điều này, chúng ta cần phải sử dụng một phương thức khác thay cho fetch, đó là fetchall(). Cách thức dùng cũng tương tư nặng thằng fetch, chỉ có điều nó đưa tất cả dữ liệu vào một mảng.

Ví dụ:

Code:
$dbh = new PDO('mysql:host=localhost;dbname=thumotti', 'thumotti', 'thuhaiti');
$stmt = $dbh->query("SELECT * FROM user where user_id<10") or die();
$result=$stmt->fetchAll();
print_r($result);
« Last Edit: February 08, 2008, 09:49:41 AM bởi cmxq » Logged

Trở về phpvn.org
Ai bán domain rẻ nhất?
doangia
Administrator
PHP Intermediate
*****
Posts: 1056

Hữu Tâm Ắt Thành Tựu


Xem hồ sơ WWW Email
« Trả lời #3 on: February 14, 2008, 03:23:15 AM »

Hết rồi àh bác ? Sao chưa thấy gì mầu nhiệm hết vậy ? Chưa thấy sự nổi bật khác biệt so với các cách thông thường , chỉ được cái ... rườm rà .
Quote
Chú ý rằng câu lệnh SQL này phải chạy được trên CSDL mà ta đang sử dụng, (do mỗi một hệ quản trị CSDL lại có một vài câu lệnh SQL đặc chủng nên ta cần phải chú ý điều này)
Chỗ này thắc mắc . Không phải chú PDO này lo cho ta việc tương thích hết hay sao ? Ta vẫn phải thủ công àh ? Muốn chuyển từ Mysql sang MS SQL phải viết lại query àh ?
Logged

Cần Thơ Gạo Trắng Nước Trong
Đến Chơi Mang Dép Chân Không Đi Về ...
phpKungFu
For a better united PHP community in Vietnam
Administrator
PHP Intermediate
*****
Posts: 414


Flattern the world


Xem hồ sơ WWW
« Trả lời #4 on: February 15, 2008, 03:57:52 AM »

Câu hỏi về MySQL và MS SQL hay đấy. Hãy coi phần framework MVC của 5s, trong đó các câu SQL không phải viết trong code mà trong file .xml riêng. Như thế khi chuyển đổi CSDL sẽ không khó khăn tìm ra câu nào cần viết lại, câu nào không.

Đây là 1 vấn để bảo trì và nâng cấp hệ thống đáng quan tâm Cheesy
Logged

Twitter: http://twitter.com/phpKungFu
-------------------------------------
Flexica Solutions
http://www.webflexica.com
doangia
Administrator
PHP Intermediate
*****
Posts: 1056

Hữu Tâm Ắt Thành Tựu


Xem hồ sơ WWW Email
« Trả lời #5 on: February 16, 2008, 01:21:46 AM »

Việc tập trung các query ra 1 chỗ để quản lý đến nay em mới biết Grin .Đúng là càng học càng thấy mình dốt.
Nhưng thực thế những thứ em mong đợi ở PDO hay những cái khác là nó sẽ bao thầu việc thay đổi query cho phù hợp những loại database khác nhau ,công việc của ta là chỉ giao tiếp với duy nhất với chú PDO này và chú này sẽ thay lời muốn nói đến từng loại cơ sở dữ liệu riêng biệt.Hình như chú PDO này ko làm được những gì em muốn nhỉ ?
Thế bác nào có thể nói thử sơ lược 1 số ưu điểm của việc dùng PDO so với cách thông thường được không nhỉ ?
Logged

Cần Thơ Gạo Trắng Nước Trong
Đến Chơi Mang Dép Chân Không Đi Về ...
cmxq
Administrator
PHP Intermediate
*****
Posts: 1306


Xem hồ sơ Email
« Trả lời #6 on: February 17, 2008, 07:37:46 AM »

Hic, mấy hôm nay nằm đắp chiếu trong xó phòng nên ko reply được Grin

Quote
Chỗ này thắc mắc . Không phải chú PDO này lo cho ta việc tương thích hết hay sao ? Ta vẫn phải thủ công àh ? Muốn chuyển từ Mysql sang MS SQL phải viết lại query àh ?

Cậu thử xem thằng ADO nó có tương thích hết được ko? Grin Nói là tương thích nhưng nó cũng chỉ mang tính chất tương đối chứ không thể hỗ trợ hoàn toàn 100% được, vì bản chất mỗi loại CSDL có những cách thức xử lý khác nhau và có một số ít chúng không tuân theo chuẩn, vì thế nên trong mô hình lập trình 3 lớp, người ta phải cắt bỏ hẳn một lớp để thao tác với CSDL.

Cái hay của PDO là cố gắng tạo ra một mô hình đồng nhất để truy cập tới hầu hết các CSDL, nhưng sự đồng nhất đó đạt đến đâu là còn tuỳ thuộc vào Hệ quản trị CSDL có chịu cho... đồng nhất hay không. Còn thì về mặt output thì hầu như là giống nhau rồi còn gì?

Khi sử dụng PDO, ta có thể thay đổi sang các dạng CSDL khác nhau nhưng chỉ phải chỉnh sửa một số lượng rất ít các câu lệnh SQL, đó là điểm mạnh của PDO. Chẳng hạn nếu cậu sử dụng các hàm mysql_xxx thì chỉ làm việc được với MySQL, nhưng khi khách hàng yêu cầu sử dụng Oracle thì thời gian, công sức và money bỏ ra để viết lại lớn hơn rất nhiều lần nếu như cậu sử dụng PDO. Tàm tạm thế đã, giờ tớ phải đi ngủ đây, hic, đang ốm mà chả thấy ai đem đường sữa đến thăm cả Sad
Logged

Trở về phpvn.org
Ai bán domain rẻ nhất?
phpKungFu
For a better united PHP community in Vietnam
Administrator
PHP Intermediate
*****
Posts: 414


Flattern the world


Xem hồ sơ WWW
« Trả lời #7 on: February 17, 2008, 10:07:13 AM »

Một số công cụ DAL (Data Access Layer) đúng là có đi lo chuyện bò trắng răng, có bộ query builder để xử lý query tương thích với nhiều loại DB khác nhau.

Tớ không thích chuyện này tí nào vì nó làm chậm đáng kể tốc độ xử lý của hệ thống, viết lách coding cũng cực khổ hơn, khó lòng dùng được stored procedure/trigger,...

Một hệ thống trung bình thường không mấy khi thay đổi DBMS sau khi đã chọn lúc đầu, trong khi đó, hệ thống lớn thì phải 1 vài năm, khi bắt đầu chứng minh tốt hiệu quả sử dụng, người ta mới tính chuyện phát triển trên nhiều DBMS khác nhau.
Logged

Twitter: http://twitter.com/phpKungFu
-------------------------------------
Flexica Solutions
http://www.webflexica.com
Ácman
Global Moderator
PHP Intermediate
*****
Posts: 401


If it's worth having, it's worth fighting for


Xem hồ sơ Email
« Trả lời #8 on: February 26, 2008, 12:45:40 AM »

Sử dụng Prepared statements:

Prepared statement có thể coi là 1 mẫu query được dịch sẵn với các tham số có thể thay đổi được.

Quá trình xử lý (parse/prepare) 1 query của database bao gồm việc phân tích, dịch và tối ưu query trước khi thực hiện nó. Sử dụng prepared statements, query chỉ phải parse 1 lần, sau đó ta có thể dùng lại nó nhiều lần với các tham số khác nhau mà không phải parse lại với mỗi lần thực hiện truy vấn như cách thông thường, nhờ đó sẽ tiết kiệm được tài nguyên và tăng tốc độ ứng dụng. Ngoài ra, sử dụng prepared statements còn giúp tránh được SQL injection.

Để tạo prepared statements, ta sử dụng phương thức: PDO->prepare()

class PDO {
   PDOStatement prepare ( string statement [, array driver_options] )
}

Trong đó tham số statement là 1 chuỗi query có sử dụng các placeholder làm tham số đầu vào. Phương thức này trả về 1 đối tượng PDOStatement.
Ví dụ:
Code:
<?php
//Tạo database object
$dbh = new PDO('mysql:host=localhost;dbname=thumotti''thumotti''thuhaiti');

//Tạo prepared statement
$stmt $dbh->prepare("INSERT INTO users (name, isMale) VALUES (:name, :ismale)");
$stmt->bindParam(':name'$name);
$stmt->bindParam(':ismale'$ismale);

// Thêm record
$name 'Ácman';
$ismale 1;
$stmt->execute();

// Thêm record
$name 'cmxq';
$ismale = -1;
$stmt->execute();
?>

Giải thích:
- Ở VD trên ta sử dụng :name, :ismale làm các placeholder, nơi sẽ nhận các giá trị cụ thể khi thực hiện query. Ngoài cách trên, ta có thể dùng ? làm placeholder. VD:
Code:
<?php
$stmt 
$dbh->prepare("INSERT INTO users (name, isMale) VALUES (?, ?)");
?>

- Phương thức PDOStatement->bindParam() gắn placeholder với 1 biến, giống như PDOStatement->bindValue(). 2 phương thức này hoàn toàn giống nhau ngoại trừ việc bindParam() gắn biến theo tham chiếu. Placeholder khi được sử dụng dưới dạng ? sẽ được phân biệt bởi thứ tự của chúng. VD:
Code:
<?php
$stmt
->bindParam(1$name);
$stmt->bindParam(2$ismale);
?>

- Phương thức PDOStatemen->execute() thực hiện câu lệnh prepared statement. Tham số truyền vào là 1 mảng. Nếu bỏ trống tham số, phương thức sẽ sử dụng giá trị của các biến mà ta đã gắn cho placeholder. VD:
Code:
<?php
$stmt
->execute(array(':name'=>'Ácman'':ismale'=>1));
$stmt->execute(array('cmxq', -1)); //Khi placeholder sử dụng ?
?>
Logged

pt_conan
PHP Starter
*
Posts: 2


Xem hồ sơ Email
« Trả lời #9 on: March 02, 2008, 11:03:32 PM »

Các bác có thể tham khảo về thư viện PDO tại đây. Khá đầy đủ và chi tiết.


http://www.phpro.org/tutorials/Introduction-to-PHP-PDO.html

« Last Edit: March 03, 2008, 02:55:53 AM bởi phpnubie » Logged
phpnubie
Global Moderator
PHP Intermediate
*****
Posts: 443


Xem hồ sơ
« Trả lời #10 on: March 03, 2008, 02:57:29 AM »

Hình như không phải tiếng việt  Grin.

ps. sorry pt_conan tôi post nhầm post của ban.
Logged
quangtin17
PHP Intermediate
*
Posts: 77


Xem hồ sơ Email
« Trả lời #11 on: April 04, 2008, 01:14:18 AM »

cái hàm prepare mình ko cần dùng bindparam, mình có thể dùng str_replace được mà, ví dụ
str_replace(':name','adman',<sql string>), các bạn thấy thế nào
Logged
Ácman
Global Moderator
PHP Intermediate
*****
Posts: 401


If it's worth having, it's worth fighting for


Xem hồ sơ Email
« Trả lời #12 on: April 04, 2008, 03:48:02 AM »

Vấn đề là làm như cách của bạn thì thà dùng query bình thường có phải nhanh hơn ko, cần j phải prepare Grin. Bạn xem lại xem tác dụng của prepared statement là j là hiểu ngay, còn h tớ phải lượn gấp Grin
Logged

quangtin17
PHP Intermediate
*
Posts: 77


Xem hồ sơ Email
« Trả lời #13 on: April 04, 2008, 07:12:51 AM »

thì mình vẫn dùng PDO nhưng mà ko dùng prepare. Mình có một ví dụ
câu lệnh SQL:
     SELECT * FROM table LIMIT :from,:to
cái này hình như bindparam hay bindvalue làm không được Cheesy
Logged
Ácman
Global Moderator
PHP Intermediate
*****
Posts: 401


If it's worth having, it's worth fighting for


Xem hồ sơ Email
« Trả lời #14 on: April 04, 2008, 09:40:25 AM »

Rất tiếc là nó vẫn làm được Grin
Prepared statement hữu ích khi phải dùng nhiều lần cùng 1 kiểu câu lệnh, với các tham số khác nhau, vì câu lệnh sql chỉ phải dịch 1 lần, chứ ko phải dịch lại nhiều lần như cách dùng thông thường.
Logged

Trang: [1] 2
  In  
 
Chuyển sang:  

Powered by SMF 1.1.11 | SMF © 2006-2007, Simple Machines LLC . Modified by PHPVN Members