23 Sep
Posted by ProCOM
on September 23, 2007 – 10:19 pm - 393 views
In the first installment of my series on SPL, we talked about Exceptions. If you have not read it and are not yet familiar with how exceptions work in PHP 5, please do so here. This article assumes knowledge of the Exception class. This installment will cover the new Array object, introduce Iterators and the ArrayIterator, and discuss some practical examples of their usage.
An iterator is, as the name implies, an object that traverses the contents of another object. The object may be a simple array data type or it may be a complex class, but by using iterators, we can standardize the way we traverse objects. The more important concept, however, is providing a way to traverse an object without exposing its internal data structure. In addition to providing a standard interface for object traversal and keeping the internal structure of the object being traversed private, it is common to iterate an object using a filter or to have multiple pending traversals on a single object. Using an iterator allows us to do all this.
The big picture objective behind using special objects such as Iterators is to achieve what is called loose coupling. Loose coupling is present when the internal behavior of objects can change without affecting the objects that interact with them. It also means that private class data is kept private and is not directly accessible to outside objects. This allows classes to store internal data in whatever way they like without forcing other objects to make assumptions about data storage when attempting to directly access class data. The new features in PHP 5 and the introduction of the SPL allow PHP developers to take advantage of these concepts in ways that were previously not possible. To get an overview of the new features in PHP 5 if you are not already familiar with them, have a look at my article: “What’s New in PHP 5″.
We will discuss the new ArrayObject class as a precursor to our discussion on iterators, as the ArrayObject class serves as an excellent example for simple iteration routines.
The Array Object
Programmers familiar with Java and .NET will be at home with using the new ArrayObject class. The ArrayObject class has a definition like this:
class ArrayObject implements IteratorAggregate,
ArrayAccess, Countable {
public function __construct($array);
public function append($value);
public function count();
public function getArrayCopy();
public function getIterator();
public function offsetExists($index);
public function offsetGet($index);
public function offsetSet($index, $newval);
public function offsetUnset($index);
}
As you see in the declaration, the ArrayObject class implements three interfaces. The Countable interface requires the public method count() to be defined and allows the built in PHP count() function to be used on the object. The ArrayAccess interface is used to override array access of objects. For example, the offsetGet($index) method is used in place of the normal array style: $array[$index]. This interfaces calls for the public methods offsetExists(), offsetGet(), offsetSet() and offsetUnset(). The IteratorAggregate interface requires the public method getIterator(), which allows the calling code to use an external iterator for object traversal.
It is worth noting that the IteratorAggregate interface implements the Traversable abstract base interface, which is used to detect if a class is traversable using foreach. This interface must be implemented by either Iterator (an iterator object) or IteratorAggregate (an object to be iterated).
Let’s take a look at some sample code:
$myArray = new ArrayObject();
$myArray->append('a');
$myArray->append('b');
$myArray->append('c');
echo 'First Element: '.$myArray->offsetGet(0).'<br />';
echo 'Second Element: '.$myArray->offsetGet(1).'<br />';
echo 'Third Element: '.$myArray->offsetGet(2).'<br />';
echo 'Number of Elements: '.$myArray->count().'<br />';
$myArray->offsetUnset(0);
$myArray->offsetSet(1, 'a');
echo 'First Element: '.$myArray->offsetGet(0).'<br />';
echo 'Second Element: '.$myArray->offsetGet(1).'<br />';
echo 'Third Element: '.$myArray->offsetGet(2).'<br />';
echo 'Number of Elements: '.$myArray->count().'<br />';
The first line creates the ArrayObject object and the next three lines store the values “a”, “b” and “c” in it. The next four lines demonstrate using the offsetGet() method and the count() method to retrieve values at a specified offset and to return the number of elements in the array, respectively. Next we unset the first index value by calling offsetUnset() and then change the value of the second index to “a”. We then repeat the process of outputting the values in the array and the number of elements in the array. This script will output the following:
First Element: a Second Element: b Third Element: c Number of Elements: 3 First Element: Second Element: a Third Element: c Number of Elements: 2
Note that after calling unset, the index at position 0 still exists but has no value and is not included when calling count(). This seems like a counterintuitive behavior. It seems that the expected result would have been to completely remove the element – index and all – from the array and shift the other elements down. The term unset implies that after calling the method, the value is no longer set at all – meaning it is not set to NULL, 0, ” or anything else, and the index does not exist in the array. I would be interested to hear readers’ thoughts on this, as I see it as poor implementation.
Simple Array Iterators
The following code snippet shows a simple example of creating an ArrayObject object and an ArrayIterator object, then traversing the iterator using the three most common control structures for iteration – foreach, for and while.
$myArray = new ArrayObject();
$myArray->append('a');
$myArray->append('b');
$myArray->append('c');
$i = $myArray->getIterator();
foreach ($i as $item) {
print $item.'<br />';
}
$i->rewind();
for (; $i->valid(); $i->next()) {
print $i->current().'<br />';
}
$i->rewind();
while ($i->valid()) {
print $i->current().'<br />';
$i->next();
}
The first line of this example creates an ArrayObject object and the next three lines call the append() method to add “a”, “b” and “c” to the array. The fifth line gets an ArrayIterator object from the ArrayObject by calling the getIterator() method. Once we have the iterator, we are free to traverse the object in a number of different ways. The first method shown uses the foreach() control structure. Note that after traversing the iterator, we must reset it to its initial position with the rewind() method.
The second method demonstrates using an iterator with a for loop. Note that we do not need any initialization condition in the loop, but we could move the call to rewind() after the previous iteration to the for loop if desired. The condition section of the loop calls the valid() method of our iterator which returns true if more elements of the array exist after our current position and false if not. For our change section, we call the next() method which advances the iterator to the next element it contains.
The last method uses a while loop. Our condition, like the for loop above, uses the valid() method. In this example, however, we call next() after working with our data.
Directory Iteration
PHP developers are accustomed to using a special variable type – resource handles. Resource handles are used by PHP to identify external resources such as open files, directories and database connections. The introduction of the DirectoryIterator class allows developers to traverse a directory through a standard iterator interface, providing a high level of abstraction between the data source (the directory) and application components that use the data source. Previously a developer would perform a simple directory iteration like this :
$dh = opendir('images/');
if (!$dh)
die('Unable to open directory');
while (($resource = readdir($dh)) !== false) {
print $resource.'<br />';
}
This rudimentary example would traverse a directory and output all the files and directories that it contains. The problem with this method of directory iteration is that the calling application has to know the data source is a directory. The following example demonstrates the use of a directory iterator. After the example, I will explain how this could be used in a non-specific context by the calling object.
try {
$iter = new DirectoryIterator('images/');
while ($iter->valid()) {
print $iter->current().'<br />';
$iter->next();
}
}
catch (Exception $e) {
print_r($e);
}
This code should look familiar – it is identical to the array example provided above, only with a different Iterator class. You are probably wondering at this point how we have allowed our calling code to stay unaware of the actual data source. Consider this: we have an application that allows a common display component to output the contents of any iterator. The calling application sends it the right iterator object and it outputs the data. This is a highly simplified example, but it is sufficient to demonstrate intent.
try {
TraverseIterator(new DirectoryIterator('images/'));
TraverseIterator(new ArrayIterator
(new ArrayObject(array('a', 'b', 'c'))));
}
catch (Exception $e) {
print_r($e);
}
function TraverseIterator(Iterator $iter) {
while ($iter->valid()) {
print $iter->current().'<br />';
$iter->next();
}
}
In this example we define a function called TraverseIterator that takes an Iterator object as its only argument. If an object that is not a child class of Iterator is passed to the function, an Exception will be thrown. Our application calls the function twice – once with a DirectoryIterator and once with an ArrayIterator. There are certainly more practical applications of this technique but this demonstrates the basic idea.
Going further, a developer could create some other object that handles creation of iterators. An object whos job is to create other objects is known as a Factory. If we create a class, IteratorFactory, we can use this to create the iterator needed and the calling application would not have to know what type of iterator to create – it would only need the object to traverse and the type of object. A detailed example of this is a subject for another article, but the concept is worth touching on here.
Recursive Iteration
In our example above we used an example that traversed a directory and displayed its contents. This is fine if you are simply checking the contents of a single directory, but what if you need to traverse an entire directory tree? Perhaps you may be searching for a file or simply preparing formatted output. The example below demonstrates a simple way of displaying a directory tree for a given path.
try {
$iter = new DirectoryIterator('images/');
print WalkDirectory($iter);
}
catch (Exception $e) {
print_r($e);
}
function WalkDirectory(DirectoryIterator $iter, $depth = 0) {
$return = str_repeat(' ',
($depth * 5)).$iter->getPathName().'<br />';
while ($iter->valid()) {
$node = $iter->current();
if ($node->isDir() && $node->isReadable() && !$node->isDot()) {
$return .= WalkDirectory
(new DirectoryIterator($node->getPathname()), $depth + 1);
}
elseif ($node->isFile())
$return .= str_repeat
(' ', ((1 + $depth) * 5)).$node->getFilename().'<br />';
$iter->next();
}
return $return;
}
First let us discuss the WalkDirectory function. This function takes a DirectoryIterator object as its first parameter and is required. The second parameter, depth, should not be specified by the calling application, as it is used solely to track the depth of the current traversal in the directory tree. The first line of the function grabs an appropriate amount of padding for the current depth level (we use $depth to determine how far to indent a file or directory in our output) and the current directory path name with the getPathName() method.
The next block of code beginning with the while loop is where we begin to traverse the DirectoryIterator. First we put the node from our DirectoryIterator object into a variable $node. We then test if the variable is a non-dot directory (that is, not “.” or “..”). If the current node is a directory, we append the return value of another call to WalkDirectory to our current return value. This is where the recursion we mentioned before steps in. Recursion is a topic unto itself but in short, recursion is a function calling itself with a known set of operating conditions until a desired target condition is reached. For a higher quality introduction to recursion than could be provided in this article, read “Solving Problems with Recursion” by Mohamed Saad.
If the node is not a directory then it is a file, and we simply append the appropriate amount of padding and the name of the file. The following line advances the iterator one step. Finally, on the last line, we return our return value. If we output the return value, we will see a primitive tree view of the directory we traversed.
The makers of PHP considered this scenario, though, and provided a better way of of recursively iterating structures that require recursion for complete traversal – such as directories, multidimensional arrays and any object with nested objects that use the same type of Iterator.
Conclusion
In short, the introduction of the various interfaces related to Iterators allows PHP developers to strongly implement a sort of regimented object traversal that truly prevents outside code from seeing inside classes’ private data. The new features in PHP 5 and the introduction of the SPL are great steps toward improving developers’ abilities to develop reusable, loosely coupled classes. Keeping private data private is an important part of this and the ArrayObject, Iterator interfaces and classes come built in to assist the task of creating strong code.
As was mentioned on the previous page during our discussion of recursive iteration, there is another group of Iterators that specifically provide a method for recursive object traversal. These will be the subject of the third and final installment in this series on SPL.
—
by David Fells
Recursion is a way to solve a problem by…reducing it to the same problem. What? It may be counterintuitive, but many turn-based games (including chess) use exactly this technique to make a computer player “think.” Mohamed Saad explains the concept, along with when (and when not) to use recursion in your programming. Check out the Connect4 example!Recursion: Solving problems the recursive way
In this article, I will introduce the concept of recursion, one of the most amazing programming constructs, as you will see. Recursion is quite counter-intuitive, and you will certainly find it weird at first, but once grasped, it becomes a seriously powerful weapon in your programming arsenal. Let’s start with the definition.
What is Recursion?
Recursion is a totally different method of solving problems. Conventional problem solving methods consists of decomposing the solution into steps, and executing each step in turn. Well…enter recursion. The recursive way of solving a problem is to reduce the problem into another problem that is exactly of the same type, and solving the new one instead. And how do you solve the new one? Guess what? You just reduce it into another problem of exactly the same type, and so on, and so on, and so on…
Ok, before it gets too weird, let’s see an example of a real-life problem, and how we can use recursion to solve it.
Real Life Example
Let’s assume you have moved to a new apartment. You are exploring the neighborhood, and you suddenly discover that you don’t know your house number. You looked at the building, didn’t find a number there. You knocked on a random apartment, and asked, “what is the number of this building,” and the guy who opened the door smiled and said, “I don’t know the number of this building, but if you look at the number of the building next to us and add 1, you will know our building number.”
Now, let’s pause for a moment. The problem you are trying to solve is “knowing the number of your house.” Let’s look at the proposed solution to this problem. What was the suggestion? You were asked to look at the number of the building next to you and add 1. Your problem was thus reduced into a problem of exactly the same nature! At first your problem was “to find the number of a house,” and your problem now became “finding the number of a house.”

