Throwing Basic Exceptions When Auto Loading Classes in PHP 5

Welcome to the second part of the series that began with “Auto loading classes in PHP 5.” Comprised of four approachable tutorials, this series walks you through the key concepts you need to understand how to automatically include classes with PHP 5, without having to use the popular include functions that are provided by this powerful server-side scripting language.

Introduction

As you may have heard, PHP 5 introduces the “__autoload()” magic function within its improved object model. This function can be very useful for loading automatically all of the source classes required by your object-oriented applications. Of course, this feature can be a real time saver if you frequently work with classes during the development of your web projects. So if you’re interested in learning how to put this handy function to work for you with minor hassles, then this series of articles might be what you’re looking for.

Now that I’ve introduced you to the main subject of the series, I’m going to spend a few moments refreshing the topics that were covered in the preceding article. This will help you understand much more easily how that tutorial links with this one.

As you’ll surely recall, during the previous part of the series, I guided you through the process of using the “__autoload()” magic function that comes with PHP 5 to facilitate the inclusion of all the source classes required by a certain PHP application that uses the object-oriented paradigm to work as expected.

Specifically, in that article I showed you how to implement a simple database-driven application whose primary goal was to fetch some basic data from an “Users” MySQL database table. The application would then display this information on the browser using a couple of MySQL processing classes.

Of course, as you might recall, the most important thing to highlight here is that I demonstrated by means of two illustrative code samples how to load the respective source classes required by the database-driven application. We used a couple of conventional PHP 5 includes first, and then I showed you how to utilize the capacity of the handy “__autoload()” magic function.

Undoubtedly, this function makes it really easy to include automatically into client code all the classes that are required by a concrete object-based application. Assuming that the "_autoload()" magic function has been adequately implemented, there’s no need to use multiple includes to accomplish this task. Whether you’re including one or ten classes into a specific script, the function will perform the inclusion task neatly.

So far, I have refreshed the basic concepts surrounding the utilization of the “__autoload()” magic function in the context of a simple database-driven application, which hopefully will provide you with the right pointers to start using it within your own PHP projects as soon as possible. However, it should be noted that the PHP manual says that any exceptions thrown by this function during its execution simply won’t be caught by a “try-catch()” block. This could be rather problematic, particularly if you use to build PHP 5 applications that include exception-based error handling modules.

Thus, bearing in mind this intrinsic limitation exposed by the “__autoload()” magic function when it comes to triggering exceptions at runtime, in this second article  of the series I’m going to show you some basic workarounds that you can implement to provide this function with the ability to throw exceptions when a determined source class fails to be included.

So, let’s not waste more time in preliminaries and learn together how to expand the native functionality of the “__autoload()” magic function. Let’s get started now!

{mospagebreak title=Two examples of the _autoload() PHP 5 function}

Before I show you how to implement a basic error handling mechanism that works in conjunction with the “__autoload()” PHP 5 magic function, first I’d like you to recall the respective signatures of the two examples that I built in the previous articles of the series. As you recall, the first one showed how a primitive database-driven application used a couple of “require_once()” PHP functions to load into client code all of its source classes, and the second case performed this same task, but this time using the “__autoload()” function.

Having said that, I’m going to start listing the definitions of the two MySQL processing classes that I used with the examples, which resided on different files. The first of these classes was called “MySQL,” and was stored on a “mysql.php” file. It was defined in the following way:

(definition of mysql.php file)


<?php

class MySQL{

private $host;

private $user;

private $password;

private $database;

private $connId;

// constructor

function __construct($options=array()){

if(!is_array($options)){

throw new Exception(‘Connection options must be an array’);

}

foreach($options as $option=>$value){

if(empty($option)){

throw new Exception(‘Connection parameter cannot be empty’);

}

$this->{$option}=$value;

}

$this->connectDb();

}

// private ‘connectDb()’ method

private function connectDb(){

if(!$this->connId=mysql_connect($this->host,$this->user,$this->password)){

throw new Exception(‘Error connecting to MySQL’);

}

if(!mysql_select_db($this->database,$this->connId)){

throw new Exception(‘Error selecting database’);

}

}

// public ‘query()’ method

public function query($sql){

if(!$result=mysql_query($sql)){

throw new Exception(‘Error running query ‘.$sql.’ ‘.mysql_error());

}

return new Result($this,$result);

}

}

