assert(boolean,\Throwable) is a very handy tool for exception-proofing PHP code, but is has an annoying side effect: The second argument has to be either a string or a Throwable. That means that if you want to throw an exception, you have to new your exception on the spot. Which means that the __construct() method runs. And if the __construct() contains something such as error logging or dumping a variable to your tracking system, that's going to happen even if the assertion passes. This can result in unwanted side effects from redundant logging to stuff being rendered to your output--sometimes creating a bug where one wouldn't normally exist.
Given the tools currently available in PHP 8.1, how can someone structure an error handling system so that they can execute code in the exception ONLY WHEN the exception is actually thrown, not just when it is created?
Related
I am only learning Exceptions and error reporting, and I am trying to understand behaviours of try/catch and perhaps other methods that I don't know yet. I have code like this:
function nameless(....) {
if(!$condition) {
throw new Exception('Condition not met');
}
[someCode ...]
return $result;
}
I want to make sure that someCode only executes if the condition is met. Would a structure like this guarantee that it?
Before talking about putting the rest of the code in an else block, or other methods, I want to know if there is some way to execute nameless() in a way that would continue its execution after it throws the exception.
Once I know that, I would like to know if there are better/worse ways of doing things and if this particular example is poor or it's one of a hundred equally valid ways to do this. Thank you.
Yes, it will stop. The behavior is defined here:
When an exception is thrown, code following the statement will not be executed, and PHP will attempt to find the first matching catch block. If an exception is not caught, a PHP Fatal Error will be issued with an "Uncaught Exception ..." message, unless a handler has been defined with set_exception_handler().
Based on the definition and purpose of exceptions, the function should not continue after an exception, and you shouldn't look for a way to force that to happen.
If you have some code that must be executed even after an exception is thrown, you should not include it in the function, but instead enclose the function in a try/catch, with the necessary code in a finally block.
I've just started with php unit.
In my test cases UsersController should return:
public function UsersController() {
....
throw new \Cake\Network\Exception\NotFoundException();
}
phpunit code
$this->setExpectedException('Cake\Network\Exception\NotFoundException');
returns an assertion failed that looks like:
App\Test\TestCase\Controller\UsersControllerTest::testActivate
Failed asserting that exception of type "Cake\Network\Exception\NotFoundException" is thrown.
Meanwhile browser return a 404 PageNotFound and $this->assertResponseOk() returns:
App\Test\TestCase\Controller\UsersControllerTest::testActivate
exception 'Cake\Network\Exception\NotFoundException' with message 'Not Found' in /vagrant/ifmx.local/src/Controller/UsersController.php:215
Does somebody know why it's happened? And is there any way to get exception message in unit test.
You seem to have misunderstood how the integration test case works.
It doesn't just wrap a call to a controller method, like $controller->action(), it simulates a whole request, and as such, exceptions are being catched, and result in error pages being rendered, just like it happens when you are visiting a URL in your browser.
So PHPUnit will never know about the exception, and thus you cannot use the expected exception feature as you would when directly testing specific code parts where exceptions bubble up to PHPUnit. If that would happen, then it wouldn't be possible to assert responses, which one might want to do, even when an exception has been thrown.
Possible exceptions are being buffered in the IntegrationTestCase::$_exception property, which you can for example use to test if, what kind of exception has been thrown, etc, like
$this->assertInstanceOf('\Cake\Network\Exception\NotFoundException', $this->_exception);
$this->assertEquals('Not Found', $this->_exception->getMessage());
I wrote a class whose methods frequently throw a number of Exceptions--for example, a NoResultException if the given user ID doesn't correspond to a user, a BadTokenException if the token was wrong, an EmailTakenException if the e-mail address is already registered, etc.
I am trying to write a test program using it really quick. I was feeling lazy and I didn't want to write try/catch blocks. I probably will now, but I still have to ask: is it possible to change PHP's behavior and make it so that Exceptions don't produce fatal errors? In other words, can I make my script catch the Exceptions and output them using the default exception handler (since I'm using XDebug and the backtrace is nice), but allow the script to finish executing? Then I can just see the message of the error (like "The e-mail address is already taken") without stopping the rest of the page from being printed.
Thanks.
use trigger_error instead. it throws non-fatal errors
trigger_error("Custom Error", E_USER_ERROR);
display it via set_error_handler()
see
http://us1.php.net/trigger_error
and
http://us1.php.net/set_error_handler
You can only make exceptions non-fatal if you catch them through try/catch blocks and you've just said that you're too lazy to do that? This makes no sense. You either use trigger_error or you add try/catch blocks.
You can have uncaught exceptions be non-fatal by creating an set_exception_handler function to handle them. Most of the time I just show a HTTP 500 system error page. If there is a way to recover (Which I'm not sure why you wouldn't do it in a try/catch) you can do there by looking at the Exception class and the error code number in the exception.
How to force catching exceptions in PHP?
I want to force exception catching if method may return and exception and is not added to try catch block.
For example:
If an exception is not thrown developer may never know that certain kind of exception may be thrown by the method he uses. So he won't catch it. I want to make sure that every exception that can be thrown will be caught.
In case it is not, I want a fatal error, or at least an exception.
Update: In comments it points out, that the former answer was not the actual answer to the problem. The detection of uncaught exceptions, or potentially uncaught exceptions in PHP is not supportet by the PHP parser itself. (Not like the Java compiler). You'll have to use external tools for statical code analysis to improve the quality of your code. I found this interesting answer for example: https://stackoverflow.com/a/8268875/171318
Original Answer:
You can register a function as global exception handler using set_exception_handler(). This function will be called by the PHP engine if an exception was not caught.
Example (from PHP manual):
<?php
function exception_handler($exception) {
echo "Uncaught exception: " , $exception->getMessage(), "\n";
exit(1);
}
set_exception_handler('exception_handler');
throw new Exception('Uncaught Exception');
echo "Not Executed\n";
?>
I decided to share what I do for myself considering this question.
I will add compilation mechanism to my application. So it won't be working if its not compiled first.
This will help me to force coding practices on developers and won't slow an application.
======================
Sorry, I cannot find a way to make it without slowing application. The best thing for the moment that comes to my mind is to check file modification time when it gets included. If its not equal to compilation time then throw an exception about compilation.
But it checks date and time of all files that participated in script run after all. So if you run 1000 files in your script execution, on my pc it gets slowed for 0.022 sec. If there are around 50 files included in your script run then it is slowed by 0.0015 sec
In most cases running this kind of application will still be cheaper then fixing bugs made by developers. But it depends how fast you want your application to be.
I want to use a custom exception handler (set with set_exception_handler() function) to control what is printed to a user when unhandled exception occurs.
Unfortunately, in this case exception is not logged to a php error log and I don't want to write my own logging code because automatic exception logging was absolutely ok for me.
The question is:
Is there a way to make PHP log exception (as by default) if custom exception handler was executed? If no, is there a way to log into main php error log file?
Is there a way to make PHP log exception (as by default) if custom exception handler was executed?
No, not from what PHP offers (e.g. return FALSE in the callback).
If no, is there a way to log into main php error log file?
Yes, you can use the error_logDocs function for that. The ExceptionDocs should contain the message as well as code, file name and line number.
It also is stringable and error_log() adds the delimiting newline character, so it directly works in logging (it will even downsize based on log_errors_max_len configured size):
set_exception_handler(function ($throwable) {
error_log((string)$throwable);
});
Or less verbose:
set_exception_handler('error_log');
Demo/Playground: https://3v4l.org/s41Vn
Another more or less dirty trick is to create an exception capturing object that remains in memory all the time. If it captures an uncatched exception, it will handle it and store it. In case of destruction (at the end of the process) it can re-throw it. Then PHP needs to deal with it and probably logs it. However I would consider that experimental and also perhaps short-sighted as there can be only one exception handler and it catches uncaught ones, so there is not much way to continue (more shutdown function material perhaps).