PHP5 and customization exceptions for OOP programming

Source: Internet
Author: User
Tags continue count error handling exception handling execution functions implement string back
One, Dbquery object

Now, our Dbquery object simply imitates a stored procedure-once executed, returns a result resource that must be saved, and if you want to use a function on the result set (such as num_rows () or Fetch_row ()), you must pass the MySQLdb object. So how does it work if the Dbquery object implements a MySQLdb object that is designed to operate on the result of a query? Let's continue to use the code in the previous example, and let's assume that our result resources are now managed by the Dbquery object. The source code for the Dbquery class is shown in Listing 1.

List 1. Use the Dbquery class.

Require ' mysql_db.php ';
Require_once ' query.php ';
$db = new MySQLdb;
$db->connect (' host ', ' username ', ' pass ');
$db->query (' use Content_management_system ');
$query = new Dbquery ($DB);
$query->prepare (' SELECT fname,sname from users WHERE username=:1s and pword=:2s and Expire_time<:3i ');
try {
if ($query->execute ("Visualad", "apron", Time ()))->num_rows () = = 1) {
Echo (' correct Credentials ');
} else {
Echo (' Incorrect credentials/session expired ');
}
catch (Queryexception $e) {
Echo (' Error executing query: '. $e);
}

What we are most interested in in the modified code above is the catch statement and the EXECUTE statement.

· The EXECUTE statement no longer returns a result resource, and now it returns the Dbquery object itself.

· The Dbquery object now implements the Num_rows () function-we are already familiar with the DB interface.

· If the query execution fails, it throws an exception of the queryexception type. When converted to a string, it returns the details of the error that occurred.

To do this, you need to use a proxy. In fact, you've already used proxies in our Dbquery object, but now we're going to use it more intensively to tie it tightly to the MySQLdb object. The Dbquery object has been initialized with an object that implements the DB interface, and it already contains a member function execute-the query () method that calls the DB object to execute it. The Dbquery object itself does not actually query the database, it is done by the DB object. This is the proxy, in fact, a process--with this process, an object can implement a particular behavior by sending the message to another object that implements the same or similar behavior.

To do this, you need to modify the Dbquery object to include all functions-they manipulate a result resource from the DB object. When you execute a query to call the corresponding function of the DB object and return its results, you need to use the stored results. The following functions will be added:

Listing 2: Using the proxy extension Dbquery class.

Class Dbquery
{
.....

Public Function Fetch_array ()
{
if (! Is_resource ($this->result)) {
throw new Exception (' Query not executed. ');
}
return $this->db->fetch_array ($this->result);
}

Public Function Fetch_row ()
{
if (! Is_resource ($this->result)) {
throw new Exception (' Query not executed. ');
}
return $this->db->fetch_row ($this->result);
}

Public Function Fetch_assoc ()
{
if (! Is_resource ($this->result)) {
throw new Exception (' Query not executed. ');
}
return $this->db->fetch_assoc ($this->result);
}

Public Function Fetch_object ()
{
if (! Is_resource ($this->result)) {
throw new Exception (' Query not executed. ');
}
return $this->db->fetch_object ($this->result);
}

Public Function Num_rows ()
{
if (! Is_resource ($this->result)) {
throw new Exception (' Query not executed. ');
}
return $this->db->num_rows ($this->result);
}
}

The implementation of each function is fairly straightforward. It first checks to make sure that the query has been executed and then proxies the task to the DB object, returning it as if it were the query object itself (called the basic database function).

   II. type hint (types hinting)

In order for the agent to work, we need to ensure that the $db variable of the Dbquery object is an instance of an object that implements the DB interface. Type hints are a new feature in PHP 5 that enables you to cast function arguments to a specific type of object. Before PHP 5, the only way to ensure that a function argument is a specific object type is to use the type-checking function provided in PHP (also known as is_a ()). Now you can simply cast the object type-by adding the type name before the function argument. You have seen a type hint from our Dbquery object to ensure that an object that implements the DB interface is passed to the object builder.

Public function __construct (DB $db)
{
$this->db = $db;
}


When you use a type hint, you can specify not only the object type, but also the abstract class and interface.

Three, throw an exception

you may have noticed from the above code that you are catching an exception called queryexception (we will implement this object later). An exception is similar to an error, but it is more general. The best way to describe an exception is to use emergency. Although a emergency can not be "fatal", it must be dealt with. When an exception is thrown in PHP, the current scope of execution is quickly terminated, regardless of whether it is a function, try ... Catch block or the script itself. The exception then traverses the call stack-terminates each execution scope until or in a try. Caught in a catch block or it reaches the top of the call stack-it will generate a fatal error.

Exception Handling is another new feature in PHP 5, which enables good control of error handling and reporting when it is associated with OOP. a try. A catch block is an important mechanism for handling exceptions. Once captured, the script will continue to execute from the next line of code that is caught and processed by the exception.

If the query fails, you need to change your execute function to throw an exception. You will throw a custom exception object called Queryexception-the Dbquery object that caused the error to be passed to it.

List 3. Throws an exception.

