WEBVTT

00:00.500 --> 00:07.700
So in this video, we are going to be talking about errors about how to handle built in PHP.

00:07.730 --> 00:16.430
Errors and exceptions and how to do that the most secure way, and the way that will also give you the

00:16.430 --> 00:19.610
necessary information about what has happened.

00:20.360 --> 00:24.230
So this app is currently lacking any error handling.

00:24.230 --> 00:32.810
And we need to add some error handling because every serious application needs a way to deal with errors.

00:32.810 --> 00:40.520
And in PHP we've got two kinds of errors the built in errors, warnings and notices.

00:40.760 --> 00:50.000
This was initially the way PHP reported errors, and it also outputted those errors on the screen directly.

00:50.210 --> 00:52.490
You're gonna see in a second what I mean.

00:52.490 --> 00:56.510
And another kind of errors are exceptions.

00:56.600 --> 00:59.240
This was introduced later in PHP.

00:59.270 --> 01:04.790
That's why we have two kinds of errors that can happen in PHP.

01:05.750 --> 01:09.830
First, let me trigger the traditional PHP error.

01:09.980 --> 01:17.630
This can happen, for example, if I echo or use a variable that wasn't initiated first.

01:17.630 --> 01:22.280
So this hey variable obviously doesn't exist anywhere in here.

01:22.310 --> 01:26.360
That's why this should cause some kind of an error.

01:26.360 --> 01:33.200
And by default, in most modern versions of PHP this would be reported in console.

01:33.320 --> 01:35.330
So let me refresh this page.

01:35.330 --> 01:41.060
You can see this is not reported on this page that this variable is not defined.

01:41.060 --> 01:49.490
But inside the console where PHP server runs, we can see a PHP warning that we are using an undefined

01:49.490 --> 01:50.540
variable.

01:50.540 --> 01:55.010
So it is good that PHP changed this behavior because.

01:55.010 --> 01:59.270
Now let me show you how this looked like before.

01:59.300 --> 02:07.730
So this word times in older versions of PHP, and I think that every single one of you have seen this

02:07.760 --> 02:13.790
online popping up randomly on some older websites using WordPress.

02:13.820 --> 02:20.870
So first let's set the error reporting level to display all errors.

02:20.900 --> 02:22.370
This is how you do that.

02:22.490 --> 02:32.360
And we're gonna set using any set method the setting called display underscore errors.

02:32.360 --> 02:37.040
In modern PHP versions this is disabled by default.

02:37.040 --> 02:39.410
And that's the right thing to do.

02:39.710 --> 02:43.190
Let's just enable it so you can see what I mean.

02:43.190 --> 02:47.150
Now when I refresh this page this is what I was talking about.

02:47.150 --> 02:52.610
I guess every single one of you, even if you didn't know that is PHP.

02:52.640 --> 02:56.270
You seen that on at least one website.

02:56.300 --> 02:58.790
I think it's terrible.

02:58.790 --> 03:00.860
It's ugly error reporting.

03:00.860 --> 03:09.320
And it is unsafe because it is telling the random visitor of the website what language you are using,

03:09.320 --> 03:17.870
what framework you are potentially using, and where your files are kept, and also what PHP file had

03:17.870 --> 03:18.650
the error.

03:18.650 --> 03:23.270
So it's great that now it is disabled by default.

03:23.270 --> 03:28.190
Let's comment this out then it's enough to see it in the console.

03:29.060 --> 03:32.810
So another kind of errors are exceptions.

03:33.290 --> 03:36.770
So you already know a little about exceptions.

03:36.770 --> 03:45.320
And you can throw your own exceptions or just handle the exceptions produced by some PHP libraries.

03:45.440 --> 03:54.320
For example PDO can produce some exceptions if for example you can't connect to database, you can't

03:54.320 --> 03:56.810
insert it to data to the database.

03:56.810 --> 04:01.010
Can't read the data or there are some database errors.

04:01.040 --> 04:07.310
Like for example, you are trying to insert a record that already exists.

04:07.310 --> 04:15.620
So typically, the most modern solution to any kind of errors in PHP is to throw an exception.

04:15.740 --> 04:23.240
So this is what I was talking about earlier, that we don't really have any error handling in this app,

04:23.240 --> 04:25.550
so we need to handle exceptions.

04:25.550 --> 04:31.940
Before we do, let me trigger an exception manually so we can see how it looks like.

04:31.940 --> 04:38.090
So you do it using throw and you create just a new instance of the exception.

