Try, Throw, Catch
The title pretty much explains the purpose of try, throw and catch blocks. Most basically said, they handle specified errors upon their occurrence. We are also enabled to specify the error that should be output. We dispose with three main blocks which are not used independently from each other.
Try
- The block that ‘listens’ for any thrown exceptions
Throw
- If any, the Throw block sends them to the Try block
Catch
- Catch block receives what the Try block has sent
First of all, I’d like to start off with some common ways which programmers use to return their errors and meanwhile explain the mechanism of try, throw, catch. As usual with our example. We have one class UserModel (UserModel.php) which supposedly would be the model of a user and one public method which takes a couple of parameters and registers them on the database.
<?php
class UserModel {
public function register($name, $email, $pass) {
}
}
?>
And we have our index.php which handles that data by some default values assigned beforehand and includes the UserModel.php file.
<?php
include 'UserModel.php';
$user=new \UserModel();
$result=$user->register('Keeper', 'keeperr7@gmail.com', 'uniquepassword');
?>
The first thing we should do in such case is to validate the incoming data because the model itself is an independent unit and without any validation, you can kinda imagine what can really happen. And an independent unit would mean that the model won’t be disturbed by whether someone calls it or not.
<?php
class UserModel {
public function register($name, $email, $pass) {
if(mb_strlen($name)>4){
}
else{
return false;
}
return true;
}
}
?>
We have a simple loop to check for the length of the name, if the name is above 4 characters it return boolean true, if not boolean false. From the model point of view, there’s nothing wrong to code it like that. But from the point of view of the whole code and the programmer who calls this method, this is not practical. For example, when he gets returned boolean false, means that something has gone wrong but if we have like more than one if statements or any loop checks and use true and false as return values, the coder won’t be able to find out where the improper input has been used. Take for instance the following:
<?php
class UserModel {
public function register($name, $email, $pass) {
if(mb_strlen($name)>4){
if(mb_strlen($pass)>4{
} else {
return false;
}
}
else{
return false;
}
return true;
}
}
?>
So basically with all those boolean values we are unable to identify the input that is not acceptable. Now the next thing that people use to do in such cases is to return specific messages.
<?php
class UserModel {
public function register($name, $email, $pass) {
if(mb_strlen($name)>4){
if(mb_strlen($pass)>4{
} else {
return 'Password is too short';
}
}
else{
return 'Username is too short';
}
return true;
}
}
?>
In small projects or any tiny pieces of code that do not require any solid validation and sanitize of the input, this scheme is okay. But do be perfectly strict and accurate and actually practical whereas returning strings of data, we would have some public static properties and we will actually return the identifier of that public static property. However, that is not the idea of this tutorial so I won’t get into that now.
So the thing that is not practical with the above example is that the programmer should write a series of loops so as to describe every situation that may occur. The second thing that is not practical about it is its so-called impact on the semantics. Now what does that mean? It means that the public method register is not supposed to return the errors within itself. As a method, it is not his job to handle the errors but in this case to register the user.
So to the essence of this tutorial:
<?php
class UserModel {
public function register($name, $email, $pass) {
if(mb_strlen($name)>4){
if(mb_strlen($pass)>4{
} else {
return 'Password is too short';
}
}
else{
throw new Exception('Username is too short', 74);
}
return true;
}
}
?>
We throw an exception using the Throw block. It’s literally nothing more than an ordinary class, the difference is that it is embedded in PHP and we do not need to write a file for it and so on. The first check does not pass because the string ‘Keeper’ has more than 4 characters. Upon executing this code we are returned with an error stating the following:
Fatal error: Uncaught exception 'Exception' with message 'Username is too short' in ...
Because we haven’t declared the Try block therefore we receive uncaught exception as a result. We throw an error but do not catch and modify it. The defining of the Try block should be done in there, where we call the class (in our case index.php).
<?php
include 'UserModel.php';
$user=new \UserModel();
try {
$result=$user->register('Keeper', 'keeperr7@gmail.com', 'uniquepassword');
} catch (Exception $exc) {
echo $exc->getTraceAsString();
}
?>
As I said in the introduction, the job of the Try segment (block) is to listen if anything between its scope throws and exception. If so, it sends it to the Catch block. Otherwise, if there is nothing wrong, no error is being returned as if the catch block does not exist.
The Catch block will be executed automatically only if any of these codes throw an exception. Catch accepts one parameter called $exc. It comes from exception and it’s practically one regular object which has a few embedded methods for itself. They are:
__toString();
- A magic method which represents an exception as a string value. It accepts no parameters therefore
getCode();
- Takes the exception code (the parameter for the code in the exception is obligatory). It accepts no parameters as well
getFile();
- Gets the file in which the exception has occurred
getLine();
- Gets the line in which the exception has occurred
getMessage();
- Grabs the exception message
getPrevious();
- Used to return the previous exception (if any) - not an obligatory parameter of the exception class
getTrace();
- Not sure really. Read it on php.net - I never came to use this one
getTraceAsString();
- Does the same as getTrace but converts the value to a string
Notice that Throw always works with objects which are exceptions. For example executing the class using getLine(); will output the line where the error has occurred. In this case it will be 13. If we use getFile(); it will respectively return the file where it has occurred and so on. I have explained them above.
In some specific cases, Try, Throw, Catch comes in handy mainly because of its flexibility. First, we listen for whatever exception there might occur, no matter where it has occurred.
try {
$result=$user->register('Keeper', 'keeperr7@gmail.com', 'uniquepassword');
}
As well as that we can work with any problems that might occur during the process of establishing a connection to the database server. Say we have failed to connect to the stmt server. We’d have the following exception that would notify us if so.
<?php
class UserModel {
public function register($name, $email, $pass) {
if(mb_strlen($name)>4){
if(mb_strlen($pass)>4{
new mysqli_stmt();
} else {
return 'Password is too short';
}
}
else{
throw new Exception('Username is too short', 74);
}
return true;
}
}
?>
This exception will be thrown and caught by the Try, Catch mechanism. And as I already mentioned twice, those exception are objects. So we can, for example, make another class which extends the basic class Exception.
<?php
class UserModel {
public function register($name, $email, $pass) {
if(mb_strlen($name)>4){
if(mb_strlen($pass)>4{
new mysqli_stmt();
} else {
return 'Password is too short';
}
}
else{
throw new MyException('Username is too short', 74);
}
return true;
}
}
class MyException extends Exception{
public function Infamous() {
echo 'Infamous Forever';
}
}
?>
Also whereas throwing the method Exception, we will throw MyException to proof the concept that the below class inherits the one above it. And actually call this in our index.php:
<?php
include 'UserModel.php';
$user=new \UserModel();
try {
$result=$user->register('Keeper', 'keeperr7@gmail.com', 'uniquepassword');
} catch (Exception $exc) {
echo $exc->Infamous();
}
?>
This returns the string ‘Infamous’ as expected. So we can execute our own methods. Besides that, you might have noticed the syntax of the Catch block. In particular this line:
catch (Exception $exc){}
This is specific only for PHP, as far as I am aware. What this does is force us to have a certain type. So if we write the code like so:
<?php
include 'UserModel.php';
$user=new \UserModel();
try {
$result=$user->register('Keeper', 'keeperr7@gmail.com', 'uniquepassword');
}
catch (Exception $exc) {
echo $exc->Infamous();
}
catch (MyException $exc) {
echo $exc->Infamous();
}
?>
And modify the object in our UserModel class at (UserModel.php) to the type of MyException, it will be executed in this line of our index.php:
catch (MyException $exc) {
echo $exc->Infamous();
}
Now another thing that is also good to know about exception handling is that we may have a sequence of Catch blocks as I did in the above examples. Now let’s throw a new exception for the password loop.
<?php
class UserModel {
public function register($name, $email, $pass) {
if(mb_strlen($name)>4){
if(mb_strlen($pass)>4{
new mysqli_stmt();
} else {
throw new Exception("Password is too short", 43);
}
}
else{
throw new MyException('Username is too short', 74);
}
return true;
}
}
class MyException extends Exception{
public function Infamous() {
echo 'Infamous Forever';
}
}
?>
In this case the object that is going to be executed will be Exception(), not MyException(). In that way we say that the MyException() object will be executed only when we have MyException() in the class. This Catch block here:
catch (Exception $exc) {
echo $exc->Infamous();
}
As of our Catch block situations in our code, you need to be aware that their sequence of writing is important. So take that in mind as well.
Namespaces
Before we start off, I’d like to mention that namespaces are available only in PHP version 5.3 and above in order to escape further questions if anyone experiences an error using an older version. Now namespace is a functionality of PHP that enables us a better organising of our classes in hierarchical structures. Said in an easier manner, the logical sequence of where everything is gonna be placed. Aside from that, it is not mandatory to use this because it’s just a way to structure you classes in a logical sequence as I said.
How it works?
Now imagine that namespaces are directories (just do it). When we declare a namespace, imagine that everything within it is in a folder. And when we want to access the class User, we say - this file from that folder. That is in fact realistic and I thought it would clear things up. So an example for this would be the following. Suppose we have a project under a framework (MVC for example - my favourite) and we have our controller and model. Within those folders are our classes and so on. When we have a file bearing the same name as another one in another directory, we cannot include them both. Before the introduction of namespaces in PHP 5.3, most coders used to add prefixes and suffixes to the classes they included. But for now, it’s just good to know that. Now to my favourite examples:
<?php
namespace Model;
class User {
}
?>
And we do the same thing in the other User.php class file BUT with a different value after the keyword namespace. For example - Cont (abbreviated from controller).
So now when we execute both classes with the same name and have them included in our index.php
<?php
include 'Controller/User.php';
include 'Model/User.php';
?>
This time we don’t get an error because namespaces have been declared. So if we want to create an instance of a class we could easily do it like so:
<?php
include 'Controller/User.php';
include 'Model/User.php';
$a = new Model\User();
$b = new Cont\User();
?>
Another thing you should be aware of is that namespace should be declared at the very beginning of our code. Above it there is only one thing that could be added - comments. In that way if we declare a class above the namespace it will not be part of it simply.
<?php
class Keeper {}
namespace Model;
class User {
}
?>
As well as that we can declare sub namespaces like (notice that the backwards slash is specific for PHP, it’s the separator we need to use):
<?php
namespace Model\User;
class User {
}
?>
Now in order to refer to it in our index.php we need to point the directory it’s in (as it’s a namespace of a namespace).
<?php
include 'Controller/User.php';
include 'Model/User.php';
$a = new Model\User\User();
$b = new Cont\User();
?>
Here comes the time to talk about global namespaces. You might actually guess from now what that means. Classes that do not have a namespace, PHP places them in one global namespace. So for example we make an instance, simply, like so because PHP reads it as a global namespace automatically:
<?php
new User();
?>
So all in all, this means that everything that is not in a declared namespace is automatically situated in a global namespace which we can access and refer to directly.
Note: Though it may seem weird but never use PHP as a name for a namespace. It will not return an error but will mess up the whole structure of php configurations for namespaces.
Conclusion
Nothing much to add. This was the fourth tutorial of my series. I elaborated more on some of the subjects in this tutorial than I should have and that is the reason I marked the session as an extended version. I also thought of including type hinting in this part but later on I altered my decision because it seemed to much material for a single tutorial. Again, this is by far not my last tutorial. Expect the next ones from my series and thanks for reading!