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.
Related
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)");
});
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();
I'm trying to do a very basic exception try catch, but it doesn't catch.
$id =0;
try {
$question = $this->model->find($id); // will not find anything since $id = 0
$question->delete(); // throw an exception
return true;
} catch (\Exception $e) {
dd ('hello'); // should end up here, but no?!?!?
} catch (FatalThrowableError $f) {
echo ("fatal"); // or here... but no.
}
but the catch doesn't "catch". I get an Fatal error in the browser saying that delete was called on a null object. But that's exactly what I was trying to do: do a delete on a null object (id = 0 is not in the DB), to test the exception.
I have tried
use Symfony\Component\Debug\Exception;
use Symfony\Component\Debug\Exception\FatalThrowableError;
or simply
Exception;
FatalThrowableError;
Also, having the \Exception $e or Exception $e (with or without ) doesn't change anything.
Note that if I add a line like $foo = 4/0 I get into the Exception section (dd (hello)).
in .env APP_DEBUG=true, APP_LOG_LEVEL=debug
I'm on Laravel 5.5 using PHP 7.0.10 on windows 7.
http://php.net/manual/en/language.errors.php7.php
As the Error hierarchy does not inherit from Exception, code that uses
catch (Exception $e) { ... } blocks to handle uncaught exceptions in
PHP 5 will find that these Errors are not caught by these blocks.
Either a catch (Error $e) { ... } block or a set_exception_handler()
handler is required.
You can, additionally, catch (\Throwable $e) {} to account for both Error and Exception types.
Is it possible to log a stacktrace on warnings?
Here is the way I log all warning and notice errors
function boot_error_handler($errno, $errstr, $errfile, $errline){
switch($errno){
case E_WARNING:
case E_PARSE:
case E_NOTICE:
$message = "$errstr $errfile:$errline";
if(class_exists('Log')){
Log::write($message, 'warning', true);
}
if(ENV != ENV_PROD){
echo $message;
}
break;
}
}
set_error_handler('boot_error_handler');
You can use debug_backtrace() function in you error handler to get current stacktrace. The thing is that it returns array of associative arrays wichi is uncomfortable to use if you just need to log it, because you would need to generate a human-readable string form it.
Another solution would be to create an Exception instance and use its method getTraceAsString().
$exception = new \Exception();
$trace = $exception->getTraceAsString();
So basically it depends if the default exsceptions stacktrace format is enough for you or you want to have soem custom format.
(new \Exception)->getTraceAsString();
is an easy way of generating a nicely formatted trace (PHP 5.4+)
It'll just return a string, so you can either replace or extend your existing log messages with it as appropriate.
Use debug_backtrace() or fire an exception, catch it and get its trace with getTraceAsString():
try {
throw new Exception();
} catch (Exception $e) {
$e->getTraceAsString();
}
Let's say I have the following piece of code.
To test this, I change the server IP to mimic the error messages. The IP below doesn't exist so the Unhandled Exception message is: Cannot connect to 10.199.1.7. Error 113. No route to host
This displays an ugly screen with PHP code. Is it possible to catch this error?
try {
$ssh = new Net_SSH2('10.199.1.7');
if (!$ssh->login('deploy', $key)) {
throw new Exception("Failed login");
}
} catch (Exception $e) {
???
}
Looked through library.
user_error('Connection closed by server', E_USER_NOTICE);
It triggers errors. You can handle those errors using http://php.net/manual/en/function.set-error-handler.php
e.g.
// Your file.php
$ssh = new Net_SSH2('10.199.1.7');
$ssh->login('deploy', $key);
// bootstrap.php
// This will catch all user notice errors!!!
set_error_handler ('errorHandler', E_USER_NOTICE)
function errorHandler($errno, $errstr, $errfile, $errline) {
echo 'Error';
// Whatever you want to do.
}
You can use # in front of you function call. # operator