04:38.090 --> 04:43.160
It can be let's use runtime exception saying whoops.

04:44.540 --> 04:49.250
Now let me refresh the page and jump back to the terminal.

04:49.250 --> 04:54.020
So the page that was returned isn't really telling us anything.

04:54.020 --> 04:56.330
It looks really broken.

04:56.330 --> 05:00.860
So that is not even a page that we have created.

05:00.860 --> 05:04.040
This is the default browser page.

05:04.040 --> 05:10.970
And when we take a look at the terminal, it contains a little bit more information about the error

05:10.970 --> 05:14.240
that we maybe can use for debugging.

05:14.240 --> 05:24.230
So our goal would be to create some common error page that will give our users more confidence that

05:24.230 --> 05:31.250
something bad has happened, but maybe they can try again not to display this really terrible page that

05:31.250 --> 05:36.320
looks like everything just went completely wrong and there is no recovery.

05:36.440 --> 05:40.310
And also to handle those errors the same way.

05:40.310 --> 05:49.160
Doesn't matter if there is a built in PHP error, or an exception is thrown by either our code or some

05:49.160 --> 05:51.710
built in PHP code.

05:52.460 --> 05:54.320
Now let's get to it.

05:54.350 --> 05:59.060
Let's see how can we change the way errors are handled in PHP?

05:59.810 --> 06:05.930
Now, I think that we should start with handling exceptions in a better way because as you can see right

06:05.960 --> 06:11.090
now, currently if an exception happens, it is pretty catastrophic.

06:11.120 --> 06:17.270
The whole page basically disappears and we see some default browser page.

06:17.300 --> 06:24.170
Now we need to remember that exceptions can still be handled inside a try catch block.

06:24.200 --> 06:29.990
That's best for when you expect a certain exception can be happening.

06:29.990 --> 06:37.310
For example, with database connections it's quite possible that something would go wrong.

06:37.340 --> 06:44.480
Now, currently we just need to add a handler that will handle unhandled exceptions.

06:44.480 --> 06:50.660
However, this sounds so exceptions that weren't handled by our try catch block.

06:50.660 --> 06:54.320
And they are really unexpected.

06:54.740 --> 07:02.450
So without any changes here, let's jump to the bootstrap PHP file, because this is where I'd like

07:02.450 --> 07:04.790
to set up the error handling.

07:05.150 --> 07:08.180
So we want to report all the errors.

07:08.180 --> 07:13.610
And another function that will be useful is set exception handler.

07:13.640 --> 07:21.260
That's just a PHP function that will let us create our own custom way to handle exceptions.

07:21.500 --> 07:23.390
So we need to call it.

07:23.570 --> 07:26.300
This is set exception handler.

07:26.300 --> 07:31.190
And we pass a callable here which is just a function.

07:31.220 --> 07:33.440
Now we need to create one.

07:33.470 --> 07:37.850
I think we can create another file just for errors.

07:37.850 --> 07:40.820
I'm going to call it error handling.

07:40.910 --> 07:44.810
And it's really crucial for our app.

07:44.810 --> 07:50.060
That's why I think it can be on the same level as the bootstrap file.

07:50.090 --> 07:56.990
Also, I think that the error handling should be one of the first things that happen inside the bootstrap

07:56.990 --> 07:57.770
file.

07:57.800 --> 08:04.070
I think it's pretty obvious because if we would move it at the end of the bootstrap file, all those

08:04.070 --> 08:11.270
things that happen in between can potentially cause some errors, which would be then not really properly

08:11.270 --> 08:13.190
reported and handled.

08:13.220 --> 08:18.890
That's why it's important to do it as the first thing now.

08:18.920 --> 08:26.600
That's also why we're gonna use require once and just require this error file right away.

08:26.840 --> 08:29.690
So this is error handling PHP.

08:31.010 --> 08:37.490
And now let's jump back to this file and create our custom exception handler.

08:37.550 --> 08:39.470
So we need to pass a function here.

08:39.470 --> 08:41.930
Let's see how this function should look like.

08:41.930 --> 08:51.470
So it should only accept one parameter of type throwable which can be Of type error or exception.

08:51.470 --> 08:54.410
That's why we type it with an interface.

08:54.470 --> 08:56.510
So let me add a function called.

08:56.540 --> 09:01.940
Exception handler that accepts throwable.

09:05.150 --> 09:08.150
And it doesn't really return anything.

