• Aucun résultat trouvé

Learning About the Iterator Interface

Dans le document PHP OBJECT-ORIENTED (Page 105-108)

Listing 10-6: Methods of the Iterator interface

Note that instead of beginning with the keyword class, Iterator begins with interface, but otherwise it looks like a class. Notice too that method names have access modifiers and that the method declarations are followed by semicolons. There are no braces following the method names because there is no implementation—which is precisely what makes an interface an interface. The interface is a skeleton; an implementing class must flesh it out.

Learning About the Iterator Interface

Here’s a brief description of each method in the Iterator interface:

A bit more can be gleaned from watching an iterator in action. For exam-ple, the code shown in Listing 10-7 traverses an iterable object using all of the methods in the Iterator interface.

$iterator->rewind();

while($iterator->valid()){

echo $iterator->key();

print_r($iterator->current());

$iterator->next();

}

Listing 10-7: Using the methods in the Iterator interface to traverse an iterable object You begin by calling the rewind method to ensure that you are at the start of the result set. The call to valid controls the while loop so that it continues only as long as there is another record to retrieve. In our implementation, the key returned by the key method will be a number; it is displayed here simply for demonstration purposes. The method current returns the record that the result set currently points to. Finally, a call to next advances the record pointer.

current Returns the current element

key Returns the key of the current element next Moves forward to the next element rewind Rewinds the iterator to the first element

valid Checks to see if there is a current element after calls to rewind ornext

You’ve probably used foreach loops in many different circumstances (most likely with arrays), but you may not have given much thought to what goes on in the background. Listing 10-7 shows what happens in a foreach loop. At the start of the loop an implicit call is made to the rewind method, ensuring that you are at the beginning and that the first record is ready to be displayed. If there is a valid record you can enter the loop with the record pointer pointing to the current row. The record pointer is then advanced—

by making an implicit call to next—and the process is repeated until the end of the record set is reached.

Implementation

To implement an interface, you need to indicate inheritance in your class def-inition. When inheriting from a class you use the keyword extends, but when inheriting from an interface you use implements. Your class definition now reads class MySQLResultSet implements Iterator

Implementing an interface also requires that all methods be defined.

In this particular case you must add the five methods of an iterator, as well as the new data members currentrow, valid, and key, to your existing class. The currentrow member will hold the value(s) of the current row. The member valid is a Boolean that indicates whether there is a current row. The member key simply functions as an array subscript.

Five New Methods

The first three methods that your new class MySQLResultSet inherits from the Iterator interface are straightforward accessor methods that return the value of the newly added data members, like so:

public function current (){

return $this->currentrow;

}

public function key (){

return $this->key;

}

I T E R A T O R M E T H O D S

We’ll seldom use the iterator methods directly. We’re implementing this interface so that we can use a MySQLResultSet within a foreach loop. In a sense, these methods are magic because they are invoked in the background by the foreach construct in much the same way that the __toString method of the MySQLException class is invoked when a MySQLException object is displayed. Any object used within a foreach loop must devise its own implementation of the iterator methods. The implementation will differ depending upon the nature of the object—an iterator that traverses file directories will differ significantly from a result set iterator, for example, but all objects that implement a specific interface will exhibit common behaviors. The point of an interface is that it guarantees the existence of specific methods without specifying what exactly these methods should do.

I m pr ovem en t T hr oug h I n her it an c e 87 public function valid (){

return $this->valid;

}

The method current returns the value of the current record if there is one; key returns its array subscript; and valid returns true unless the record pointer is positioned at the end of the record set. The more interesting meth-ods, however, are next and rewind. First, let’s look at the next method:

public function next (){

if($this->currentrow = mysql_fetch_array($this->result)){

$this->valid = true;

$this->key++;

}else{

$this->valid = false;

} }

In this code, you see that next attempts to retrieve the next row from the result set, and then resets the data members valid and key accordingly.

As you would expect, rewind resets the record pointer to the beginning of the result set after first checking that the number of rows is greater than 0.

This method must also maintain the valid and key data members. The data member valid indicates whether there is a current row, and key is reset to 0.

Here’s the rewind method:

public function rewind (){

if(mysql_num_rows($this->result) > 0){

if( mysql_data_seek($this->result, 0)){

$this->valid = true;

$this->key = 0;

$this->currentrow = mysql_fetch_array($this->result);

} }else{

$this->valid = false;

} }

This method works because your result set is buffered; it was created using the function mysql_query. Because a buffered result set stores all rows in mem-ory, the record pointer can be repositioned.

NOTE An unbuffered result set uses a forward-only cursor, so it cannot use the mysql_data_seek

function. Unbuffered result sets are discussed in both Chapter 15 and Chapter 16.

What to Do with Flightless Birds

Flightless birds such as the emu and the ostrich are unquestionably birds, but they lack one defining characteristic of birds—flight. Like flightless birds, unbuffered result sets lack one characteristic of an iterator. Unbuffered result sets are unquestionably iterable, but they cannot be rewound.

When I introduced interfaces I defined them as classes that have meth-ods but no body for those methmeth-ods. A class that implements an interface must provide the body for every method of the interface. What, then, do you do with an unbuffered result set and the rewind method?

Just as flightless birds simply don’t fly, an unbuffered result set can define a rewind method that does nothing.

NOTE The problem of unwanted methods of an interface is not peculiar to PHP. Other OO languages such as Java circumvent this problem by using “adapter” classes that provide an empty implementation of unwanted methods and only require that desired methods be defined.

Dans le document PHP OBJECT-ORIENTED (Page 105-108)