/**
* Execute Current Query
*
* Execute current query-replace any bit with supplied arguments
* .
*
* @ parameter: Mixed $queryParams, ... Query parameters
* @ return: Resource A reference describes the resource that executes the query.
*/
Public Function Execute ($queryParams = ')
{
For example: SELECT * from table WHERE name=:1s and Type=:2i and level=:3n
$args = Func_get_args ();
if ($this->stored_procedure) {
/* Call compile function to get query * *
$query = Call_user_func_array (Array ($this, ' compile '), $args);
} else {
/* A stored procedure is not initialized, therefore, as a standard query to execute the * *
$query = $queryParams;
}
$result = $this->db->query ($query);
if (! $result) {
throw new Queryexception ($this);
}
$this->result = $result;
/* Notice how we now return the object itself, which allows us to invoke the member function from the return result of this function
*/
return $this;
}

   Iv. using inheritance to throw custom exceptions

In PHP, you can throw any object as an exception, but first the exception should inherit from PHP's built-in exception class. By creating your own custom exception, you can record other information about the error, such as creating an entry in a log file or doing anything you like. Your custom exception is going to do the following several things:

· Log the error message from the DB object generated by the query.

· Give exact details of the line code where the query error occurred-by checking the call stack.

· Displays error messages and query text-when converted to a string.

To get error messages and query text, you need to make multiple changes to the Dbquery object.

1. A new protected property-compiledquery-needs to be added to the class.

2. The compile () function updates the query CompiledQuery properties using query text.

3. A function that retrieves the compiled query text should be added.

4. You should also add a function-it gets the DB object that is currently associated with the Dbquery object.

Listing 4. Throws an exception.

Class Dbquery
{
/**
* Store the compiled version of the query after calling compile () or execute ()
*
* @var String $compiledQuery
*/
protected $compiledQuery;
/**
* Returns a compiled query without executing it.
* @ parameter: Mixed $params, ... Query parameters
* @ return: string-compiled query
*/
Public function compile ($params = ')
{
if (! $this->stored_procedure) {
throw new Exception ("stored procedure not initialized.");
}
/* Instead of parameters * *
$params = Func_get_args (); Get the function parameters
$query = Preg_replace ("/() Compile_callback ($params, 1," 2 ") ', $this->query);
return ($this->compiledquery = $this->add_strings ($query)); Put the string back in the query
}
Public Function Getdb ()
{
return $this->db;
}
Public Function Getcompiledquery ()
{
return $this->compiledquery;
}
}

Now you can implement the Queryexception class. Notice how you traverse the call stack to find the location in the script that actually caused the error. This applies precisely when the Dbquery object that throws an exception is a subclass of a Dbquery object that inherits from it.

List 5:queryexception class.

/**
* Query exception
*
* If an error occurs when an attempt is made to execute a query, an error is thrown by the {@link Dbquery} object
*/
Class Queryexception extends Exception
{
/**
* Query Text
*
* @var string $querytext;
*/
protected $QueryText;
/**
* Error number/code from the database
*
* @var String $errorcode
*/
protected $ErrorNumber;
/**
* Error messages from the database
*
* @var String $errormessage
*/
protected $ErrorMessage;
/**
* Class Builder
*
* @ parameter: Dbquery $db, is the query object that throws an exception
*/
Public function __construct (dbquery $query)
{
/* Get Call stack * *
$backtrace = $this->gettrace ();
/* Set the rows and files to where the error actually occurred.
if (count ($backtrace) > 0) {
$x = 1;
/* If the query class is inherited, then we need to ignore the call made by the subclass.
while (! isset ($backtrace [$x] [' line ']) | |
(Isset ($backtrace [$x] [' class ']) && is_subclass_of ($backtrace [$x] [' class '], ' dbquery ')] | |
(Strpos (Strtolower (@ $backtrace [$x] [' function ']), ' Call_user_func ')!== false) {
/* loop execution, as long as there is no line number or called function is a subclass of the Dbquery class * *
+ + $x;
/* If we reach the bottom of the stack, then we use the first caller/
if (($x) >= count ($backtrace)) {
$x = count ($backtrace);
Break
}
}
/* If the above loop is executed at least once, then we can subtract it by 1 to find the actual line of code that caused the error
*/
if ($x!= 1) {
$x-= 1;
}
/* Finally, we can set the file and line number, which should reflect the SQL statement that caused the error.
$this->line = $backtrace [$x] [' line '];
$this->file = $backtrace [$x] [' file '];
}
$this->querytext = $query->getcompiledquery ();
$this->errornumber = $query->getdb ()->errno ();
$this->errormessage = $query->getdb ()->error ();
/* Call exception constructor for superclass * *
Parent::__construct (' Query Error ', 0);
}
/**
* Get the query text
*
* @ return string query text
*/
Public Function Getquerytext ()
{
return $this->querytext;
}
/**
* Get the error number
*
* @ return string error number
*/
Public Function Geterrornumber ()
{
return $this->errornumber;
}
/**
* Get the error message
*
* @ return string error message
*/
Public Function GetErrorMessage ()
{
return $this->errormessage;
}
/**
* Called when the object is converted to a string.
* @ return string
*/
Public Function __tostring ()
{
$output = "Query Error in {$this->file} to line {$this->line}nn";
$output. = "Query: {$this->querytext}n";
$output. = "Error: {$this->errormessage} ({$this->errornumber}) nn";

return $output;
}
}

At this point, the code you see at the beginning of this section works.

   v. Conclusion

In this article, you see how the agent maps the DB interface associated with the query to an operation on a particular query result. The Dbquery object exposes the same function, such as FETCH_ASSOC (), as the DB object. However, these all work against a single query. You also learned how to use custom exceptions to give details-when and where an error occurred, and how they better control the handling of the error.



Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.