09:08.150 --> 09:12.740
And let's implement some better exception handling.

09:14.780 --> 09:20.570
Let's begin by producing a message that we are about to log.

09:20.600 --> 09:25.070
The same as things are currently logged in the terminal.

09:25.070 --> 09:28.220
So I just want a custom message.

09:28.400 --> 09:33.290
So we say that this was an uncaught exception.

09:33.290 --> 09:37.760
That's important to just say it that it wasn't caught.

09:38.480 --> 09:43.730
Next up we need to concatenate with the actual class name of this exception.

09:43.730 --> 09:46.070
This is important information.

09:46.070 --> 09:50.830
For this we can just use the getclass function of PHP.

09:50.860 --> 09:57.910
Passing this argument that I've called the exception, you can customize the name of that argument.

09:58.510 --> 10:01.720
Then concatenate to close the parentheses.

10:01.720 --> 10:08.920
That's just the beginning because next up we are going to sorry the colon goes in here.

10:09.850 --> 10:17.230
Next up we concatenate that with further information from this exception object.

10:17.470 --> 10:23.290
Because it contains the actual message we can get it through a method.

10:23.830 --> 10:29.140
And next up let's also say in what file this happened.

10:29.170 --> 10:32.470
Keep in mind this is information for us.

10:32.470 --> 10:34.750
We're going to be logging this.

10:34.750 --> 10:36.970
This is not displayed to the user.

10:37.120 --> 10:42.010
So from exception we can also get the file name.

10:42.100 --> 10:55.750
And additionally It's also concatenate this with online and say basically in which line this has happened.

10:55.780 --> 11:02.290
This would be exception get line.

11:02.290 --> 11:06.100
So that's the full message I'd like us to output.

11:06.130 --> 11:13.660
Now in PHP there is this error log message that will put that on the console.

11:15.250 --> 11:16.480
So let's do it.

11:16.480 --> 11:25.450
And the rest let's just use the function we already have returning 500 code, but with some response

11:25.450 --> 11:32.080
we're gonna say an unexpected error occurred.

11:33.970 --> 11:39.220
Please, please try again later.

11:40.810 --> 11:48.370
So as you see as little as possible information will be getting to the visitors of our website.

11:48.370 --> 11:54.430
And this is intentional because they won't be fixing the errors in our code.

11:54.430 --> 11:57.370
That's why they don't need to know the actual message.

11:57.400 --> 12:03.190
Exception, and especially the file and line in which this has happened.

12:03.880 --> 12:11.770
Now the final step is to jump to bootstrap and just pass a string with the function name that will handle

12:11.770 --> 12:13.300
those exceptions.

12:13.330 --> 12:19.870
After those changes, I should be able to refresh this page and see a nicer message.

12:19.900 --> 12:24.100
Now nothing stops us from actually rendering a view.

12:24.100 --> 12:26.890
So we've got this templates folder.

12:26.890 --> 12:36.610
We can create a whole page including the header and footer called maybe 404 or 500 specific for errors

12:36.610 --> 12:42.430
that will display the whole page with a very nice error and maybe very nice error message.

12:42.430 --> 12:46.510
I mean, and maybe some instructions on how to recover.

12:46.510 --> 12:51.580
But I think that for the purpose of demonstration, that's enough.

12:51.970 --> 13:00.160
And also, let's jump to the terminal where we have our custom message that uncaught exception with

13:00.160 --> 13:04.780
the class name has happened with the message and all the other info.

13:06.910 --> 13:12.610
So another thing to handle apart from exception handler is this error handler.

13:12.640 --> 13:17.470
So let's see the function set error handler.

13:18.460 --> 13:21.160
That's the next one that we would have to call.

13:21.190 --> 13:22.810
This is set error handler.

13:22.810 --> 13:26.320
And obviously we need to prepare this handler first.

13:26.320 --> 13:33.940
That's why we're gonna jump to error handling and create another function that can handle the non exception

13:33.940 --> 13:35.530
errors in PHP.

13:35.830 --> 13:39.820
So let's take a look at this set error handler function.

13:39.820 --> 13:42.370
The first argument to it is callable.

13:42.400 --> 13:45.790
But notice that it is nullable.

13:46.600 --> 13:49.660
This means we can pass null to this function.

13:49.660 --> 13:54.250
What's the point of that if we are about to set a custom error handler?

13:54.280 --> 14:02.050
Well, the point is that if you pass null, it resets any custom handlers that you have assigned before