Fig 1. You never knew knowing your house number could get you into so much trouble, did you?
The Plot Thickens
To confuse things even more, let’s say you visited the house next to you, but you still found no number. You knocked on the door, and asked about the house number. Guess what they said to you? “We don’t know, but look at the house next to us, add 1, and you will know our house number.”
Déjà vu anyone? This game could take a while. You should repeat this again and again, till you find a house with a number you know. You add 1, and know the number of the one next to it, and so on, until you reach your house.
Notice that in every step, your problem was always reduced to exactly the same kind of problem (knowing a house number). This is the heart of recursion. We have just made our first recursive solution to a problem.
Before we go any further, I want to make two very important notes. These notes are going to be extremely useful when we start dealing with recursion in programming.
Note 1: In every step of solving a recursive problem, the problem always reduces to a problem of exactly the same nature.
This one is obvious, but now look at number 2.
Note 2: At a certain point, you should just solve the problem you have immediately rather than reducing it any further.
This note is extremely important. Let’s return back to our house numbers problem. If you just keep asking and you are always asked to see the next house, you will spend your entire lifetime looking at buildings! At a certain point, you have to find a house with a number that you know. At this point, the recursion stops, and you start to solve all the problems you left open.
Let me stress this again: you can’t keep reducing your problem into a similar problem forever, or else you are never going to stop. At a certain point, you have to just stop and solve the problem at hand. This point is sometimes called the stopping condition.
Now, I can already hear you screaming, “What does this have to do with programming?!” Well, a lot, actually. When you are writing a program, you are solving a problem (or a set of problems). If you write your solution to the problem in a recursive way, what will it look like? Basically the function you write to solve the problem is going to eventually call itself. What for? This comes from our definition of recursion. We reduce a problem to a problem of exactly the same nature. This is why the function calls itself to solve the new instance of the problem…
Sounds complicated? Don’t worry. Let’s look at our first programming example, a really simple one.
First Programming Example
As promised, this one is going to be easy. We will take a well known problem, and see how we can solve it recursively. The problem is searching an array. You are given an array, and you want to search for a certain value inside the array. The non-recursive approach to this problem would be to iterate through the array looking for the value we search for. When it is found, we stop and report success, and if not, we report failure.
Now, let’s think recursively. We want to reduce the problem of searching an array into a problem of…well…searching an array. After all, this is how recursion works.
Think of this approach. To search an array whose length is n for the value of v, do the following.
If the element is in the very last position, report as success
If not, search the whole array (except for the last position), for the element we are looking for.
You see, we actually managed to reduce the problem from searching an array into searching an array. Are we forgetting anything? Of course we are: the stopping condition! When should this stop? Luckily this is simple–when you are faced with an empty array, report failure.
Now look at the code to actually implement this…
class List
{
int[] data=new int[100];
public boolean search(int v, int n)
{//v is the value we search for, n is length of array to search
if(n==0) return false;
if(data[n-1]==v) return true;
return search(v,n-1);
}
}
Take a closer look at this code. I have removed everything, except for the relevant parts. Did you notice that there aren’t any loops at all? That’s right, we made a search over all the elements of the array without having any kind of loops in the code. Just a couple of if statements, and a return statement! How does it work?
It is a little tricky. First you call search(v,100). This function checks the last element of the array, and if that’s the one we want, it returns true. If not, it calls search(v,99). The newly called function checks the position before the last one, and if the element is not found there it calls search(v,98), and so on. If the element is not in the array, the function search() will keep calling itself till it reaches search(v,0), which will return false. If the element is found, the function that finds it will return true.
If you think this is complicated, don’t worry. Recursion looks complicated the first time you see it. I mentioned that recursion is quite counter-intuitive. The human brain can never solve problems recursively. Our brains can only solve problems by thinking of the steps necessary, and doing them one by one. Only computers are comfortable with recursion. Anyway, let’s get back to our discussion.
I can hear the skeptics complaining, “I can’t see any benefits from using recursion. We solved a simple problem by writing a really tricky piece of code. We could have just lived with a small loop to do the search, and ignore recursion completely.” Patience people; I can’t say everything at the same time! Let’s head into our second example.
The Flood Fill Algorithm
Now, let’s turn our attention to a totally different problem. We are working on a 2D drawing package, and we want to make a bucket fill tool similar to that found in Microsoft Paint. The user selects a color, clicks on a point, and the color spreads to fill the area with this color. Have a look at this figure.

Fig 2. We need to write a program to flood fill a shape
We want to write a function to implement this feature. We are given a 2 dimensional array of colors, a point to start painting from, and a color. We should fill the fill area with the color as mentioned above.
There is no easy non-recursive solution to this problem, but we can solve this recursively in just 8 lines of code. How? The idea is simply to make a flood fill from a point do the following:
Now, you see, the whole solution is just 5 steps, and 4 of them are recursive calls. It is important to understand how this actually works.
class Canvas
{
byte board[][]=new byte[100][100];
public void Fill(int x,int y,byte c)
{
if(board[x][y]==c) return;
board[x][y]=c;
if(x<99&&board[x+1][y]!=c)
Fill(x+1,y,c);
if(x>0&&board[x-1][y]!=c)
Fill(x-1,y,c);
if(y<99&&board[x][y+1]!=c)
Fill(x,y+1,c);
if(y>0&&board[x][y-1]!=c)
Fill(x,y-1,c);
}
}
I have tried to make the code simpler by fixing width and height. But, of course, it is easy to generalize the code to different sizes and color formats.
How it Works
How does this code work? Looks too small to be true? Well, it isn’t. It works like this: you start at a point, if it is already colored you do nothing. This condition prevents color from flowing out.
Next, you turn your attention to the 4 neighboring pixels. If any one of them is not colored, start a flood fill from that point too. And guess what, when you start a flood fill from each of those points, they will start to fill the neighboring pixels, and so on, and so on… This is the magic of recursion.
Take a look at this figure. It shows the first 3 steps of how flood fill works. This figure is not actually 100% accurate in terms of the sequence of pixels being filled, but I hope it illustrates the idea.

