Agent and customization exceptions in PHP5OOP programming

Source: Internet
Author: User
Tags string back
1. DBQuery object currently, our DBQuery object simply imitates a stored procedure-once executed, it returns a result resource that must be saved; and if you want to use functions in the result set (such as num_rows () or fetch_row (), you must pass the MySQLDB object. Then, if the DBQuery object is used to implement the MySqlDB object (which is designed to operate on a query execution result), function 1 and DBQuery object

Now, our DBQuery object simply imitates a stored procedure-once executed, it returns a result resource that must be saved; and if you want to use functions in the result set (such as num_rows () or fetch_row (), you must pass the MySQLDB object. So what if the DBQuery object is used to implement the function of MySqlDB object (which is designed to operate on a query execution result? Let's continue to use the code in the previous example. let's assume that the DBQuery object manages our result resources. The source code of the DBQuery class is shown in list 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 =: 1 s and pWord =: 2 s and expire_time <: 3i ');
Try {
If ($ query-> execute ("visualad", "apron", time ()-> num_rows () = 1 ){
Echo ('correct credentials ');
} Else {
Echo ('encrect Credentials/session expired ');
}
} Catch (QueryException $ e ){
Echo ('error executing query: '. $ e );
}

In the code modified above, we are most interested in catch and execute statements.

· The execute statement no longer returns a result resource. now it returns the DBQuery object itself.

· The DBQuery object now implements the num_rows () function-we are familiar with it from the DB interface.

· If the query fails, it throws a QueryException type exception. When converted into a string, it returns the details of the error.

Therefore, you need to use a proxy. In fact, you have used a proxy in our DBQuery object, but now you will use it more deeply to closely bind it to the MySqlDB object. This DBQuery object has been initialized using an object that implements the DB interface, and it already contains a member function execute-it calls the query () method of the DB object to execute this query. This DBQuery object does not actually query the database. it submits this task to the DB object. This is a proxy. it is actually a process-by sending messages to another object that implements the same or similar behavior, an object can implement a special behavior.

Therefore, you need to modify the DBQuery object to include all the functions-they operate on 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:

List 2: use a proxy to expand the 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 quite simple. It first checks to ensure that the query has been executed, and then proxies the task to the DB object, returning the result as if it was a query object itself (called a basic database function.

II. Type Hinting)

To enable the proxy to work, we need to ensure that the $ db variable of the DBQuery object is an instance of the object that implements the DB interface. The type prompt is a new feature in PHP 5, which enables you to forcibly convert function parameters to specific types of objects. Before PHP 5, the only way to ensure that the function parameter is a specific object type is to use the type check function (is_a () provided in PHP ()). Now, you can simply forcibly convert the object type by adding the type name before the function parameter. You have seen the type prompt from our DBQuery object to ensure that an object implementing the DB interface is passed to the object constructor.

Public function _ construct (DB $ db)
{
$ This-> db = $ db;
}

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

III. throw an exception

You may have noticed from the code above that you caught 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 an emergency can not be "fatal", it must be handled. When an exception is thrown in PHP, the current execution range is quickly terminated, whether it is a function, try .. catch block or the script itself. Then, the exception traverses the call stack-terminates each execution range until or in a try .. catch block capture it or it reaches the top of the call stack-at this time it generates a fatal error.

Exception handling is another new feature in PHP 5. when associated with OOP, it can implement good control over error handling and reporting. A try... catch block is an important mechanism for handling exceptions. Once captured, the script continues execution from the next line of the code where the exception is captured and processed.

If the query fails, you need to change your execute function to throw an exception. You will throw a custom exception object called QueryException-causing the wrong DBQuery object to be passed to it.

List 3. an exception is thrown.

/**
* Execute the current query
*
* Execute the current query-replace any point operator with the provided parameters
*.
*
* @ Parameter: mixed $ queryParams,... query parameter
* @ Return: Resource A-the resource that executes the query according to the description.
*/
Public function execute ($ queryParams = '')
{
// Example: SELECT * FROM table WHERE name =: 1 s and type =: 2I AND level =: 3N
$ Args = func_get_args ();
If ($ this-> stored_procedure ){
/* Call the compile function for query */
$ Query = call_user_func_array (array ($ this, 'compile '), $ args );
} Else {
/* A stored procedure is not initialized. Therefore, it is executed as a standard query */
$ Query = $ queryParams;
}
$ Result = $ this-> db-> query ($ query );
If (! $ Result ){
Throw new QueryException ($ this );
}
$ This-> result = $ result;
/* Pay attention to how to return the object itself, which enables us to call the member function from the returned result of this function.
*/
Return $ this;
}

IV. use inheritance to throw a custom exception

In PHP, you can throw any object as an exception. However, the exception should first be inherited from the PHP built-in exception class. By creating your own custom exceptions, you can record other information about the error, such as creating an entry in a log file or doing anything you like to do. Your custom exceptions will do the following:

· Records error messages from DB objects generated by queries.

· Provide accurate details of the code in the row where the query error occurs-by checking the call stack.

· Display error messages and query text-when converted into a string.

To obtain error information and query text, you need to make multiple changes to the DBQuery object.

1. a new protected attribute-compiledQuery-needs to be added to the class.

2. the compile () function uses the query text to update the query compiledQuery attributes.

3. you should add a function to retrieve compiled query text.

4. add a function to obtain the DB object associated with the DBQuery object.

List 4. An exception is thrown.

Class DBQuery
{
/**
* Stores the compiled version after calling compile () or execute ().
*
* @ Var string $ compiledQuery
*/
Protected $ compiledQuery;
/**
* Return the compiled query without executing it.
* @ Parameter: mixed $ params,... query parameter
* @ Return: string-compiled query
*/
Public function compile ($ params = '')
{
If (! $ This-> stored_procedure ){
Throw new Exception ("the stored procedure is not initialized .");
}
/* Replace parameter */
$ Params = func_get_args (); // Obtain the function parameter.
$ 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. Note how you traverse the call stack to find the location that actually caused the error in the script. This is suitable when the thrown DBQuery object is a subclass inherited from the DBQuery object.

List 5: QueryException class.

/**
* Query exception
*
* If an error occurs when an attempt is made to execute a query, an error will be thrown by the {@ link DBQuery} object.
*/
Class QueryException extends Exception
{
/**
* Query text
*
* @ Var string $ QueryText;
*/
Protected $ QueryText;
/**
* Error code from the database
*
* @ Var string $ ErrorCode
*/
Protected $ ErrorNumber;
/**
* Error messages from databases
*
* @ Var string $ ErrorMessage
*/
Protected $ ErrorMessage;
/**
* Class constructor
*
* @ Parameter: DBQuery $ db, which is the query object that throws an exception.
*/
Public function _ construct (DBQuery $ query)
{
/* Get the call stack */
$ Backtrace = $ this-> GetTrace ();
/* Set the row and file to the actual location where the error occurred */
If (count ($ backtrace)> 0 ){
$ X = 1;
/* If the query class is inherited, we need to ignore the calls 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 row number or the called function is a subclass of the DBQuery class */
++ $ X;
/* If we reach the bottom of the stack, we use the first caller */
If ($ x)> = count ($ backtrace )){
$ X = count ($ backtrace );
Break;
}
}
/* If the previous loop is executed at least once, we can subtract 1 from it to find the actual code line that caused the error.
*/
If ($ x! = 1 ){
$ X-= 1;
}
/* Finally, we can set the file and row 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 the superclass exception constructor */
Parent: :__ construct ('query error', 0 );
}
/**
* Obtain the query text.
*
* @ Return string query text
*/
Public function GetQueryText ()
{
Return $ this-> QueryText;
}
/**
* Get the error code.
*
* @ Return the string error code
*/
Public function GetErrorNumber ()
{
Return $ this-> ErrorNumber;
}
/**
* Get error message
*
* @ Return a string error message
*/
Public function GetErrorMessage ()
{
Return $ this-> ErrorMessage;
}
/**
* Called when the object is converted into a string.
* @ Return string
*/
Public function _ toString ()
{
$ Output = "Query Error in {$ this-> file} on 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 can work.

V. Conclusion

In this article, you will see how the proxy maps the DB interface associated with the query to operations on a specific query result. DBQuery objects expose the same functions, such as fetch_assoc (), as DB objects. However, these functions work for a single query. You also learned how to use custom exceptions to provide detailed information-when and where errors occur, and how they can better control error handling.

Related Article

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.