How to use exceptions correctly

After examining the syntax of construction try{...}catch(Exception $e){...}, and learning about the opportunity to create your own exception
classes by inheriting them from Exception class and realizing the power of mechanism you have, you could follow either of two ways:

Starting to use exceptions immediately.
For instance, using them in a system which they have never been used in, or in a project, which OOP is nowhere near in. Or, worst of all, trying to use
them everywhere, especially where it is not needed.

Trying to figure out
where to use them, how to do it right, and why they are needed.

1. You should clearly distinguish an exceptional situation from a regular error in the program; for example, having login and password incorrectly entered
is not an exception. This is a user error, not the program’s one; and it may occur very often. On the other hand, the failure of function mysql_connect() due to the inaccessibility of the database server is an exceptional situation, and you need to throw the exception. See
the details hereafter.

2. The class methods should not catch exceptions generated by other methods in the same class. The library should not know anything about
what to do in case of an exception in its methods, as depending on the system where it is used, this operation could vary greatly. It should throw an
exception. For example, if a file required for correct operation of your entire class does not exist, you do not have to deal with it. This is the case of higher levels of an application.

On the other hand, you may catch exceptions thrown by lower levels (if you wish). If you do not wish, they are transferred on the stack into the nearest catch{} (more precisely into catch{}, corresponding to the nearest try{}). Let us assume that you have a wrapper class for
working with the database, with methods such as connect(), query(), etc. It is clear that if the server cannot be
connected, you need to throw an exception in method connect().

However, it should not catch neither connect(), nor even query(), which could cause connect()
automatically. This exception should be caught at a higher level, which works with the methods of this class, and there a decision should be made to try to
connect to another server, or use a different type of data source, or simply display the error, or pass the exception much higher (differently in different
systems, let them decide what to do). I hope the idea is clear.

3. In a large application, you should use your own exception classes (inherited from the built-in Exception). This allows you to build a hierarchy
of errors classes and divide them by priority, type, etc. Let us assume that we have class Application_Exception:

class Application_Exception extends Exception{...}
and some of its childs:

class Logic_Exception extends Application_Exception{...}

- logical errors, such as violation of the tables relativity in database or of key uniqueness.

class Data_Access_Exception extends Application_Exception{...}

- error of access to the necessary data, e.g. a missing file or device, or connection to access to any source.

class Security_Exception extends Application_Exception{...}

- security errors, e.g. when a user sends a cookie that they simply are not able to have)

All these types of errors should be handled differently; for example, you should not cry all over the Internet about your security errors, but in case of
failure of the database server you could make a smart sign of apology (generally speaking, tastes differ).

4. In order to obtain maximum information about an error, you should take opportunities of built-class Exception; there is no need to reinvent the
wheel. If a file name and line in which an exception has been thrown is not enough; then you can use methods getTrace() and getPrevious(), which certainly give you the whole "picture" of what has happened (more details are in the documentation).