I want to analyze the result of each function that I call. If this result is a exception or is false then the script ends. I can do this manually, but it is a big waste of time to call a control function for each new function.
Can I configure PHP to set this error function automatically?
Check the comments , will give you and idea of how to register callbacks .
How do I catch a PHP Fatal Error
Here are some steps I ll suggest :
a) register register_shutdown_function or other callback functions to track your exceptiosn
b) Each function call Should throw an exception when there is error
c) call_back function catches the exception
d) echo custom output
check my comment on above reference question
You mean the call_user_func and call_user_func_array functions?
function error ($funcName, $funcParameter) {
try {
$params = func_get_args();
unset($params[0]);
call_user_func_array($funcName, $params) or exit ("Error !");
}
catch (exception $e) {
exit ("Error !");
}
}
Related
I am looking to get some advice on best practice for throwing exceptions and catching them. I am using a 3rd party library for connecting to Amazon mws API. This library already throws exceptions which I am catching within a function.
My question is, should this function pass the exception onto the main script by using a try-catch? e.g.
function myFunction() {
try {
$obj = new Object();
$obj->makeCall();
return $obj->getData();
} catch (Exception $ex) {
throw new Exception('There was a problem with the library '.$ex->getMessage());
}
}
then in the main script;
try {
//make the call
$response = myFunction();
} catch (Exception $e){
//log error
$logger->error("log error");
}
If you are catching the exception in the main script, you don't need to catch it in your function myFunction until you need to do some processing in your function.
The control will return to the exception being catched in the main script if any of it's children or children's children and so on throw an exception.
Is it possible to catch an exception in an generator and just yield the next value? I tried something similar like the code in the example below, but it stops on an exception and does not yield the next value as "expected".
function generator(){
foreach($aLotOfWork as $task){
try {
$promise = doSomethingThatCanFailBadly($task);
yield $promise;
} catch (Exception $e) {
echo "oh.. there is an error, but I don't care and continue";
}
}
}
IMHO This is not a duplicate of (php: catch exception and continue execution, is it possible?), because this person just wanted to know how to catch an exception in php and go on. In my case I already catch all exceptions, but the generator stops and does not go on as intended.
Your code is right and it will capture the exception and continue, check this out:
$ cat so.php
<?php
function doSomethingThatCanFailBadly($task) {
if ($task == 3) {
throw new Exception();
}
return $task;
}
function generator(){
$aLotOfWork = array(1,2,3,4,5);
foreach($aLotOfWork as $task){
try {
$promise = doSomethingThatCanFailBadly($task);
yield $promise;
} catch (Exception $e) {
echo "oh.. there is an error, but I don't care and continue\n";
}
}
}
foreach (generator() as $number) {
echo "$number\n";
}
?>
$ php so.php
1
2
oh.. there is an error, but I don't care and continue
4
5
Have a look at your error stack trace. Maybe what's happening is that something inside your doSomethingThatCanFailBadly method is producing an exception but it is also catching it and forcing the quit with die() or exit() before it ever gets to your catch block. There's not much you can do in that case. You could maybe use register_shutdown_function and see if that helps, but that is starting too look messy.
You would need to save to output of the generator to an array, and if during individual yields an exception is thrown, with right exception handling, it simply will not get into the array.
In your example the doSomethingThatCanFailBadly throws an exception, then the program flow gets to the catch branch. So actually doSomethingThatCanFailBadly has no return value that could be assigned to $promise - so there's nothing to yield at that point.
#palako explained the problem very nicely, but he does not really provide a solution for my case. I use this generator to generate Promises and the consumer (Guzzle's EachPromise-method) seems to stop working on an Exception. So I replaced the throw new SomeException('error message') statement by return RejectedPromise('error message').
I have to admit that this is a very situation-specific solution, but you can do something similar in other settings too: just return an object instead of using exceptions.
In the PHP project I'm working on there are several methods that make use of individual try/catch blocks. Here is one example:
public function getListData()
{
$clauses['filter'] = '';
$clauses['sort'] = 'CAST(propertyID AS INT) DESC';
try
{
return $this->getModel()->getListData($clauses);
}
catch (Exception $e)
{
// create an Error() object, send $e->getMessage() to it
}
}
Now, keeping in mind there are several similar methods, it would seem more efficient to write a method in the Model class that would look like this:
public function run($method)
{
try
{
return $this->$method;
}
catch (Exception $e)
{
//create an Error() object, send $e->getMessage() to it
}
}
The problem is calling it. This does not work:
public function getListData()
{
return $this->getModel()->run('getListData($clauses)');
}
The error is:
Undefined property:
classes\utility\Model::$getListData($clauses).
Is there a way to get this to work?
I'm going to assume that the first and second getListData() methods are in separate classes, otherwise you are calling a loop, since getListData would call getListData...which would call, you get it.
However, the way you are calling the method is incorrect in the run() method. It should be called using call_user_func. It is a callback to the method, not a call to the property, of the class.
You could call it statically using
public function run($method, $data)
{
try
{
return call_user_func(array($this, $method), $data);
}
catch (Exception $e)
{
//create an Error() object, send $e->getMessage() to it
}
}
public function getListData()
{
return $this->getModel()->run('getListData', $clauses);
}
There are several problems with this approach:
It prevents you from listening for custom exceptions
You can throw exceptions other than Exception, but this type of wrapper will make it much more difficult to do so.
It is difficult to follow the execution flow
When you pass method names and parameters around as strings, it becomes much harder for humans, IDEs and code analysis tools to understand what the program will do at runtime.
Try/catch blocks are cheap
The code required to catch exceptions is very simple and easy to use. This wrapper adds more complexity and more cost (an extra function call).
Consider just using try/catch blocks where needed instead of using the wrapper. If you have fifty similar methods as described in your comment above, you may gain more efficiency by eliminating the duplicate business logic and combining those methods.
You could simply convert errors to exceptions using this code:
set_error_handler(function ($errno, $errstr, $errfile, $errline)
{
if ((error_reporting() & $errno) === $errno)
throw new \Exception("$errstr ($errfile: $errline)", (int) $errno);
}, -1);
After it any error would be converted to exception.
How do i catch (custom)exceptions (with custom exception handler) that i have thrown in custom shutdown function ? I am not using any framework.
Example:
register_shutdown_function( 'shutdownFunction');
set_exception_handler( 'exceptionHandler');
function exceptionHandler(Exception $exception)
{
// handle and log exception for later debugging...
}
function shutdownFunction()
{
// something is not going right...
if (someVariable != someValue)
throw new RuntimeException('blah...'); // WILL NOT be caught by exception handler
}
// somewhere else in the code...
throw new Exception('something...'); // WILL be caught by exception handler (but not in shutdown function)
The script is using exceptions to communicate that it encountered an error during execution ie. unexpected variable passed to function, database failed to insert row etc...
You simply cannot do this in php.
The register_shutdown_function callback is the last thing that happens in your PHP application. Trying to throw an exception in there will not do anything but invoke a standard php handler. There isn't much to be found on the web regarding these inner workings.
However, I created my own solution for directing it to a single function.
set_exception_handler and register_shutdown_functionare very different functions:
set_exception_handler receives a single argument Exception
register_shutdown_function receives no arguments by default
I've made it so that the set_exception_handler (which receives $exception as argument) sets a property which I can use in the register_shutdown_function.
$lastException = null;
set_exception_handler(function ($e) use (&$lastException) {
$lastException = $e;
});
register_shutdown_function(function() use(&$lastException) {
if($error = error_get_last()) {
$lastException = new \ErrorException($error['message'], $error['type'], 1, $error['file'], $error['line']);
}
if($lastException) {
if (APPLICATION_ENV === 'production') {
Sentry\captureException($lastException);
} else {
var_dump($lastException);
}
}
});
I have no clue if this is a good way to solve the issue, but it allowed me to catch require unexisting_phpfile1389.php errors (Fatal) and regular throw \Exception()s in the same function.
Trying to throw an exception inside the shutdown handler will result in the following exception (how ironic):
( ! ) Fatal error: Uncaught Error: Can only throw objects in
C:...\index.php on line 34
( ! ) Error: Can only throw objects in
C:...\index.php on line 34
You can just wrap the body of your shutdownFunction with
function shutdownFunction()
try {
...
} catch (\Exception $e) {
// do something
}
}
and you will catch all exceptions becase Exception is the base class for all of them
It's quite simple:
function exception_handler (Exception $e) {
if ($e instanceof DBException)
error_handler (['query' => $e->getQuery ()]); // Your actions with your custom Exception object
}
function error_handler ($error) {
if (isset ($error['query']))
echo $error['query'];
else
// Another errors
}
set_error_handler ('error_handler', E_ALL);
set_exception_handler ('exception_handler');
I have come accross to this function below and I am wondering wether this is the right way of using the error handling of try/catch.
public function execute()
{
$lbReturn = false;
$lsQuery = $this->msLastQuery;
try
{
$lrResource = mysql_query($lsQuery);
if(!$lrResource)
{
throw new MysqlException("Unable to execute query: ".$lsQuery);
}
else
{
$this->mrQueryResource = $lrResource;
$lbReturn = true;
}
}
catch(MysqlException $errorMsg)
{
ErrorHandler::handleException($errorMsg);
}
return $lbReturn;
}
Codewise it is correct/works, However the power of try-catch is that when an Exception is thrown from deep down in one of the functions you're calling.
Because of the "stop execution mid-function and jump all the way back to the catch block".
In this case there are no deep-down exceptions therefore I would write it like this:
(Assuming there is a function "handleErrorMessage" in the ErrorHandler.)
public function execute() {
$lsQuery = $this->msLastQuery;
$lrResource = mysql_query($lsQuery);
if(!$lrResource) {
ErrorHandler::handleErrorMessage("Unable to execute query: ".$lsQuery);
return false;
}
$this->mrQueryResource = $lrResource;
return true;
}
Which I find more readable.
No. Throwing an exception in this case is simply a GOTO, but with a (slightly) prettier face.
Why have a call to ErrorHandler::handleException here anyway?
Just throw the exception, but never catch it. Then in the global initialization code for your app have a function with the following signature:
function catchAllExceptions(Exception $e)
Then call:
set_exception_handler('catchAllExceptions');
This will cause all uncaught excpetions to be passed as an argument to catchAllExceptions(). Handling all uncaught exceptions in one place like this is good, as you reduce code replication.
Well it is not really a good implementation since you throw the exception and you look for that exception in catch. So the answer of Visage is true.
You should use a global error handler instead of a tr-catch usage like in your code.
If you are not sure of the type of the error and occurance but want to continue the execution of the code although an exception had occured, then a try-catch block will help.