Fig 3. Starting at the red point, the program fills the point, and then calls itself to fill the 4 surrounding points, and then from each of the surrounding point, calls itself to fill the 4 surrounding each one of them and so on (Note: the function calls will not occur concurrently as shown here. This is just for illustration purpose. In reality. They will be called one after the other. The sequence of coloring pixels will be different)
Now you see how it works. We have created a really nice flood fill algorithm that can fill really complicated shapes with a minimum amount of effort.
I’ll let you in on a little secret. The code we have just written is bad in its memory usage. Really bad. Why? The same function is called again for every pixel. Each function call takes a specified amount of memory that is released when the function is finished. And so, by the time we reach the last pixel to fill, there are lots of instances of the flood fill function all in the memory, taking lots of space. For a large shape, this memory could be in the megabytes range. Not something to be ignored if you are working on a machine with limited memory (such as a mobile phone).
The moral is to be careful when dealing with recursion. There is a secret overhead because of the function calls, which should never be ignored.
Coming up next is a major example, and one of the best uses of recursion. It is harder than the previous examples, but it’s such a good example that I feel obligated to include it. Grab a cup of coffee; it should help. I’d treat you if I could…but let’s not digress. Instead, let’s go directly to our final example.
Connect 4 AI program
Our last example is creating an AI routine for a connect 4 program. Let’s assume you are creating a connect 4 game, and you want to write the routine for the computer player. How do you make the computer think? This is our example.
By the way, the same idea can be used to make an AI routine for nearly any turn based game, be it Tic-Tac-Toe, Connect 4, or even Chess. We will see in a moment what changes need to be made, and why the harder games require more work.
First, for those people who don’t know what Connect 4 is, it involves dropping pieces into a board to form a line of of 4 in a row, column or a diagonal. You can find an applet that plays Connect 4 at http://www.bodo.com/Applets/Connect4. I hope this gives you an idea of the game.
What is a good way to make the computer play this game? Here’s an idea. Computers are good at enumerating choices, so let’s make them do just that. Here is how we will make it work.
First, let’s consider this solution. The computer will try to put one of its pieces in each different location. Whatever makes the computer win, it will take it. What do you think of this solution? It is not very good. Why? Because the computer is not planning anything ahead. If the computer is only looking one move ahead, it is just like a man fighting in the dark, a man who can only see his footsteps. He will never be able to beat his opponent. Especially if his opponent can see and plan his moves very carefully.
Here is a better alternative. The computer will try to play a piece in each possible location. For each location, it will also try to put a piece for the opponent in each possible location, and then evaluate the position. It will choose the best position. Now, this is a bit better. The computer is now looking one move ahead.
But why stop here? We can extend this idea like this. The computer will try to place a piece in each possible location. For each location, it will try to put a piece for the opponent, and for each location it will try to place a piece for itself, and so on.
In other words the computer is trying all possible combinations for several moves ahead, and then it chooses the best move.
How should the computer decide the best move? It should assume that both sides are playing their best moves. So, when it tries its own moves, it should take the best move for itself, and when it considers the opponent’s move, it should take the worst move for itself. In other words, the best move for the opponent.
Getting complicated? Don’t worry, let me explain it in more detail. When I am trying my moves, if I find a really good move, then I certainly will take it. When I am enumerating my opponent’s moves, what if I find a really good move for him? He will certainly take it. It is that simple. When you are considering moves, you should take the best move for the side you are trying moves for.
The Minimax Method
What we have just created is called the minimax method. Let’s see roughly how our code should look. I will try to keep things as simple as possible, so as not to distract you from the main idea. I will explain how to improve on it later.
class MoveValue
{//holds a score, column pair.
int Score;
int col;
MoveValue(int s,int c)
{
Score=s;
col=c;
}
MoveValue()
{
Score=col=0;
}
}class Connect4
{
byte board[][]=new byte[8][7];
//the connect 4 board. 0 means empty, 1 means player 1 piece
//2 means player 2 pieceMoveValue bestMove(byte sideToMove,int depth,int maxDepth)
{//Finsd the best move for the side. Returns column and score pair
//depth specifies current level of depth (should be passed as 0)
//maxDepth specifies the maximum depth to search//holds the best score
MoveValue best_score = new MoveValue(-100000,0);
if(depth%2==1)best_score.Score*=-1;MoveValue mv=new MoveValue();
for (int i=0;i<7;i++)
{ //try putting a piece at each of 7 columns.
mv.col=i;
if(board[0][i]!=0)
continue; //if column is full ignore it.//find the row to put this piece. x is the row
int x=0;
while(x<8&&board[x][i]==0)x++;
board[x-1][i]=sideToMove;//find if it is a game over, don’t search further if it is
//a score of 100 or -100 means a game over
MoveValue cur=new MoveValue();
cur.Score=value();if(cur.Score==100||cur.Score==-100||depth==maxDepth)
mv.Score=cur.Score;
else //search further (this one is the recursive call)
mv.Score=bestMove((byte)(3-sideToMove),depth+1,maxDepth).Score;
//3-sideToMove, gives you the number of the opponent. If sideToMove is 1
//3-sideToMove will be 2. If sideToMove is 2, 3-sideToMove is 1//if this move is better, use it instead
if(mv.Score>best_score.Score&&depth%2==0)
best_score=mv;
else if(mv.Score<best_score.Score&&depth%2==1)
best_score=mv;//undo the move. Remove the piece you just put
x=0;
while(board[x][i]==0)x++;
board[x][i]=0;
}
return best_score;
}
}
This is the most complex piece of code we have written today. What does it do? Let me explain.
The code starts be defining a new class MoveValue, just to hold the value of a move, plus the column to play at. For example, if we discover that the best move is at column 3, which will give you a benefit of 90, the pair should hold the value (90,3).
Now, let’s turn our attention to the code itself.
The basic idea is simple. Each move is assigned a score based on how good this move is for the player. We choose the best move for the player by choosing the move with the highest score.
The code first declares a MoveValue variable called best_score to hold the best move it can find.
If depth is odd it initializes the score to a very small negative number, or else it initializes it to a big positive number. Huh? Why? Remember when we said the computer, when it tries its moves, should take the best move for itself, and when it considers the opponent’s move, it should take the worst move for itself. In other words, the best move for its opponent.
This is the reason behind those initial values. When depth is even, we are considering a move for the computer, so we initialize the score to a very small value so that the first possible move will be better than it. And when depth is odd, we initialize it to a very big number, so that any possible move will be worse than it.
Placing Pieces
Now what? We make a loop over all 7 columns and try to put a piece in each place. We try to put a piece in column #i if it has an empty slot.
After trying to put a piece we call a function called value() to tell us about the value of this position. The function value(), which we are going to cover in a moment, is given the current situation, and gives us a score that tells us how well this position is for the computer–higher is better, of course.
We call this function first to check for a game over. If it returns +100 the computer has won, or if it returns -100 the human player has won (this is how we are going to program it). In both cases, we don’t need to continue trying further moves. The game is over.
So, we check if the return from this function was +100 or -100 or if we have reached the end of our analysis (depth is equal to maxDepth) and we just take the value returned from the value() function.
If not, we recursively call the bestMove() function to continue digging deeper into the tree of possibilities.
In both cases, we check the return from the function against the best score found so far. If the new score is better than the best score found so far (i.e. it is larger than the best score if it is the computer’s turn, or smaller than the best score if it is the human’s turn), we replace the best score with the new score.
Finally, we return the board to what it was by removing the piece we just put. We repeat again for the next column and so on…
The Value Function
Now, what about that value function? This function should tell us how good a position is from the point of view of the computer player. For the sake of simplicity, we will make a simple value function that just checks who is winning. Here it is…
int value()
{//get the value of a position//check for 4 in a row
for(int i=0;i<5;i++)
for(int j=0;j<7;j++)
if(board[i][j]!=0&&board[i][j]==board[i+1][j]&&
board[i][j]==board[i+2][j]&&board[i][j]==board[i+3][j])
if(board[i][j]==1)
return 100;
else return -100;//check for 4 in a column
for(int i=0;i<8;i++)
for(int j=0;j<4;j++)
if(board[i][j]!=0&&board[i][j]==board[i][j+1]&&
board[i][j]==board[i][j+2]&&board[i][j]==board[i][j+3])
if(board[i][j]==1)
return 100;
else return -100;
//check for 4 in a diagonal
for(int i=0;i<5;i++)
for(int j=0;j<4;j++)
if(board[i][j]!=0&&board[i][j]==board[i+1][j+1]&&
board[i][j]==board[i+2][j+2]&&board[i][j]==board[i+3][j+3])
if(board[i][j]==1)
return 100;
else return -100;//check for 4 in the reverse diagonal
for(int i=3;i<8;i++)
for(int j=0;j<4;j++)
if(board[i][j]!=0&&board[i][j]==board[i-1][j+1]&&
board[i][j]==board[i-2][j+2]&&board[i][j]==board[i-3][j+3])
if(board[i][j]==1)
return 100;
else return -100;
return 0;
}
As you see, the function just checks if there are 4 pieces in a row, column or diagonal, and if it is the computer’s pieces, it returns +100, and if it’s the human’s pieces it returns -100.
Trying it Out
Whew, and that’s it. Now we have a nice Connect 4 AI engine that can actually look several moves ahead, thanks to recursion. For example, if we try the engine on this position:

Fig 4. The AI (red player), will know how to win in this situation
If the program is called to play for the red player with a depth of only 3, it will correctly find that the best move is to put a piece in column 2 to force the human to block at column 5 and then the computer wins by putting a piece at column 5.
In another situation:

Fig 5. If the computer (yellow player) could only see one step ahead, he would be unable to see the threat of playing at column 3 or 6 and winning. Now, it can detect and prevent it.
The computer correctly decides to play at column 3 to block the human from winning by putting at column 3 or 6.
Pretty impressive, huh? And it is all less than 30 lines of code.
Two More Tips
(Page 10 of 10 )
So, is this the end of story? Certainly not! There is room for improvement, but that’s really beyond the scope of this article. I will just give you 2 pointers. First, the value() function could be greatly enhanced, so that it gives a better scoring system. For example it should give some score for 3 in a row (because that’s close to getting 4 in a row). If further studies are made about the game, we can even create a much better value function that takes into account the position of pieces relative to each other, and to the edges and so on…
On the other hand, we can also improve on the bestMove() function itself, by using the alpha beta pruning technique. This technique makes minimax run a lot faster, and I mean a lot. Sadly, this is also outside the scope of this article, but you will find references to alpha beta pruning at the end. Maybe this should be the topic of a future article. Drop me an email if you are interested.
One last comment. The routine we made ignores the case when the board gets full and the game ends in a draw. I didn’t want to complicate things, but I am sure you can easily add it to the current code without much trouble.
So, that was it. Our last example for recursion. But this not the end of the journey. The journey has just started. Hopefully you are ready to start writing your own recursive code now.
When to Use (or Avoid) Recursion
As we saw with the flood fill program, sometimes recursion wastes a lot of memory space (or execution time). Other times, recursion is just the way to go. How do you decide?
Finally a bit of theory, for theory fans. Every recursive program can be re-written in a non-recursive way. Period. But this simple statement doesn’t indicate how complicated the non-recursive code can be. Sometimes a 3 liner recursive code can become truly monstrous code when you switch into the non-recursive version. It is always your decision.
—
by Mohamed Saad
The PHP 5 release comes with a slew of new features aimed at simplifying development with PHP. With PHP 5 comes the introduction of exception handling, the Standard PHP Library (SPL), enhanced support for XML, reflection, and quite a few enhancements to the object oriented features of the language. PHP 5 also offers a sizable list of new functions, many of which will not be covered in this article but are available in the manual.XML
PHP 5 by default installs XML support and offers a new extension, SimpleXML. All XML functions are now standardized on the libxml2 library and are fully W3C standards compliant. SimpleXML is quite possibly the most valuable addition to PHP in years, providing a traversable structure to work on XML documents, allowing you to simply change values in the structure and write the file out with only a few lines of code. The XML functionality that has been available through PHP in the past has been quite rudimentary and required a fair amount of programming work to use, so it is not uncommon to see PHP 4 applications using XML without ever touching the xml functions.
PHP 5 also offers a replacement extension for DOMXL (available in “experimental” form in PHP 4) with the DOM extension. This extension allows you to work on your XML files using the DOM object model and is superior to SimpleXML particularly when you are not certain what document format to expect with your application. While DOM is more powerful, SimpleXML is much quicker to implement and easier to get a handle on for beginner programmers. Both of the extensions are robust and well thought out, and whichever suits your programming needs and taste, you will be using a powerful extension that is light years beyond what was available in PHP 4.
Database Support
PHP 5 offers some big enhancements to its ability to interact with databases. The most significant addition is the embedded SQLite database, a quick, lightweight database engine made specifically for embedded applications. This means there is no RDBMS process running on the server; SQLite reads and writes directly to files on disk. This results in significantly lower memory overhead when the database is not being used, but major performance problems arise if the system is used in a high traffic environment. SQLite is intended for small scale use, as best I can gather.
When testing it with small tables and less than one thousand rows per table, it was comparable to MySQL in executing simple joins with only one concurrent request, but performance from SQLite degraded exponentially with five or more concurrent connections coming in, which makes perfect sense. This is a good database solution for a small site that needs minimal features and expects minimal usage. It could also be useful for storing embedded configuration data in a PHP 5 application that may house its main data store in another RDBMS, and only run small queries against SQLite. SQLite is relatively standards compliant with a few major exceptions, most notably the lack of an ALTER TABLE statement.
PHP 5 also introduces support for the MySQL 4.1 client library with the introduction of the mysqli extension. The mysqli extension provides some basic objects for working with the MySQL server. The mysqli class is used as a connection object and as the ability to open and close connections as well as get context and state information from the server. The mysqli_stmt class represents a prepared statement that allows you to execute “prepare” and “execute” queries against the database. Lastly, the mysqli_result object provides a cursor based interface for reading results, providing similar functionality to the functions available in the standard MySQL extension using a MySQL resource handle. The new extension also adds support for SSL and input/output parameters.
The last notable addition in the database area is enhanced support for Firebird/InterBase, an RDBMS that offers most ANSI SQL-92 features and runs on most operating systems. The ibase extension provides most of the same functionality for Firebird/InterBase as the new mysqli extension does for MySQL but in the same manner as the old MySQL extension – that is, no objects.
SPL: Exceptions and Iterators
PHP 5 comes with the Standard PHP Library (SPL), a collection of objects built to handle various tasks such as exception handling and object traversal (iteration). There are basically six groups of classes/interfaces available natively to the SPL.
Each iterator has a specific purpose and details can be found in the PHP manual.
OOP: Object Enhancements
PHP 5 makes leaps and bounds in its support for objects. Aside from all the new features, Zend claims to have addressed the performance problems involved with object creation and usage in previous versions of PHP, a fact that in itself should encourage more developers to use object-based PHP. PHP 5 offers enhancements in a few key areas including object autoloading, destructors, visibility, static methods, class constants, type hinting, interfaces, cloning, reflection and several magic methods.
Autoloading is a great new feature that provides a way for developers to make sure all dependencies for a class are in place before using it. If you attempt to instantiate a class that has not yet been defined, PHP 5 will call the __autoload() function as a last attempt to load the class before failing with an error. Since most developers put one class per file, and many classes often depend on another either by way of inheritance or encapsulation, __autoload() allows you to make sure all the necessary class files have been included. While PHP 4 had constructors, PHP 5 offers a new features: destructors. Destructors are called when an object is destroyed or all references to it have been removed. Destructors are implemented in classes by use of the __destruct function. The __construct function has also been introduced and takes precedence over the old-style constructor function. The old style still works, but it is recommended that __construct is used as it takes higher priority.
One of the biggest additions to PHP’s support for objects is visibility modifiers, also known as access modifiers. The var keyword has been deprecated and class variables are now to be declared as public, private, or protected. Public class variables are available to any other part of the program. Private variables are only available to that class. Protected variables are available to a class as well as its child classes, unlike private which only allows the class itself to access the variable. Methods can also be declared as public, private, or protected, and if none are declared a method is assumed to be public. Access modifiers allow PHP programmers to programmatically hide the inner workings of one object from another by preventing other objects from accessing class data directly. PHP 5 also introduces the static keyword. Static methods are called without an object instance and calls to static methods are resolved at compile time, not runtime. Static properties are accessed by the :: operator, not ->, and the special variable $this is not available in static methods.
Not only can you declares constants in C-style syntax, const constant = ‘constant value’;, but a class can contain it’s own constants and access them internally using self::constant. This simplifies management of constants and keeps them contained within the classes they belong to, preventing code clutter and conflicts with other constants in the same application that may need the same name but a different value. PHP 5 also allows type hints in method parameter declarations. If a parameter is given a type hint and an object of the wrong type is passed to it, PHP will generate a fatal error. It would be preferable for an exception to be thrown, but type hinting does at least allow responsibility to be placed in the calling code for making sure the proper data type is passed into a function call. Type hints can be used in any function, not strictly in class methods.
PHP 5 also introduces abstract classes and interfaces, which is probably THE most significant enhancement to the language. Abstract classes and interfaces allow high level design principles to be semantically applied to PHP classes. PHP includes three special method keywords, final, abstract and virtual, to facilitate the use of inheritance and interfaces. When a method is declared as final, it cannot be overridden by a child class. When a method is declared as abstract, it must be defined in a child class. When a method is declared as virtual, it may be inherited as is or overridden by a child class. When used in combination, abstract classes and interfaces enforce high level design throughout all levels of implementation and support properly coded objects. They can be used in excess, as can anything else, but used properly these are the most powerful tools available to object oriented developers.
The last features of note are object cloning, some more magic functions and the reflection class. Object cloning allows the implementation of a magic method, __clone() to define what exactly takes place when clone is called on an object. It allows developers to implement deep copying of object data when cloning without writing messy code. A few other noteworthy magic functions are __sleep() and __wakeup(), which are used in conjunction with serialize and unserialize to ensure proper destruction and recreation of resources used within an object. Additionally, the __toString magic method allows a class to decide how to react when it is used in string context. The reflection class works as the name implies; it allows developers to programmatically reverse-engineer classes, interfaces, functions and extensions. Reflection is a powerful tool in developing custom application frameworks.
Conclusion
Overall, PHP 5 offers dramatic improvements over PHP 4 in a lot of areas. These improvements are, by and large, geared toward advanced PHP developers. With the exception of the SimpleXML extension, most of the new functionality will probably have no appeal to the largest segment of the PHP programming population – that is, developers who look at PHP as a simple scripting language and use it to accomplish one task at a time. For PHP application developers though, I see PHP 5 quickly becoming the de facto standard. Start putting pressure on your hosts now to upgrade, because PHP 5 was definitely worth the wait.
—
by David Fells
22 Sep
Posted by ProCOM
on September 22, 2007 – 9:11 pm - 533 views
While most of the excitement surrounding the release of PHP 5 focused on its XML and object-oriented features, the Standard PHP Library (SPL) also saw some significant improvements that went mostly unnoticed. In the first of two articles covering the SPL, David Fells discusses the Exception class, which lets programs handle errors more gracefully and simplifies debugging.Introduction
Amid all the noise and excitement surrounding the release of PHP and its shiny new XML and object oriented features, the Standard PHP Library (SPL) slipped by without much recognition. Exception handling has been a major feature add for PHP 5, and the classes built into PHP are a part of the SPL. This article will demonstrate basic application of several SPL classes and provide information on the classes and interfaces available to PHP 5 programmers.
This article is the first part in a series discussing the classes available in the SPL and their uses. In this article we will discuss the Exception class and its application. Exceptions serve a dual purpose – they allow applications to gracefully handle errors, and they allow simplification of the debugging process, which adds up to a more efficient development process and less stress for developers.
Exceptions
Exceptions have been around for quite a while in languages like C++ and Java, but simple scripting languages have never had support for this graceful error handling device. That changed with the release of PHP 5. Exceptions are not all that special as far as objects go; they are essentially containers for error information. The interesting part is how exceptions are created and identifed. To use exceptions, one only needs to be familiar with the special control structures and functions associated with them. They are built-in and require no configuration and only a handful of brain cells. Exception handling requires proper use of “try”/”catch” blocks and the use of the “throw()” function.
Exceptions are created, or thrown, in one of two ways. Either a developer tells the application to throw an exception when a specific error condition is met (such as data out of the expected range as a function parameter) or the language itself throws an exception when it encounters an application error. The latter type are generated from a lower level in terms of system architecture, but the end result is the same: developers can catch exceptions that are thrown by application code and either ignore them, attempt to recover or gracefully fail. Any option is better than creating a web of error handling methods (such as the PEAR Error class) or by using “die()”, but exceptions are, pun intended, an exceptional solution to the problem of graceful, clean error handling.
Simple Example
Now that we have covered the basics of what an exception is, we will look at a code snippet to see them in action.
class Math {
function divide($divisor, $dividend = 1) {
if (!is_numeric($divisor))
throw(new Exception(’Divisor is not a number’));
if (!is_numeric($dividend))
throw(new Exception(’Dividend is not a number’));
if ($dividend == 0)
throw(new Exception(’Division by zero’));return ($divisor / $dividend);
}
}try {
print Math::divide(1, 0);
}
catch(Exception $e) {
print $e;
}
If you run this code sample, you will see a dump of the contents of the exception thrown by our divide function. The object contains a lot of useful info like the file name and line where the error occurred and the trace. If you are logging errors or displaying them to the screen (for debugging), this information is priceless. Let’s go over the important parts of this code.
if (!is_numeric($divisor))
throw(new Exception(’Divisor is not a number’));
if (!is_numeric($dividend))
throw(new Exception(’Dividend is not a number’));
if ($dividend == 0)
throw(new Exception(’Division by zero’));
This piece of code checks to see if the divisor and dividend are numbers and if the dividend is a non-zero value. If any of these checks fail, our method calls the new function “throw()”, passing it a new Exception object. We send our message to the constructor of Exception so the debugging information is descriptive enough to be of use and to indicate the specific type of failure encountered by the function. Exceptions can also be extended to give them meaningful names, such as DivisionByZeroException for our case, but in general supplying a suitably descriptive message is adequate.
try {
print Math::divide(1, 0);
}
Here we attempt to call “divide()”. Placing it in a “try” control structure allows us to logically separate our code blocks, as not all operations require exception handling. We could generate other errors by making calls to divide with non-numeric input.
catch(Exception $e) {
print $e;
}
This is where the exception is actually caught for handling. We could do something with this error, such as tell the user they cannot divide by zero with the “divide()” function, but in this case we are simply invoking the “$e->__toString()” magic method by treating “$e” as a string – ultimately yeilding an informative error message for the developer.
The Exception Class Hierarchy
As I noted before, the Exception object is essentially a data container from the developer’s standpoint. The only overridable method is “__toString()”, a magic function invoked by default when the class is used in string context. Below is the class definition for the built-in exception class.
class Exception
{
protected $message = ‘Unknown exception’; // exception message
protected $code = 0; // user defined exception code
protected $file; // source filename of exception
protected $line; // source line of exceptionfunction __construct($message = null, $code = 0);
final function getMessage(); // message of exception
final function getCode(); // code of exception
final function getFile(); // source filename
final function getTrace(); // an array of the backtrace()
final function getTraceAsString(); // formated string of trace/* Overrideable */
function __toString(); // formated string for display
}
The methods provided by the Exception class allow a developer to get all relevant information required to debug an error. The most useful feature is the stack trace, which was previously only available to developers using the Zend Debugger. The stack trace allows you to follow the code path that generated the exception from end to end, tracing back through calling methods, files and lines, until the source function call is displayed.
In complex applications, this information is truly priceless and eliminates, to some degree, the ad hoc debugging methods typically employed in PHP to trace errors such as inserting “die()” or “print_r()” calls at key places in your code to get a trace. You will still have to do these things from time to time but overall, Exceptions should ease debugging pains considerably. Other methods allow you to retreive the message and code that were passed into the constructor, the stack trace in string format (instead of an array), and the file name and line number where the exception was thrown.
Like most other clases, the base class Exception can and should be extended to fit its intended usage. The purpose of extending the Exception class is, almost exclusively, to allow instantiation of Exceptions with intuitive, specific names rather than the nonspecific (but still intuitive) Exception.
Developers should be very careful in how they extend the Exception class, as the purpose of the class itself requires minimal functionality.If a task needs complex work to take place before an Exception can be built with the proper data, then you would be right to put that functionality into the Exception, but adding functionality for functionality’s sake is not the right approach. For example, you would not create several methods to output an error message in various formats. There are already quite a few children of the Exception class in the SPL, all of which are made for use in other SPL classes or by the runtime itself.
A Simple Exception Extension

