• Aucun résultat trouvé

The PDO Class

Dans le document PHP OBJECT-ORIENTED (Page 181-184)

So far in this book we’ve created our own connection class and used the SQLiteDatabase class—classes that have many similarities to PDO. With this experience, I needn’t say a lot about the PDO class.

I’ve already mentioned the quote, setAttribute, and query methods of the PDO class. For databases such as SQLite that support transactions, this class also has methods to begin, commit, or roll back transactions.

The most important method, however, is prepare. This method is similar to the query method in that it also returns a PDOStatement. The major differ-ence is that query is typically used for SQL statements that are issued once and prepare for queries that will be issued a number of times.

PDOStatement

In the conversion of our application from SQLite to PDO, in some cases the difference between a result set and a statement isn’t apparent at all. For example, the snippet of SQLite code to display all the resources in our data-base (from the file getresources.php) is shown in Listing 16-1.

$result = $db->query($strsql);

if(!empty($result)){

$previous = "";

foreach ($result as $row){

foreach ($row as $key => $value){

...

Listing 16-1: Displaying resources

The equivalent PDO code is identical. In one case, the variable $db represents an SQLiteDatabasePlus, and in the other it represents a PDO. Like-wise the $result variable is an SQLiteResult or a PDOStatement. Because result sets and statements are both iterable, they can be used in the same way within foreach loops. In this case, using PDO takes no more steps than using SQLite directly.

This similarity between a result set and a statement makes it easy to start using statements, but it also masks important differences. These differences are more apparent when the prepare method is used.

prepare

Instead of using the query method to create a PDOStatement object, the code

$result = $db->query($strsql); in Listing 16-1 can be changed to the following:

$result = $db->prepare($strsql);

$result->execute();

I have already hinted at one of the advantages of using prepare instead of query. Any variables used in the parameter to the prepare method will auto-matically be quoted. This is an easier and more portable way of escaping quotes than using the quote method. If used exclusively, you needn’t worry about forgetting to quote an SQL statement. This is a security advantage that will protect against SQL injection attacks.

This is one way in which a statement is superior to a result set, but it is not the most important difference. Statements are more commonly used to insert multiple records into a database, and they do this more efficiently than a series of individual SQL statements. This is what is referred to as a prepared statement.

Prepared Statements

There are a number of ways that statements can be used with both input and output parameters. We’ll content ourselves with one example of a prepared statement used to make multiple inserts. The SQLite application in Chapter 15 has no need for multiple inserts, so we’ll create a simple new example.

Suppose you have an ecommerce application. The inventory numbers for various purchased items are stored in an array. Here’s how we can update our database using a prepared statement:

//$pdo is an instance of a PDO connection

$orderid = "200";

$array_skus = array(1345, 2899, 6502);

$strsql = "INSERT INTO tblorderitems (orderid, inventorynumber) ".

" Values ($orderid, ? ) ";

$stmt = $pdo->prepare($strsql);

$stmt-> bindParam(1, $number);

foreach ($array_skus as $number){

$stmt-> execute();

}

Using PDO 163 This is a fairly simple example of a prepared statement, but it will give you an understanding of how statements work. A replaceable parameter ( ) is indicated by a question mark, this parameter is bound to the variable

$number, and each iteration of the foreach loop executes the query, inserting a different value.

Using statements is much more efficient than separately querying the database. The performance improvements are due to the fact that after a parameterized query is first executed, for each subsequent query, only the bound data needs to be passed.

Remember, there’s no such thing as a prepared statement in SQLite.

The developers of PDO thought it important to support this feature for all databases regardless of native support. Using PDO is a good way to familiar-ize yourself with statements and makes it easy to switch to a database that supports this capability.

Fetching Objects

For an OO programmer, the ability to retrieve rows as objects is important.

PDO has a number of ways of doing this. An easy way of doing this is to create an instance of the PDORow class in the following way:

$stmt = $pdo->query( "SELECT * FROM tblresources", PDO::FETCH_LAZY );

$pdorow = $stmt->fetch();

There is also a fetchObject method that can be used to create an instance of a specific class. Supposing we have defined a class called RowInfo, creating an instance of that class is done in this way:

$row = $stmt->fetchObject('RowInfo');

This method is perhaps the simplest way to create an object. You can use it with an existing class or, if you don’t specify a class, it will create an instance of stdClass, the generic object class.

What these various ways of creating objects have in common is that they instantiate an object, creating data members from the columns of the current row.

PDOStatement also has a method, getColumnMeta, to dynamically retrieve metadata about the current query. By using this method in conjunction with one of the create object methods and adding a magic get method to the class you’re instantiating, it is easy to retrieve the data members of any object cre-ated from any query without knowing the structure of that query beforehand.2 Perhaps our criticisms of magic set and get methods in Chapter 13 were a little harsh.

NOTE SQLite has a procedural version of fetchObject that returns a stdClass object. It is documented as a result set method but not yet implemented.

2 You could, of course, query the sqlite_master table for this information, but the PDO method provides a database-independent way of doing this.

Assessment

We’ve touched on a number of the capabilities of PDO. We’ve used some of them in our application, but not all of them. This is by no means a definitive overview of PDO, but we certainly have enough information to make a judgment about the utility of this data-access abstraction layer.

Our application behaves exactly as it did without PDO. We haven’t had to sacrifice any functionality and some things were much easier to implement—

catching exceptions, for example. All our queries, triggers, and views work in exactly the same way. One minor inconvenience was converting the utility methods of our derived class, but we were able to implement them proce-durally without loss of functionality. The object model of PDO is perhaps a little more difficult, but along with this we’ve gained the ability to use pre-pared statements should we need them. No question—PDO works well with SQLite.

But what if we decided to use a MySQL back-end instead? How many changes would we have to make? Beyond changing the driver, the most obvious change would be removal of the SQLite-specific function sqliteCreateFunction. As noted in Chapter 15, this could be replaced by the MySQL function SUBDATE. Likewise, any other operators or functions not used by MySQL would have to be changed.

Another option would be to use standard SQL wherever possible. The date manipulation functions could be ignored, and this task performed from within PHP. That’s a choice each developer will have to make for themselves, but I expect most won’t quickly give up on hard-won knowledge about specific SQL dialects.

Dans le document PHP OBJECT-ORIENTED (Page 181-184)