A Polymorphism problem - Part 2
So I’m back with part two of my problems I’ve had with polymorphism. In part one I talked about ways of getting around not being able to assign a base class to a derived class (of that base class). Previously, I said that all you need to do is just assign all variables and such in a constructor to the new class variables, thereby making a “copy” of the class.
While this sort of works in theory, it doesn’t quite work in practice. It’ll work with simple classes, or classes that you design to work that way, but it’s not really what I wanted.
What I wanted isn’t really good practice, so now I’m going to show you how I really ended up creating my extended classes for the mysqli libraries. I’m just going to work with the mysqli and mysqli_stmt objects, but you can apply the same concepts to other objects.
First we create our two basic classes as follows
class mySQL extends mysqli { } class mySQL_stmt extends mysqli_stmt { }
Simple enough really. So lets move on to the constructors. I changed the functionality here a little. I created these new objects because I wanted them to throw exceptions, rather than just return error values. For this reason, I don’t believe that you should do the actual connection in the constructor of the object.
So here’s the constructors along with the added connect function, which throws an exception when it can’t connect.
class mySQL extends mysqli { // Connection Variables var $dbConnection = null; var $dbServer = null; var $dbDatabase = null; var $dbUsername = null; var $dbPassword = null; var $CONNECTED = false; function __construct($server, $username, $password, $database) { $this->dbServer = $server; $this->dbDatabase = $database; $this->dbUsername = $username; $this->dbPassword = $password; } function connect() { parent::__construct($this->dbServer, $this->dbUsername, $this->dbPassword, $this->dbDatabase); if ($this->connect_error) { throw new Exception($this->connect_error, $this->connect_errno); } $this->CONNECTED = true; } } class mySQL_stmt extends mysqli_stmt { function __construct($link, $query) { parent::__construct($link, $query); } }
The mySQL_stmt functionality is rather simple at this point, we’re simple duplication the constructor. You could in actual fact not even bother. If you don't define a constructor, the parent constructor will be called instead. I just like to keep in practice of always defining a constructor.
Lets talk about the mySQL object, which is a little different. We override the parent constructor with our own constructor and assign the variables needed for the connection. Previously, in the mysqli object, the connection to the DB was actually done here. As I said, I don’t think this is the correct way of doing things. The variables are public, but you can make them private this way too, as you shouldn’t really need to access them at all.
We then create a function called mySQL::connect(). This function simply calls the parent constructor with the variables we assigned in our new constructor. In the parent constructor, the connection takes place. If the connection fails, a error value will be assigned to mysqli-->connect_error, so by checking this value, we can check if the connection has been successful. If there is an error, we simple throw an Exception (which is another object). If you don’t already know what throw is, it’s basically a glorified return statement. If the connection has been successful, we set a value to say so.
Here’s an example using the new classes.
include "mysql.php"; $mySQL = new mySQL("localhost", "username", "password", "database"); try { $mySQL->connect(); } catch (Exception $err) { echo "There was an SQL error: ". $err->getMessage(); }
I’m not going to go into the try and catch parts of the code, there is enough documentation oh php.net. As you can see its reasonably simple in functionality, yet quite powerful in terms of what you can achieve with it.
Now lets jump forward a bit and deal with the problem I was actually trying to solve. We have the mysqli::prepare() method that returns a mysqli_stmt object. Problem is, I never really understood how it was doing it. It never occurred to me, that all it was doing, was creating the object in the method and returning what it had created. Pretty stupid of me really. So here’s our new mySQL::prepare() function.
class mySQL extends mysqli { // Connection Variables var $dbConnection = null; var $dbServer = null; var $dbDatabase = null; var $dbUsername = null; var $dbPassword = null; var $CONNECTED = false; function __construct($server, $username, $password, $database) { $this->dbServer = $server; $this->dbDatabase = $database; $this->dbUsername = $username; $this->dbPassword = $password; } function connect() { parent::__construct($this->dbServer, $this->dbUsername, $this->dbPassword, $this->dbDatabase); if ($this->connect_error) { throw new Exception($this->connect_error, $this->connect_errno); } $this->CONNECTED = true; } function prepare($query) { $stmt = new mySQL_stmt($this, $query); if($stmt==false) { throw new Exception(.$this->error, $this->errno); } return $stmt; } }
So now I have duplicated the functionality that we had have with the mysqli::prepare() statement, except that we are once again, getting exceptions, rather than error codes.
Before I give an example, I’m going to move onto another problem I ran into, it’s not really related to polymorphism, but rather limitations you’ll run into when extending functions in PHP.
In the mysqli_stmt, there is a function called mysqli_stmt::bind_result(), which takes any amount of parameters of any type. Now this usually wouldn’t be a problem, as there are number of ways of accessing the variables. The problem is they are passed in by reference. The reason for this because the values are bound to the results from the database, you can then move through the results, but only have to access one variable, rather than an array of columns or rows, etc.
So we can’t extend the function exactly the way it is, but we can create another function, with similar functionality. Instead of passing in a number of params, we pass in an array, which contains the variables. The variables are stored in the array by address.
First lets show the function, then we’ll go through using the code.
class mySQL_stmt extends mysqli_stmt { function __construct($link, $query) { parent::__construct($link, $query); } function bindResult($argsArray) { $func = array($this, 'bind_result'); if(call_user_func_array($func, $argsArray) === false) { throw new Exception($this->error, $this->errno); } } }
As you can see, we use the call_user_func_array() to get this done. There are other ways of getting it done, so that it’s “transparent” to the person using the objects and they just pass the vars in like they would have before, but it’s long winded and outside the scope of what I wanted to achieve here, so we’ll settle for this for now and hopefully cover this down the road some time. Again, you can read up on it at php.net.
Here’s the full objects that I will be using, I’m not going to cover the extra functions, it should mostly be obvious as to what they do as they’re either copies of other functions, or combine the functionality of other parent functions.
class mySQL extends mysqli { /* My SQL extension * Exends the mysqli functions that I use * to throw exceptions */ // Connection Variables var $dbConnection = null; var $dbServer = null; var $dbDatabase = null; var $dbUsername = null; var $dbPassword = null; var $CONNECTED = false; // Query Variables var $queryStr = null; function __construct($server, $username, $password, $database) { $this->dbServer = $server; $this->dbDatabase = $database; $this->dbUsername = $username; $this->dbPassword = $password; } function connect() { parent::__construct($this->dbServer, $this->dbUsername, $this->dbPassword, $this->dbDatabase); if ($this->connect_error) { throw new Exception($this->connect_error, $this->connect_errno); } $this->CONNECTED = true; } function execQuery($query) { $return = $this->real_query($query); if($return != true) { throw new Exception($this->error, $this->errno); } $result = $this->use_result(); if($result == false) { throw new Exception($this->error, $this->errno); } return $result; } function prepare($query) { $stmt = new mySQL_stmt($this, $query); if($stmt==false) { throw new Exception($this->error, $this->errno); } return $stmt; } function freeResults() { while ($this->next_result()) { //free each result. $result = $this->use_result(); if ($result instanceof mysqli_result) { $result->free(); } } } } class mySQL_stmt extends mysqli_stmt { function __construct($link, $query) { parent::__construct($link, $query); } function bindResult($paramsArray) { $func = array($this, 'bind_result'); if(call_user_func_array($func, $paramsArray) === false) { throw new Exception($this->error, $this->errno); } } function executeStmt() { if($this->execute() == false) { throw new Exception($this->error, $this->errno); } if($this->store_result() == false) { throw new Exception($this->error, $this->errno); } } function closeStmt() { $this->free_result(); if($this->close() == false) { throw new Exception($this->error, $this->errno); } } }
And here is the code using the objects.
include "mysql.php"; $sql = "CALL spMyStoredProc"; $mySQL = new mySQL("localhost", "username", "password", "database"); $bindVar1 = null; $bindVar2= null; try { $mySQL->connect(); $stmt = $mySQL->prepare($sql); $stmt->executeStmt(); $stmt->bindResult(array(&$bindVar1, &$bindVar2)); while($stmt->fetch()) { echo "Column 1: ".$bindVar1."; Column 2: ".$bindVar2."\n"; } $stmt->reset(); $stmt=null; } catch (Exception $err) { echo "There was an SQL error: ". $err->getMessage(); }
So a quick run down of what’s happening here. We obviously create our sql string that we are going to execute. This stored procedure returns 2 columns of data and we’re going to need to variables for binding to those columns, so I’ve created $bindVar1 and $bindVar2. Then we open up our try/catch block of code and start our connection. We then prepare our sql statement for execution and then actually execute it. Once it’s been executed, we bind the variables to the result and the go though the results, outputting the variables. Once we’re done with that, we reset the statement and then null it (I had problem when I didn’t null it).
Now quite a few php programmers will be turning their nose up at this point as they don’t see the point of the whole try/catch way of doing things, after all, error codes work fine right?
Well, it boils down to what you like and how you want things to work. I’ve come to enjoy working with objects and the functionality and security I get from working in try/catch blocks of code, which is why I created the objects the way I did.
You don’t have to do things the way everyone else is doing it, try your own way, you’ll be more comfortable.
Coming soon - Wordpress hacking and what I've learnt about CSS.
Syn

Recent comments
18 weeks 4 days ago
36 weeks 5 days ago
36 weeks 5 days ago
38 weeks 2 days ago
45 weeks 2 days ago
2 years 11 weeks ago
2 years 12 weeks ago
2 years 12 weeks ago
2 years 12 weeks ago
2 years 12 weeks ago