Try and Catch for Syntax Errors - php

if i have the code below:
try {
//call function a
$object->function_a();
//call function b
$object->function_b();
//call function c
$object->function_c();
}
catch(Exception $e) {
$error->track_error();
}
how can i catch syntax errors, like someone is changing the function_b() name to function_d() which doesn't exists.
it seems that try and catch doesn't catch syntax errors, it doesn't work without an if statement to check if something is wrong.
but if i can expect an error with an if statement, why do i need try and catch, i can just write something like this:
if(//something is false) {
$error->track_error();
}
what i'm looking is something that will create an exception and jump to a catch block on the whole try scope, when any php error (including syntax) is happening, catch it and then get the details with error_get_last() or similar function for error logging inside the db.
is this possible?

You can use set_error_handler() to throw a custom Exception :
set_error_handler(function(int $errno, string $errstr, string $errfile = '', int $errline = 0) {
throw new Exception("$errstr ($errfile, line $errline)");
});

Related

Unable to catch Exception when using Eval function

I'm writing code that randomly generates expressions for a genetic algorithm for code optimisation purposes. The generated expressions are eval'ed for fitness. Some expressions will generate errors and I need to be able to catch these and act appropriately.
I have the following code (simplified from the original):
set_error_handler(function($errno, $errstr, $errfile, $errline, $errcontext) {
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
});
$expression = '$y=~!7;';
try {
eval($expression);
} catch (Exception $e){
echo 'Expression failed';
} catch (ParseError $e){
echo 'Expression failed';
}
This throws the following error:
PHP Fatal error: Unsupported operand types in ..... : eval()'d code on line ....
But this error is not caught in either catch block.
I've set my own error handler so that all errors are promoted to exceptions.
How do I catch this error?
Note: I am very aware that using eval is dangerous, but there is strictly no user input in my code.
At least in PHP 7.1+, eval() terminates the script if the evaluated code generate a fatal error. For example:
#eval('$content = (100 - );');
(Even if it is in the man, I'm note sure it acted like this in 5.6, but whatever)
To catch it, I had to do:
try {
eval('$content = (100 - );');
} catch (ParseError $e) {
$content = null;
}
This is the only way I found to catch the error and hide the fact there was one.

How to catch "No error: PDO constructor was not called"

how can I catch the following error: No error: PDO constructor was not called?
My question is not how to solve the error, but how to catch it!
I need that for a PHPUnit Testing Environment.
I was trying to catch it like that, but it simply doesn't work that way.
$pdo = (new \ReflectionClass(\PDO::class))->newInstanceWithoutConstructor();
try
{
$pdo->query("SELECT * FROM table");
}
catch (ErrorException $exc)
{
echo $exc->getTraceAsString();
}
the exact (error) message is as follows: PDO::query(): SQLSTATE[00000]: No error: PDO constructor was not called, but I am not sure, if that is even any type of PHP catchable.
I've already checked the method pdo_raise_impl_error()[PHP 7.3.3] that is called with the mentioned error message, but I am not wise enough to anticipate what actual type of error it produces...
Can please someone give advise?
Not sure if it's a solution you are looking for, but you can always convert all errors to exceptions with as simple code as
set_error_handler(function ($level, $message, $file = '', $line = 0)
{
throw new ErrorException($message, 0, $level, $file, $line);
});
Of course it will make a global error handler, but honestly, I believe every PHP project should have a code like this.
Or at least you can call this handler only temporarily
I now use the following code fore my test.
please check the first and the last line of code especially.
thanks to #YourCommonSense!
set_error_handler(function(int $errno, string $errstr, string $errfile, int $errline) {
throw new ErrorException($errstr, $errno, E_ERROR, $errfile, $errline);
});
$this->expectException(ErrorException::class);
$this->expectExceptionMessage("SQLSTATE[00000]: No error: PDO constructor was not called");
/* #var $pdo PDO */
$pdo = (new ReflectionClass(PDO::class))->newInstanceWithoutConstructor();
$pdo->query("SELECT * FROM table"); // triggers the error.
restore_error_handler();

Get all the exceptions from one try catch block

I wonder if it's posible to get all the exceptions throwed.
public function test()
{
$arrayExceptions = array();
try {
throw new Exception('Division by zero.');
throw new Exception('This will never get throwed');
}
catch (Exception $e)
{
$arrayExceptions[] = $e;
}
}
I have a huge try catch block but i want to know all the errors, not only the first throwed. Is this possible with maybe more than one try or something like that or i am doing it wrong?
Thank you
You wrote it yourself: "This will never get throwed" [sic].
Because the exception will never get thrown, you cannot catch it. There only is one exception because after one exception is thrown, the whole block is abandoned and no further code in it is executed. Hence no second exception.
Maybe this was what the OP was actually asking for. If the function is not atomic and allows for some level of fault tolerance, then you can know all the errors that occurred afterwards instead of die()ing if you do something like this:
public function test()
{
$arrayExceptions = array();
try {
//action 1 throws an exception, as simulated below
throw new Exception('Division by zero.');
}
catch (Exception $e)
{
//handle action 1 's error using a default or fallback value
$arrayExceptions[] = $e;
}
try {
//action 2 throws another exception, as simulated below
throw new Exception('Value is not 42!');
}
catch (Exception $e)
{
//handle action 2 's error using a default or fallback value
$arrayExceptions[] = $e;
}
echo 'Task ended. Errors: '; // all the occurred exceptions are in the array
(count($arrayExceptions)!=0) ? print_r($arrayExceptions) : echo 'no error.';
}

Cleanest way to execute code outside of try block only if no exception is thrown

This question is about the best way to execute code outside of try block only if no exception is thrown.
try {
//experiment
//can't put code after experiment because I don't want a possible exception from this code to be caught by the following catch. It needs to bubble.
} catch(Exception $explosion) {
//contain the blast
} finally {
//cleanup
//this is not the answer since it executes even if an exception occured
//finally will be available in php 5.5
} else {
//code to be executed only if no exception was thrown
//but no try ... else block exists in php
}
This is method suggested by #webbiedave in response to the question php try .. else. I find it unsatisfactory because of the use of the extra $caught variable.
$caught = false;
try {
// something
} catch (Exception $e) {
$caught = true;
}
if (!$caught) {
}
So what is a better (or the best) way to accomplish this without the need for an extra variable?
One possibility is to put the try block in a method, and return false if an exception is cought.
function myFunction() {
try {
// Code that throws an exception
} catch(Exception $e) {
return false;
}
return true;
}
Have your catch block exit the function or (re)throw/throw an exception. You can filter your exceptions as well. So if your other code also throws an exception you can catch that and (re)throw it. Remember that:
Execution continues if no exception is caught.
If an exception happens and is caught and not (re)throw or a new one throw.
You don't exit your function from the catch block.
It's always a good idea to (re)throw any exception that you don't handle.
We should always be explicit in our exception handling. Meaning if you catch exceptions check the error that we can handle anything else should be (re)throw(n)
The way I would handle your situation would be to (re)throw the exception from the second statement.
try {
$this->throwExceptionA();
$this->throwExceptionB();
} catch (Exception $e) {
if($e->getMessage() == "ExceptionA Message") {
//Do handle code
} elseif($e->getMessage() == "ExceptionB Message") {
//Do other clean-up
throw $e;
} else {
//We should always do this or we will create bugs that elude us because
//we are catching exception that we are not handling
throw $e;
}
}

Return PHP error constant (such as E_USER_ERROR) from function, or use trigger_error?

Which would you recommend?
Return an error code, such as E_USER_ERROR from a function, and determine proper message higher up:
function currentScriptFilename()
{
if(!isset($_SERVER['SCRIPT_FILENAME']))
{
//This?
return E_USER_ERROR;
}
else
{
$url = $_SERVER['SCRIPT_FILENAME'];
$exploded = explode('/', $url);
return end($exploded);
}
}
Execute trigger_error() from the function, with a specific error message:
function currentScriptFilename()
{
if(!isset($_SERVER['SCRIPT_FILENAME']))
{
//Or this?
trigger_error('$_SERVER[\'SCRIPT_FILENAME\'] is not set.', E_USER_ERROR);
}
else
{
$url = $_SERVER['SCRIPT_FILENAME'];
$exploded = explode('/', $url);
return end($exploded);
}
}
I am not sure if I will regret having put a bunch of error messages in my functions further down the line, since I would like to use them for other projects.
Or, would you recommend something totally different?
Do not mix the matters.
Error notification and error handling are different tasks.
You have to use both methods simultaneously.
If you think that $_SERVER['SCRIPT_FILENAME'] availability is worth an error message, you can use trigger error. However PHP itself will throw a notice if you won't check it.
If you want to handle this error, just check this function's return value.
But I would not create a special function for this task.
So,
if (!$filename = basename($_SERVER['SCRIPT_FILENAME']) {
// do whatever you want to handle this error.
}
would be enough
Exceptions could be useful to handle errors, to know if we had any errors occurred.
A simple example:
try {
$filename = basename($_SERVER['SCRIPT_FILENAME'])
if (!$filename) throw new Exception("no filename");
$data = get_some_data_from_db() or throw new Exception("no data");
$template = new Template();
//Exception could be thrown inside of Template class as well.
}
catch (Exception $e) {
//if we had any errors
show_error_page();
}
$template->show();
3.Use exceptions.
If this is the route you are going, I'd rather recommend throwing Exceptions rather then returing an E_ERROR (E_USER_ERROR should be used), as this is just an integer, and possibly a totally valid return for your function.
Advantages:
- Throwing of an Exception cannot be interpreted as anything else then an error by mistake.
- You keep the possibility to add a descriptive error message, even though you don't handle the error at that point/
- You keep a backtrace in your Exception.
- You can catch specific exceptions at specific points, making the decision where in your project a specific type of error should be handled a lot easier.
If not using exceptions which you should be, use trigger_error().
If it is an error you'd like to deal with, try returning FALSE like a lot of the in built functions do.
If you do use exceptions, catch them like this
try {
whatever()
} catch (Exception $e) {
// handle however
}

Categories