Using our example code above, we can demonstrate a simple extension of the Exception class.
class DivisionByZeroException extends Exception{}
class WrongParameterTypeException extends Exception{}
class Math {
function divide($divisor, $dividend = 1) {
if (!is_numeric($divisor))
throw(new WrongParameterTypeException(’Divisor is not a number’));
if (!is_numeric($dividend))
throw(new WrongParameterTypeException(’Dividend is not a number’));
if ($dividend == 0)
throw(new DivisionByZeroException(’Division by zero’));return ($divisor / $dividend);
}
}try {
print divide(1, 0);
}
catch(WrongParameterTypeException $e) {
print $e;
}
catch(DivisionByZeroException $e) {
print $e;
}
Using this approach, we are able to easily handle different errors in different ways, and this is where the real value of extending the Exception class comes in. We can chain an unlimited number of catch blocks together to capture the different types of exceptions that could have occurred. We could accomplish a similar feat using error codes (remember the second parameter to the Exception class constructor). To do this we would typically define class constants to identify the error type. We could ammend our code to look like this, for example.
Class Math {
const DIVISION_BY_ZERO = 1;
const WRONG_PARAMETER_TYPE = 2;public static function divide($divisor, $dividend = 1) {
if (!is_numeric($divisor))
throw(new Exception(’Divisor is not a number’, self::WRONG_PARAMETER_TYPE));
if (!is_numeric($dividend))
throw(new Exception(’Dividend is not a number’, self::WRONG_PARAMETER_TYPE));
if ($dividend == 0)
throw(new Exception(’Division by zero’, self::DIVISION_BY_ZERO));return ($divisor / $dividend);
}
}try {
print Math::divide(1, 0);
}
catch(Exception $e) {
if ($e->getCode() == Math::WRONG_PARAMETER_TYPE))
die(’You passed divide() a non-numeric value’);
if ($e->getCode() == Math::DIVISION_BY_ZERO))
die(’You tried to divide by zero’);
print $e;
}
The same end result is achieved with a different approach. Ultimately this is a matter of taste, but in my experience I have found it easier to keep up with exception classes. Regardless of your individual taste in approaches, this method of error handling is far more elegant and intuitive than anything available in PHP up until now, so take advantage of it.
Conclusion
Exceptions serve two main purposes: to simplify debugging and to allow for graceful error handling. They alllow a clean structure for identifying and creating errors at the script level, and allow simplified error recovery. The PHP 5 implementation of exceptions is, for all intents and purposes, identical to exception handling in Java, .NET and other languages capable of exception handling. Proper use of exceptions in PHP applications should help shed blobs of ugly legacy error handling and clean up code in general considerably. It allows the elimination of a lot of bulky error checks and the consolidation of error handling and recovery routines. Exceptions should be practiced religiously in PHP 5 applications.
Our next installment will discuss another important chunk of the SPL: Iterators. See you soon!
—
by David Fells
This article explains what polymorphism is and how it applies to object oriented design in particular. It also explains the pros and cons of polymorphism when working with certain versions of PHP.NOTE: The latest versions of PHP, and I am not sure in which exact version this was corrected, support late binding properly. There are still tons of issues with using late binding in cahoots with a bytecode cache, for reasons beyond my understanding or concern. Those of you using an older version of PHP (I still have 5.0.1 on a server) can see for yourselves the lack of late binding support. I initially rescinded this article after learning that late binding is properly supported in current versions, but it is important that you be aware of the possibility that it may not work in your particular PHP 5 install.
PHP 5 and Polymorphism
This article is going to cover one of the most important parts of object oriented programming and design–polymorphism–using PHP 5 for demonstration purposes. Before you continue, be warned that this article is not entirely positive in regard to PHP. While the language is great for rapid development and has made tremendous strides in the last two major versions, its object support still has a way to go before being on par with more mature languages like C++ or Java.
If you are an object programming guru this article probably isn’t for you, since polymorphism is one of those things you learn light-switch style – suddenly it’s all clear, and once you understand it, you never forget. If you are looking to learn a bit about object programming and design and you aren’t really sure exactly what it means when someone says an object is polymorphic, this article will help.
By the end of this article, you should know what polymorphism is and how it applies to object oriented design in particular, and you should know about the pros and cons of PHP 5 object programming as it pertains to polymorphism.
What is Polymorphism?
Polymorphism – “The occurrence of different forms, stages, or types in individual organisms or in organisms of the same species, independent of sexual variations.” (dictionary.com). By that definition, we could assume polymorphism is a programmatic way to represent the same object through multiple states or stages. That’s great, but probably still unclear to many of us. What it really means is this: programming to an interface or base class without regard to an object’s concrete class.
If you are familiar with design patterns, even on a rudimentary level, you should be getting a picture in your mind of what this means. In fact, polymorphism is probably the single greatest facilitator for patterns-based programming. It allows us to organize similar objects in a logical way such that calling code does not have to worry about specific types; rather, we code to an expected interface or base class. The more a software application is abstracted, the more flexible it becomes – and polymorphism is one of the best ways to abstract behaviors.
For example, consider a class called Person. We can subclass Person with classes called David, Charles, and Alejandro. Person has an abstract method called AcceptFeedback(), which all subclasses implement. That means that any code using any subclasses of the Person base class can call the AcceptFeedback() method with confidence, knowing that the class itself handles logic that would otherwise appear in a conditional. You do not have to check whether the object is a David or an Alejandro, just that it is a Person. The effect is that your code is written to the lowest common denominator – the Person class.
The Person class in this example could also be created as an interface. There are some differences, primarily that an interface imparts no behavior, only a set of rules, so to speak. A Person interface would say “you must support the AddFeedback() method” whereas a Person class could provide some default code for the AddFeedback() method, saying “if you choose not to support AddFeedback(), you will be provided with a default implementation.” Choosing interfaces or base classes is the subject for another article entirely, but in general, if you need a default implementation for a method, provide it through a base class. If you are simply outlining a set of expectations for your classes, then use an interface.
Applying Polymorphic Design
Continuing with our Person base class example, let’s take a look at a non-polymorphic implementation. The following example shows a really poor way to create an application that uses different types of Person objects. Note that the actual Person classes are omitted; we’re only concerned with the calling code for now.
<?php
$name = $_SESSION['name'];
$myPerson = Person::GetPerson($name);
switch (get_class($myPerson))
{
case ‘David’ :
$myPerson->AddFeedback(’Great Article!’,
‘Some Reader’, date(’Y-m-d’));
break;
case ‘Charles’ :
$myPerson->feedback[] = array(’Some
Reader’, ‘Great Editing!’);
break;
case ‘Alejandro’ :
$myPerson->Feedback->Append(’Awesome
Javascript!’);
break;
default :
$myPerson->AddFeedback(’Yay!’);
}
?>
This example shows objects that behave differently and a switch statement to differentiate between the different classes of Person, performing the correct operation on each. Note that the feedback comment in each condition is different. That probably would not be the case in a real application; it’s simply done to elucidate the differences in the class implementations.
The next example uses polymorphism.
<?php
$name = $_SESSION['name'];
$myPerson = Person::GetPerson($name);
$myPerson->AddFeedback(’Great Article!’, ‘SomeReader’, date(’Y-m-
d’));
?>
Note the lack of the switch statement and, of greater importance, the lack of concern regarding what type of object Person::GetPerson() returned. Person::AddFeedback() is a polymorphic method. The behavior is one hundred percent encapsulated by the concrete class. Remember, whether we’re working with David, Charles or Alejandro, calling code never has to know the concrete class to function, only the base class.
While I’m sure there are better examples than mine, I think it demonstrates the basic use of polymorphism from the perspective of calling code. We now need to take into consideration the internals of the classes. One of the greatest aspects of inheriting from a base class is that the inheriting class is able to access the behaviors of the parent class, which often serve as nothing more than defaults, but can also be chained to inheriting methods to create more sophisticated behaviors. Below is a simple demonstration of this.
<?php
class Person
{
function AddFeedback($comment, $sender, $date)
{
// Add feedback to database
}
}
class David extends Person
{
function AddFeedback($comment, $sender)
{
parent::AddFeedback($comment, $sender,
date(’Y-m-d’));
}
}
?>
Here we have chained the David::AddFeedback() method to the Person::AddFeedback method. You may note that it resembles overloaded methods in C++, Java, or C#. Remember that this is a simplified example, and that the actual code you write will of course be completely dependent on your project.
Late Binding in PHP 5, or, the Lack Thereof
(Page 4 of 4 )
In my opinion, late binding is what makes Java and C# so spectacular. They allow base class methods to invoke methods in “this”, or $this, even if they do not exist in the base class–or, better yet, to invoke a method from the base class that may be replaced by another version in an inherited class. You may think something like this would work in PHP:
<?php
class Person
{
function AddFeedback($messageArray)
{
$this->ParseFeedback($messageArray);
// Write to database
}
}
class David extends Person
{
function ParseFeedback($messageArray)
{
// Do some parsing
}
}
?>
Keep in mind that there is no ParseFeedback in the Person class. Now, say you have this implementation code, which, for the sake of example, results in $myPerson being a David object:
<?php
$myPerson = Person::GetPerson($name);
$myPerson->AddFeedback($messageArray);
?>
PARSE ERROR! The method ParseFeedback does not exist, or something along those lines. Sigh! So much for late binding in PHP 5! Wait–you probably want to know what late binding is.
Late binding means that method invocations bind to the target object at the last possible minute, which means those objects already have a concrete type when the method is invoked by the runtime. In our example above, you would be calling David::AddFeedback(), and since $this in David::AddFeedback() references a David object, you would logically assume that the ParseFeedback() method exists–but it does not, because AddFeedback() was defined in Person, and calls ParseFeedback() from the Person class.
Unfortunately there is no simple way to skate around this rotten behavior in PHP 5, which means you’re somewhat neutered when it comes to creating a flexible polymorphic class heirarchy.
I must point out that I chose PHP 5 as the language for this article simply for this reason: it’s not very good for abstracting object concepts! Consider it a cautionary tale from someone who learned it the hard way, beginning with PHP 5 when it was still in alpha and assuming that since they added abstract classes and interfaces, late binding was a given.
The End
You should now have a basic understanding of polymorphism and why PHP 5 is not very good at implementing it. You should, generally speaking, know how to encapsulate conditional behavior with a polymorphic object model. Ultimately what you should gain from this is flexibility in your objects, which of course means less code overall. You may end up creating a few more class and a few more class methods, but your calling code will be greatly reduced, which almost always results in time and effort savings. You also increase the clarity of your code by encapsulating conditional behavior-–behavior based on an object’s state-–within the object itself, rather than handling it with code that, for all intents and purposes, should not know enough about the object to make any real decisions on such matters.
If, like myself, you find yourself to be passionately interested in object oriented design, read what I consider to be the three fundamentals: “Design Patterns” (ISBN: 0201633612), “Refactoring” (ISBN: 0201485672), and “Refactoring to Patterns” (ISBN: 0321213351). I would suggest reading them in the stated order. They provide a far more extensive and expert opinion than my own, and will set you on the path to good object oriented software design.
—
by David Fells
PHP has the drawback of not supporting events. Fortunately, a basic structure can be built to support events in PHP 5. This article tackles that problem with some proof of concept code.One of the big drawbacks of PHP has always been its lack of events. Events allow programmers to attach new behaviors to objects that are activated when certain conditions are met. Those conditions are announced to the outside world as an event. While all object languages that support events do so a bit differently, some being very simple like JavaScript or VB.NET, others being a real pain in the rear like C#, it should go without saying that the task of creating a framework to simulate events will be much harder.
It seemed reasonable to me that some sort of basic structure could be established to support events in PHP 5, so I set out to whip something up as quickly as possible as a proof of concept. The contents of this article are the work of roughly one programming hour and surely stand to be improved upon, but the basic idea is this: instantiate an object and attach event handlers; the handlers will be executed when the events they are associated with are raised.
This is not an article for beginners, but I would not say you have to be a guru to understand the concepts and the code here. I have tried to keep it as minimal as possible to stay on point.
The Event and EventCollection Classes
First we need to create a simple object to store whatever event information we may need and an object to contain a collection of events. The reason we do not simply store them in an ArrayObject is because we need to be able to quickly check to see whether an event exists in a given collection, which requires code written specifically for the task.
Here is the Event class:
class Event
{
private $name;
public function GetName()
{
return $this->name;
}
public function __construct($name)
{
$this->name = $name;
}
}
As you can see, the class is essentially a container for a string. You could do away with this class in the examples given here, but I chose to go ahead and use an Event class in case at some point we need to store more information about a particular event. The EventCollection class basically wraps an ArrayObject and provides a function to check for an event by name.
class EventCollection
{
private $events;
public function __construct()
{
$this->events = new ArrayObject();
}
public function Add($event)
{
if (!$this->Contains($event))
$this->events->Append($event);
}
public function Contains($event)
{
foreach ($this->events as $e)
{
if ($e->GetName() == $event)
return true;
}
}
}
Again, I chose to use classes for events rather than simply an ArrayObject of strings to provide support for future additions. There is no code in either of these classes that requires explanation, so let us continue.
Simulating Events with PHP 5 – The EventHandler and EventHandlerCollection Classes
To create an event handler, we need to know the event to which it was attached and we need to know what to do when the handler finds out about the event being raised. Since we cannot create function references, and lack of native support for events eliminates the usefulness of anonymous functions, we will use an approach similar to C# delegates, but with less fuss. We will create an EventHandler object by passing it an Event object and the name of the callback function, which will later be called in an eval() statement (ugly, but it will do).
class EventHandler
{
private $event;
private $callback;
public function GetEventName()
{
return $this->event->GetName();
}
public function __construct($event, $callback)
{
$this->event = $event;
$this->callback = $this->PrepareCallback($callback);
}
public function Raise($sender, $args)
{
if ($this->callback)
eval($this->callback);
}
private function PrepareCallback($callback)
{
if ($pos = strpos($callback, ‘(’))
$callback = substr($callback, 0, $pos);
$callback .= ‘($sender, $args);’;
return $callback;
}
}
This class actually has some substance to it. The Raise() method actually runs the callback, and the PrepareCallback() method makes sure the callback has the proper signature for a delegate, that is, (Object $sender, EventArgs $e), for those of you who are familiar with C#. Since I didn’t care to make an EventArgs class, $args will just be an array. This provides the handler functions with context that they would otherwise lack. They know the calling object, $sender, and they can be given parameters with $args.
The EventHandlerCollection also provides a test for membership with the Contains() method, basically what we saw with the EventCollection, and it provides a RaiseEvent() method that picks through its list of handlers and calls Raise() on the right one. This keeps event triggering simple later on when we look at the event enabled class. Here is the EventHandlerCollection class:
class EventHandlerCollection
{
private $handlers;
public function __construct()
{
$this->handlers = new ArrayObject();
}
public function Add($handler)
{
$this->handlers->Append($handler);
}
public function RaiseEvent($event, $sender, $args)
{
foreach ($this->handlers as $handler)
{
if ($handler->GetEventName() == $event)
$handler->Raise($sender, $args);
}
}
}
We now have our four “framework” classes. It is time to move on to a class that can actually register event handlers and raise events.
Simulating Events with PHP 5 – The Event-Enabled Class
To enable a class with events, there are a few prerequisites, given our existing classes. First, it needs to contain a list of available events. Second, it needs to be able to trigger, or raise, its events through some helper method. Third, it needs to be able to register event handlers. Note that any given event can have more than one event handler.
The code for this class, which we are calling MyEventClass, is actually pretty simple. In the code below, you will notice that the class is wired up for two events, OnLoad and OnUnload. You will also notice that we pass an EventHandlerCollection into the constructor. To support the OnLoad event, which fires at the end of the constructor, we would have to already have a handler in place to make use of it – which means, in general, classes implementing this pattern will need to provide a $handlers parameter in the constructor.
class MyEventClass
{
private $events;
private $eventHandlers;
public function __construct(EventHandlerCollection $handlers
= null)
{
$this->events = new EventCollection();
if ($handlers)
$this->eventHandlers = $handlers;
else
$this->eventHandlers = new EventHandlerCollection
();
$this->InitEvents();
$this->TriggerEvent(’OnLoad’, array(’arg1′=>1));
}
public function __destruct()
{
$this->TriggerEvent(’OnUnload’, array(’arg2′=>2));
}
public function RegisterEventHandler($handler)
{
if ($this->events->Contains($handler->GetEventName()))
$this->eventHandlers->Add($handler);
}
private function InitEvents()
{
$this->events->Add(new Event(’OnLoad’));
$this->events->Add(new Event(’OnUnload’));
}
private function TriggerEvent($eventName, $args)
{
$this->eventHandlers->RaiseEvent($eventName, $this,
$args);
}
}
To quickly review the class methods, from the bottom up, there is TriggerEvent(), which accepts an event name and any relevant arguments. It directly calls EventHandlerCollection::RaiseEvent, which passes the event along to the appropriate handler or handlers, if one does in fact exist. Since the RaiseEvent() method of EventHandlerCollection does not have an exit condition when it finds a handler matching the raised event, we can have as many handlers for an event as we want.
InitEvents() is a crude way to register available events with the class. We have to populate the EventCollection somehow, and this seemed to me the best way to do it. RegisterEventHandler() is simply a wrapper for EventHandlerCollection::Add(), allowing us to attach handlers to an object after it has been instantiated. I would suggest passing all handlers in the constructor for clarity’s sake, but the RegisterEventHandler() method is available nonetheless.
Notice in __construct() and __destruct(), TriggerEvent() is called. The result of calling TriggerEvent(), through a few levels of indirection, calls the code you passed in when you created your EventHandlers. That brings me to the final bit of code for this article – using MyEventClass.
Simulating Events with PHP 5 – Using the Event-Enabled Class
Using MyEventClass is fairly straightforward. You create an EventHandlerCollection and any event handling methods you want, and you instantiate the class.
$handlers = new EventHandlerCollection();
$handlers->Add(new EventHandler(new Event(’OnLoad’),
‘handleLoad’));
$handlers->Add(new EventHandler(new Event(’OnUnload’),
‘handleUnload’));
$obj = new MyEventClass($handlers);
$obj = null;
function handleLoad($sender, $args)
{
print ‘object ‘.get_class($sender).’ loaded with ‘.count
($args).’ args!<br />’;
}
function handleUnload($sender, $args)
{
print ‘object ‘.get_class($sender).’ unloaded with ‘.count
($args).’ args!’;
}
If you create a PHP page with all the code in it from this article and run it, you will see the following on your screen:
object MyEventClass loaded with 1 args!
object MyEventClass unloaded with 1 args!
Obviously this is a rather minimalistic (and pointless) implementation, but it does demonstrate the usage of the event handlers and the event-enabled class. Pretty cool, yes?
Conclusion
Hopefully this article has piqued your interest and you will experiment, improve my code, and create a fantastic open source event framework for PHP, which I am far, far too lazy to do myself. There are some obvious points where refactoring is called for, such as creating an interface or an abstract base class that event-enabled classes adhere to, or providing a more effective design of the event and handler classes. I intend to use the code I’ve created here in my next PHP project, and I hope you will, too. Be sure to let me know how it works out and post any nifty improvements in the dicussion thread of the article.
—
by David Fells
13 Sep
Posted by ProCOM
on September 13, 2007 – 5:11 am - 640 views
So, you have a huge project that you want to build. It’s been determined that you want to use PHP, and your backend is Oracle. You’ve installed Oracle, you’ve installed your web server, and you’ve even gotten PHP to connect to your Oracle back end to do some simple queries. Now what? If you are like most lazy programmers, you get something to work, then you look for a way to do the same thing without having to cut and paste code or retype the same thing over and over. Well, I’ve found that connecting to Oracle is typically done the same way over and over. So, I’ve written some functions to help me run some queries without the drudgery of repetition. Take these functions, roll them into a PHP class, and voila! … easy PHP/OCI8!
To do any database calls, the typical process is as follows:
Meanwhile, during each step in this process you need to check for errors and handle them appropriately. You might encounter an error during the OCILogon or during the OCIParse or during…well, you get the point.
What I’ve attempted to do is abstract this process into a single function prototyped as follows:
/** PUBLIC (stmt_hndl) * Returns the statement handle created from the execution of the SQL * query. If the statement fails, the method returns (false) and the * error is available in $this->ERROR. */ function query($sid, $sql, &$bargs) { ... }
You may notice that this function takes three arguments: SID, SQL, and Bind Args.
SID – The SID is the Oracle database you want to connect to. You’ll notice that I’m not sending the username and password. You’ll see why when you read the next section on abstracting the OCILogin.
SQL – The SQL parameter is the SQL statement you want to run. This is a SELECT, INSERT, UPDATE command…whatever. You might even be calling a chunk of PL/SQL code. Regardless of the query, this function can handle it.
Bind Args – The third parameter is an array of Bind arguments. Bind arguments allow you to pass IN/OUT variables to your SQL queries and enable a syntax of doing queries that don’t require you to escape all your inputs. Once I discovered the use of bind arguments, my Oracle world was forever changed.
Another common problem in the Oracle connectivity world is where the passwords are stored. I’ve seen websites where Oracle usernames and passwords were sprinkled all over the place in this script and in that class. This makes it very difficult to maintain passwords or let alone go through the nightmare of trying to change one! What I’ve done is create another function to act as a password vault. I store the Oracle SID, username, and password as an array of three values which can be fetched by a given key. This way any time I want to connect to the “XYZ” database, I simply ask this function for the Account database name, username and password and get them. Here is a prototype for that function:
/** PRIVATE * Returns the SID, USERNAME, and PASSOWORD used to connect to a given * Oracle database. */ function getDBAuth($sid) { ... }
I’ve briefly pointed to a couple functions that we might want to build that will abstract some of the common Oracle connectivity issues. But the real magic starts to happen once we take these functions and roll them into a tight little ball of OCI8 and functioning code.
The idea here is that we’ll create a class called ‘OCIHook’ that will act as our one-and-only method of talking to Oracle. If you do this, we are guaranteed that every Oracle call is done the same way and that all the logins and passwords will come out of our vault. Hopefully by using this simple API on top of the PHP built-in functionality, we’ll save coding time and energy. So, let’s get to it — here is the OCI8Hook class:
//###################################################################### //## Written by D. Dante Lorenso//---------------------------------------------------------------------- /** PRIVATE * Returns the SID, USERNAME, and PASSOWORD used to connect to a given * Oracle database. */ function getDBAuth($sid) { switch (strtoupper($sid)) { //case "DBXYZ": return (array("usernam1", "secret1", "DBXYZ")); case "DBXYZ": return (array("usernam1", "secret1", "TESTDB")); case "DBABC": return (array("usernam2", "secret2", "DBABC")); case "DB123": return (array("usernam3", "secret3", "DB123")); case "DBHJK": return (array("usernam4", "secret4", "DBHJK")); } // I don't know what to do with this host/SID. return(false); } //---------------------------------------------------------------------- /** PRIVATE * Logs the current message in OCIError to the Apache Log file. This is * done by first including an application-level error code, and the * current PHP page identifier. */ function dumpError($errcode, $errhndl=0) { // retrieve the error message... $error = ($errhndl) ? OCIError($errhndl) : OCIError(); // clean the message... $this->ERROR = trim($error["message"]); // log this error to Apache's error log error_log(sprintf("%s %s %s %s", $errcode, $_SERVER["PHP_SELF"], $error["code"], $this->ERROR)); } //---------------------------------------------------------------------- /** PUBLIC (stmt_hndl) * Returns the statement handle created from the execution of the SQL * query. If the statement fails, the method returns (false) and the * error is available in $this->ERROR. */ function query($sid, $sql, &$bargs) { // clear any previous errors. $this->ERROR = ""; // look up the username, password, and database for this SID $dbauth = $this->getDBAuth($sid); if (empty($dbauth) || ! is_array($dbauth)) { $this->ERROR = "Database Error(1)."; return(false); } // connect to the database... $dbh = @OCILogon($dbauth[0], $dbauth[1], $dbauth[2]); if (! $dbh) { $this->dumpError("OCILogon"); return (false); } // parse the SQL statement... $stmt = @OCIParse($dbh, $sql); if (! $stmt) { $this->dumpError("OCIParse", $stmt); return (false); } // Bind the args into the statement... (ARG[0], VALUE[1], LEN[2]) foreach ($bargs as $barg) { $$barg[0] = $barg[1]; @OCIBindByName($stmt, ":$barg[0]", $$barg[0], $barg[2]); } // execute sql query $rslt = @OCIExecute($stmt); if (! $rslt) { $this->dumpError("OCIExecute(STMT)", $stmt); $this->dumpError("OCIExecute(RSLT)", $rslt); return (false); } // if there are bind args, recover them... $r_bargs = array(); foreach ($bargs as $barg) { $r_bargs[$barg[0]] = $$barg[0]; } $bargs = $r_bargs; // return the sql statement handle upon success return ($stmt); } //---------------------------------------------------------------------- } //###################################################################### //## END OF CLASS //######################################################################//## Free. Do what you want with this. Send money if you can. //###################################################################### class OCI8Hook { var $ERROR = "";
Let’s say you have a PL/SQL stored procedure in Oracle that fetches a mailing address by reading in two IN varchar values and then returns 4 OUT varchar2 values. Your procedure is defined as follows:
PROCEDURE get_mailing_addr ( in_comp_code IN VARCHAR2, in_cust_code IN VARCHAR2, line1 OUT VARCHAR2, line2 OUT VARCHAR2, csz OUT VARCHAR2, zipcode OUT VARCHAR2 );
We can write PHP code that will act as a wrapper for this PL/SQL procedure. The PHP code will connect to the database, send its IN variables, and fetch the OUT variables into bound PHP variables. We’ll ensure that all of the OUT variables are stored in a PHP array and returned to the calling function. The PHP function will be defined as follows:
/** PUBLIC * Return Array containing "LINE1", "LINE2", "CSZ", and "ZIPCODE" as keys * upon success. * Returns false if database error. */ function get_mailing_addr ($comp_code, $cust_code) { ... }
Now, here’s what our PHP function body will look like:
//-------------------------------------------------- /** PUBLIC * Return Array containing "LINE1", "LINE2", "CSZ", and "ZIPCODE" as keys * upon success. * Returns false if database error. */ function get_mailing_addr ($comp_code, $cust_code) {// build the query we'll be sending in... $sql = sprintf(" BEGIN get_mailing_addr ( :IN_COMP_CODE, :IN_CUST_CODE, :LINE1, :LINE2, :CSZ, :ZIPCODE); END; "); // Set up our Bind args... $bargs = array(); array_push($bargs, array("IN_COMP_CODE", $comp_code, -1)); array_push($bargs, array("IN_PREM_CODE", $cust_code, -1)); array_push($bargs, array("LINE1", "", 64)); array_push($bargs, array("LINE2", "", 64)); array_push($bargs, array("CSZ", "", 128)); array_push($bargs, array("ZIPCODE", "", 32)); // run the query... $stmt = $this->query("DBXYZ", $sql, $bargs); if (! $stmt) return(false); // tidy up Line3 into CITY and STATE unset($bargs["IN_COMP_CODE"]); unset($bargs["IN_CUST_CODE"]); // return the bargs results... return($bargs); } //--------------------------------------------------
In case you missed it, the magic happened in the one line that reads:
// run the query... $stmt = $this->query("DBXYZ", $sql, $bargs); if (! $stmt) return(false);
You’ll notice that that line is called ‘$this->query’. Yes, that’s right. The ‘get_mailing_addr’ function is inside another class which EXTENDS OCI8Hook! In fact, this is probably the easiest way to get this connectivity. Any time you want to create a library of PHP calls which WRAP some Oracle calls, just build a class to encapsulate all the functions into a single location, and make that class extend OCI8Hook. Suddenly you can build and run Oracle queries by simply recreating these functions. The connect, logon, bind, parse, and execute pieces of the queries are all handled for you.
OK, so you aren’t gonna let me slide that neat trick in there without an explanation, eh? I created an array of bind variables called ‘bargs’ (short for bind arguments). The ‘bargs’ array is an array of arrays where each sub array contains:
For IN variables, you only need to define a bind argument as array(”IN_NAME”, $value, -1). The -1 means that the length of the variable is not going to change, so who cares.
For OUT variables, you need to define the bind args as array(”OUT_NAME”, “”, 128) where the empty string “” is the current value, and the number 128 is the allocated space for your return data. Remember to make this a large enough value, or you won’t get your output.
The cool thing about using BindByName variables is that you no longer have to do those yuck hacks like escaping quotes and things for your Oracle inputs. Also, you can now write fun little PL/SQL chunks that will do SELECT INTO and fetch your data that way.
In this example, I execute a simple SELECT statement. The input is a customer’s login name, and I select out some made-up columns named COLA, COLB, and COLC from a made up table SAMPLETABLE.
A nice feature of this function is that I might get a return code of false. A ‘FALSE’ return code means that something failed. A failure might occur in the connect, bind, parse, execute…etc. Well, if I really cared, I could look at the $OCI8Hook->ERROR string to read that error message. Most of the time I DON’T care, though…so I give a happy error message to the user and read the Apache log files later.
//---------------------------------------------------------------------- /** * Will select a two dimensional array containing COLA then COLB * which should have access from this login. $data[COLA][COLB]... * Return: * false - System Error * array - Success. */ function simple_select_example($login) { $sql = sprintf(" SELECT COLA, COLB, COLC FROM SAMPLETABLE WHERE LOGIN = LOWER(:IN_LOGIN) ");// Set up our Bind args... $bargs = array(); array_push($bargs, array("IN_LOGIN", $login, -1)); // run the query... $stmt = $this->query("DBXYZ", $sql, $bargs); if (! $stmt) return(false); // loop through the returned rows and convert to a PHP array $data = array(); while (@OCIFetchInto($stmt, $row, OCI_ASSOC | OCI_RETURN_NULLS)) { $data[$row["COLA"]][$row["COLB"]] = 1; } // return the data that we just fetched... return ($data); } //----------------------------------------------------------------------
A lot of Oracle programmers want to have certainty that an insert or update operation was performed successfully. Here is an example where I wrap an INSERT statement in a chunk of PL/SQL so that I’ll get a clear success code of ‘7′ when the insert works. Remember that our OCI8Hook class always returns ‘false’ on error. So, if we get a FALSE from this function, we still assume an error. I need an error code which is NOT 0 or false or “” in order to ensure success. Here is my solution:
//---------------------------------------------------------------------- /* * Return * 0 - System Error * 7 - Success */ function sample_insert($value1, $value2, $value3) { // build the query we'll be sending in... $sql = sprintf(" BEGIN :RETURN_CODE := 0; INSERT INTO sampletable (cola, colb, colc) VALUES (LOWER(:IN_VALUE1), UPPER(:IN_VALUE2), LOWER(:IN_VALUE3)); :RETURN_CODE := 7; EXCEPTION WHEN OTHERS THEN :RETURN_CODE := 0; END; ");// Set up our Bind args... $bargs = array(); array_push($bargs, array("IN_VALUE1", $value1, -1)); array_push($bargs, array("IN_VALUE2", $value2, -1)); array_push($bargs, array("IN_VALUE3", $value3, -1)); array_push($bargs, array("RETURN_CODE", "", 32)); // run the query... $stmt = $this->query("DBXYZ", $sql, $bargs); if (! $stmt) return(false); // return the return code (if it's there)... if (array_key_exists("RETURN_CODE", $bargs)) { return ($bargs["RETURN_CODE"]); } // it doesn't seem to be working... return(false); } //----------------------------------------------------------------------
We created that OCI8Hook class with database login and password abstraction for a reason. In many corporations, you’ll have multiple environments. You’ll want to build your code against the development environment, test it on a QA environment and finally, if all goes well, send it out to a production environment. Well, that’s one more advantage to having your connection strings abstracted into the function getDBAuth($sid) { ... } function.
To toggle between enviroments, simply change the connect string for your DBNAME. Say I’m running all my queries against ‘DBXYZ’ with the following $stmt = $this->query("DBXYZ", $sql, $bargs);. Change the connect string from this:
case "DBXYZ": return (array("usernam1", "secret1", "DBXYZ"));
to something like this:
case "DBXYZ": return (array("usernam1", "secret1", "TESTDB"));
Or if you wanted to be really fancy, you might consider sticking an IF statement in there like this:
case "DBXYZ": if (--I'm on the DEV environment--) { return (array("usernam1", "secret1", "DEVDB")); else if (--I'm on the QA environment--) { return (array("usernam1", "secret1", "TESTDB")); } else { return (array("usernam1", "secret1", "PRODDB")); } ...
The code I’ve shown you in this article may or may not work exactly from your cut-and-paste. However, I use this same structure for writing all the Oracle connectivity on my current projects…so I know it works. By abstracting the authentication to a single location, I can manage my application’s connection strings much easier. By using the ‘query’ function for encapsulating all queries, I gain a significant speed up in application development time. It also helps to keep the code broken into distinct classes or ‘objects’. When it comes time to hunting down problems and making enhancements, you’ll be glad you abstracted the complicated portions of your PHP code so that you can concentrate on the true business logic.
—
By Dante Lorenso
13 Aug
Posted by ProCOM
on August 13, 2007 – 11:24 pm - 614 views
![]() | ![]() | ![]() | ![]() | ![]() | ![]() |
![]() | ![]() | ![]() | ![]() | ![]() | ![]() |
![]() | ![]() | ![]() | ![]() | ![]() | ![]() |
![]() | ![]() | ![]() | ![]() | ![]() | ![]() |
![]() | ![]() | ![]() | ![]() | ![]() | ![]() |
![]() | ![]() | ![]() | ![]() | ![]() | ![]() |
![]() | ![]() | ![]() | ![]() | ![]() | ![]() |
| By N2H | |||||