14:02.080 --> 14:05.830
going back to the default PHP behavior.

14:06.640 --> 14:11.650
Now let's see how our function that we are about to create should look like.

14:11.650 --> 14:13.900
So this is the handler.

14:14.740 --> 14:20.110
So here you can read that passing null will reset to the default PHP handler.

14:20.140 --> 14:25.060
Now let's create a function that we can call error handler.

14:25.090 --> 14:28.990
As you can see this function needs to return a boolean.

14:29.020 --> 14:32.950
We're going to explain why and the arguments here.

14:33.190 --> 14:37.990
So we've got an integer the error number.

14:38.230 --> 14:42.790
Then a string error string.

14:42.820 --> 14:46.420
This is a kind of a message.

14:46.570 --> 14:54.850
And additionally we've got a string error file and then an integer.

14:54.880 --> 14:58.360
This is an error line.

14:58.360 --> 15:01.870
So line in that file where the error has happened.

15:01.870 --> 15:03.070
And the context.

15:03.070 --> 15:05.710
Well we can accept this argument or not.

15:05.740 --> 15:07.180
It's up to us.

15:07.390 --> 15:09.880
So maybe this is enough.

15:09.910 --> 15:14.350
The first step is to construct a message that we're going to log.

15:14.350 --> 15:16.360
So this is only for us.

15:16.360 --> 15:23.650
We can say that the error with the error number.

15:26.680 --> 15:32.980
Then let's display the message on line.

15:34.090 --> 15:38.650
Next up we display the line in file.

15:38.680 --> 15:39.940
And.

15:42.340 --> 15:45.490
This is error file.

15:45.490 --> 15:50.800
So this is a thing that we are about to log using error log.

15:51.160 --> 15:52.330
That's a message.

15:52.330 --> 16:01.270
And again here we're going to use the server error not to display too many info about what has happened.

16:01.270 --> 16:04.630
Remember this is an unexpected thing.

16:04.630 --> 16:07.690
So something probably gone terribly wrong.

16:07.690 --> 16:11.200
So we just say an error occurred.

16:13.870 --> 16:17.350
Please try again later.

16:17.350 --> 16:19.360
So we display the message here.

16:19.360 --> 16:22.660
And then to the user to the visitor.

16:22.660 --> 16:28.240
We just call the server error function with some message that is very generic.

16:28.420 --> 16:34.990
That unexpected error occurred.

16:35.140 --> 16:38.500
Please try again later.

16:39.280 --> 16:45.520
Now, even if we have a notice or warning, this is typically something that can really go terribly

16:45.520 --> 16:46.090
wrong.

16:46.090 --> 16:53.470
Previously, PHP ignored that by either logging this info or displaying it on page and trying to continue.

16:53.470 --> 17:02.500
But I think that you should always fix all the issues and all the errors, like accessing a non-existing

17:02.500 --> 17:05.890
key in array or using a non-existing variable.

17:05.890 --> 17:12.340
I don't think you should be leaving those errors unattended and ignore them.

17:12.340 --> 17:19.810
And this returns a boolean, because now we are just telling PHP whether this concludes the error handling.

17:19.810 --> 17:21.280
If you return true.

17:21.760 --> 17:28.480
PHP won't do anything, won't handle this internally with the default behavior, but if you return false.

17:28.990 --> 17:36.670
PHP will also handle this error internally by doing how it is configured to behave, either displaying

17:36.670 --> 17:40.390
this on screen Sunscreen are just logging the error.

17:40.390 --> 17:45.520
So finally we need to jump to bootstrap and register this function.

17:45.520 --> 17:48.340
This is error handler.

17:49.540 --> 17:53.680
And then let's jump to our page where we trigger the errors.

17:53.680 --> 17:59.290
Comment out this and try to echo a non-existing variable.

17:59.320 --> 18:00.970
Now refresh this page.

18:00.970 --> 18:07.690
We see the error, the generic error, and in the console we've got more info.

18:08.110 --> 18:13.090
We've got the error the error number what's the message and where it happened.

18:13.810 --> 18:19.870
So now we can comment out this error because we just wanted to trigger something to see how this would

18:19.900 --> 18:20.500
behave.

18:20.500 --> 18:26.290
But I consider the error handling more or less done for this project.

18:26.290 --> 18:33.580
We can obviously improve error handling by handling exceptions, but I'm gonna leave it as an optional

18:33.580 --> 18:36.880
thing for the end of this project.