?>


Now that you have seen the definition of the PHP file that housed the previous “MySQL” class, please take a look at “result.php,” which contained another class, named “Result”:

(definition of result.php file)


<?php

class Result{

private $mysql;

private $result;

// constructor

public function __construct($mysql,$result){

$this->mysql=$mysql;

$this->result=$result;

}

// public ‘fetch()’ method

public function fetch(){

return mysql_fetch_array($this->result,MYSQL_ASSOC);

}

// public ‘count()’ method

public function count(){

if(!$rows=mysql_num_rows($this->result)){

throw new Exception(‘Error counting rows’);

}

return $rows;

}

// public ‘get_insertId()’ method

public function getInsertId(){

if(!$insId=mysql_insert_id($this->mysql->connId)){

throw new Exception(‘Error getting insert ID’);

}

return $insId;

}

// public ‘seek()’ method

public function seek($row){

if(!int($row)&&$row<0){

throw new Exception(‘Invalid row parameter’);

}

if(!$row=mysql_data_seek($this->mysql->connId,$row)){

throw new Exception(‘Error seeking row’);

}

return $row;

}

// public ‘getAffectedRows()’ method

public function getAffectedRows(){

if(!$rows=mysql_affected_rows($this->mysql->connId)){

throw new Exception(‘Error counting affected rows’);

}

return $rows;

}

}

?>


So far, so good. At this point you hopefully recalled the respective signatures of the two source classes listed above, so take a close look at the following hands-on examples. The first one uses a pair of simple PHP includes to load these classes into client code, and the final one utilizes the “__autoload()” function instead to do this.

Here are the corresponding code samples:

(example using conventional PHP includes)


try{

// include required classes

require_once ‘mysql.php';

require_once ‘result.php';

// connect to MySQL

$db=new MySQL(array
(‘host’=>’host’,’user’=>’user’,’password’=>’password’,
‘database’=>’database’));

// fetch users from database table

$result=$db->query(‘SELECT * FROM users ORDER BY id’);

// display user data

while($row=$result->fetch()){

echo ‘Id: ‘.$row['id'].’ First Name: ‘.$row['firstname'].’ Last Name: ‘.$row
['lastname'].’ Email: ‘.$row['email'].'<br />';

}

}

catch(Exception $e){

echo $e->getMessage();

exit();

}



// example using the magic ‘__autoload()’ function


function __autoload($className){

require_once $className.’.php';

}

try{

// connect to MySQL

$db=new MySQL(array
(‘host’=>’host’,’user’=>’user’,’password’=>’password’,
‘database’=>’database’));

// fetch users from database table

$result=$db->query(‘SELECT * FROM users ORDER BY id’);

// display user data

while($row=$result->fetch()){

echo ‘Id: ‘.$row['id'].’ First Name: ‘.$row['firstname'].’ Last Name: ‘.$row
['lastname'].’ Email: ‘.$row['email'].'<br />';

}

}

catch(Exception $e){

echo $e->getMessage();

exit();

}

 

As you can see, the above examples look nearly the same, at least when analyzed superficially. However, you’ll notice that the last code sample uses the handy “__autoload()” function to include the respective “MySQL” and “Result” classes that you saw before. Of course, the major advantage in utilizing this function is that it allows you to easily load multiple classes behind the scenes, without having to explicitly declare several “require_once()” PHP functions. Quite convenient, right?

Now that I provided you with two comparative examples of loading source classes onto a basic database-driven application using well-differentiated approaches (naturally, both are valid), it’s time to see how to improve the existing capacity of the “__autoload()” magic function. Our next step will be incorporating a simple error handling mechanism into it, which can be useful for triggering different errors when a given object-oriented application fails to include a certain source class into client code.

To see how this error processing capability will be added to the “__autoload()” function, please click on the link that appears below and keep reading.

{mospagebreak title=Triggering fatal errors with the _autoload() PHP 5 function}

As I explained in the introduction of this article, if an exception is thrown during the execution of the magic “__autoload()” function, it simply won’t be caught by a “try-catch()” block, as you’d normally expect with other PHP native functions. Most likely, the function in question will trigger a fatal error instead, if for whatever reason, a source class can’t be included into client code.

But this is only a theory, so see for yourself what happens when the file that contains the previous “Result” class is not available to be included into the sample script that you learned before:

(in this example the “result.php” file is not available)


function __autoload($className){

require_once $className.’.php';

}

try{

// connect to MySQL

$db=new MySQL(array
(‘host’=>’host’,’user’=>’user’,’password’=>’password’,
‘database’=>’database’));

// fetch users from database table

$result=$db->query(‘SELECT * FROM users ORDER BY id’);

// display user data

while($row=$result->fetch()){

echo ‘Id: ‘.$row['id'].’ First Name: ‘.$row['firstname'].’ Last Name: ‘.$row
['lastname'].’ Email: ‘.$row['email'].'<br />';

}

}

catch(Exception $e){

echo $e->getMessage();

exit();

}


// Fatal error: __autoload() [function.require]: Failed opening required ‘Result.php’ (include_path=’.;include/path/) in path/to/file


As you can see, the above hands-on example demonstrates in a nutshell what happens when one of the source classes (in this case, the one called “Result”) required by the previous script isn’t available to be included into client code. In simple words, the script will complain about this problem by triggering a fatal error similar to the one show before.

Undoubtedly, from a programmer’s point of view a crude fatal error might not be the best option when it comes to handing a failure that happened when trying to include a specific source class. So, is there a more efficient and elegant solution to deal with this type of error when using the “__autoload()” function? Fortunately, the answer to this question is an emphatic yes!

As you’ll see in the section to come, it’s possible to implement a simple workaround which will make this function throw an exception when, for whatever reason, it fails to load a determined source class.

To learn how this workaround will be developed, please go ahead and read the last section of this article. We’re almost done!

{mospagebreak title=Developing a simple mechanism to throw exceptions}

In accordance with the concepts I deployed in the previous section, it’s perfectly feasible to implement a simple workaround that provides the handy “__autoload()” function with the ability to throw an exception when one source class can’t be loaded onto a given PHP 5 application.

This rather tricky solution consists of creating the troubling class via an “eval()” command, and then explicitly throwing an exception. Logically this concept will be better grasped if you take a close look at the following example. Here it is:

// include required classes (the magic ‘__autoload()’ function now throws an exception when some of the required classes are not found)


function __autoload($className){

if(!file_exists($className.’.php’)){

eval("class $className {}");

throw new Exception(‘Class not found’);

}

require_once $className.’.php';

}

try{

// connect to MySQL

$db=new MySQL(array
(‘host’=>’host’,’user’=>’user’,’password’=>’password’,
‘database’=>’database’));

// fetch users from database table

$result=$db->query(‘SELECT * FROM users ORDER BY id’);

// display user data

while($row=$result->fetch()){

echo ‘Id: ‘.$row['id'].’ First Name: ‘.$row['firstname'].’ Last Name: ‘.$row
['lastname'].’ Email: ‘.$row['email'].'<br />';

}

}

catch(Exception $e){

echo $e->getMessage();

exit();

}


As shown above, the “__autoload()” magic function has been implemented by using the workaround that I mentioned before. As you can see, the function first check for the existence of the files that contain the corresponding source classes, and if this process fails for some reason, it tries to create the problematic class using the “eval()” function. Finally, the function throws an explicit exception, in this way implementing a basic error handling mechanism. Nothing too complex, right?

Besides, if you first remove the pertinent “mysql.php” file and test the prior example on your own web server, you’ll get an error similar to the one shown below:

Fatal error: Function __autoload(MySQL) threw an exception of type ‘Exception’ in path/to/file

Indeed, this is an advance with reference to the raw fatal error that you saw earlier. As you can see, the “__autoload()” function now is capable of launching an exception, although it still won’t be caught by a “try-catch()” block.

However, that’s all the code samples that I’m going to show you for the moment. I recommend that you test all of the examples developed in this tutorial to see how they react when a source class can’t be loaded as expected. It’s an instructive experience, trust me.

Final thoughts

In this second installment of the series you hopefully learned how to implement a simple workaround within the handy “__autoload()” magic function to incorporate into it the capacity to throw exceptions when a specific source class is not included. Nonetheless, this quick and dirty exception mechanism isn’t completely functional yet, since a conventional “try-catch()” block won’t be able to intercept these exceptions.

However, this issue will be fixed in the next part of the series, so I hope to see you there!

[gp-comments width="770" linklove="off" ]

antalya escort bayan antalya escort bayan Antalya escort diyarbakir escort