I'm working on an asynchronous process on a PHP project. I'm using a library named spatie/async. The code snippet is like below :
foreach (range(1, 2) as $i) {
$pool->add(function () use ($i) {
// Do a thing
try {
$result = $i / 0; // This will cause an error
return "Works";
} catch (\Exception $e) {
return -1;
}
})->then(function ($output) {
// Handle success
echo (output . "\n");
})->catch(function ($exception) {
// When an exception is thrown, it's caught and passed here.
echo "Sounds good, but don't work\n";
})
}
$pool->wait();
All I want is when the $result got an error, it will go into the inner catch, but instead, it goes down to the bottom catch which causing a different result from what I want.
The result that I want is :
-1
-1
But instead, the result is :
Sounds good, but don't work
Sounds good, but don't work
Can anyone help me to achieve the result as I want?
The problem of your code is, that it does not throw an Exception in the add method call. A division by 0 is just causing an error, but not ein exception. Instead of changing the whole php error handler, I 'd suggest to extend your logic a little bit in your add method call.
$divisor = 0;
$pool->add(function() use ($i, $divisor) {
try {
if ($divisor === 0) {
throw new \LogicException('Division by zero!');
}
return $i / $divisor;
} catch (\LogicException $e) {
return -1;
}
});
Another solution could be changing the error handling for the pool method call.
set_error_handler(function () {
throw new \LogicException('Ouch!');
});
$pool->add(function() use ($i) {
try {
$result = $i / 0;
} catch (\LogicException $e) {
return -1;
}
});
restore_error_handler();
Caution! Changing the error handler affects all upcoming errors. Even the errors thrown in your used library. Keep in mind, that these are code snippets. This is not tested or thougt to be used in production. Hope that helps out a little bit.
Related
i have a loop like that
foreach ($array as $row) {
$row->executeThatFunction();
}
.
.
.
public function executeThatFunction($someVariable) {
// do something that may craches
}
So i want to continue looping even if the executeThatFunction() craches (php error for example)
How can i do that ?
PS : i'm working on symfony2 project, so if symfony provide some solution for that case i'll be glad to learn it.
Thanks in advance
EDIT :
Can i do something like that ?
foreach ($array as $row) {
try {
$row->executeThatFunction();
} catch($e)
{
continue;
}
}
If your using php7: php7 throws errors like exceptions. And all recoverable errors are catchable. And also both errors and exceptions implement a common interface called Throwable.
That means you can surround your call with a try-catch-block and simply continue the loop, when a throwable error occurs:
foreach ($array as $row) {
try {
$row->executeThatFunction();
} catch (Throwable $t) {
// you may want to add some logging here...
continue;
}
}
You can use try ... catch block in your function:
public function executeThatFunction($someVariable) {
try {
// do something that may craches
} catch($e)
{
// handle your error here
}
}
My question is about the correct usage of Php Exceptions.
My Php app is an API server.
My code base is quite articulated, to a depth of 5-6 levels of nested calls.
Of course exceptions are a very handy way to handle an error,
since you don't have to handle all error conditions on every level of your function calls...
To better explain what I mean, I make an exaple below.
This is a simplified excerpt from my top level code (the "router"):
...
$this->app->get("/persons/get", function() {
try {
$persons = new PersonsController($this);
$this->success($persons->get());
} catch (Exception $e) {
$this->error($e);
});
};
...
private function error($error) {
$response = $this->app->response();
$response->body(json_encode([
"error" => [
"message" => $error->getMessage(),
]));
}
And this is a simplified excerpt from my bottom level code (the "db"):
...
public function get($table) {
try {
$sql = "SELECT * FROM '$table'";
$statement = $this->db->prepare($sql);
$statement->execute();
$result = $statement->fetchAll(PDO::FETCH_ASSOC);
return $result;
} catch (PDOException $e) {
throw new Exception("Error getting persons: ", 0, $e);
}
}
I think this is a typical and effective example of useful exception handling: on a fatal error in the bottom level of the code base, the error automatically pops up to the main error handling function. The real advantage here is I don't have to mess up with handling the error condition all along the chain of functions code, from the router level through the db level...
But, what if I should use Exceptions more extensively, in the middle of my functions stack... For example:
class PersonsController {
...
public function sync() {
if (!mkdir($d, 0777)) {
throw new Exception("Can't create folder $d");
}
}
...
}
Instead of, for example:
class PersonsController {
...
public function sync() {
if (!mkdir($d, 0777)) {dir: DEBUG ONLY!
return -1; # this error code will have to be handled upper in the stack...
}
}
...
}
The question is: How extensive can be the use of Exceptions in a Php non-trivial project?
When I execute my script something went wrong and an exception is thrown, but instead of stop the all script. How can I tell to zend to continue ?
This error appear when I fetch a mail I have a try catch block but it doesn't catch.
Fatal error: Uncaught exception 'Zend\Mail\Exception\RuntimeException' with message 'Line "X-Assp-Message/IP-Score:
Thanks.
My code is a simple class to fetch mail :
$listm = new Zend\Mail\Storage\Pop3(array('host' => $this->mServer,'user' => $this->mMail, 'password' => $this->mPassword));
foreach ($listm as $msgp3)
{
try
{
e($msgp3->from);
e($msgp3->to);
e($msgp3->subject);
e($msgp3->date);
e(strtotime($msgp3->date));
e($msgp3->messageid);
} catch (Exception $e) {
e($e->getMessage());
}
}
And my code stop at the 10em mail, so how make to tell to Zend to doesn't stop ?
The point of an Exception is to tell you that something bad has happened, and you need to build code to handle that properly. Without seeing your code, it's kinda hard to debug though.
If you want not to stop a process when a exception has been pointed. You can use a try and catch method. Like this:
try {
DoSomethingReallyBad()
}
catch(RuntimeException $e) {
// do nothing
}
// go further
I must say when a exception is called. The process of your last task is quitted.
Note: I didn't test this!
How are you catching the exception? Can you supply the try/catch code in your question please?
In Zend you need to use the full zend exception class that is being thrown. In this case it is Zend\Mail\Exception\RuntimeException, which becomes Zend_Mail_Exception_RuntimeException.
try
{
// ...
}
catch (Zend_Mail_Exception_RuntimeException $e)
{
// ...
}
I finally found where was my problem :
The error is return when i fetch the message here so in the for instruction :
foreach ($listm **as $msgp3**)
To catch any error when the message is fetch i have to fetch this way :
$maxMessage = count($messageList);
for($i = 0; $i < $maxMessage; $i++)
{
try{
$msgp3 = $messageList->getMessage($i);
//--- WORK ON msgp3
}catch(Exception $e) {
echo 'E2->'.$e->getMessage();
}
}
And now my script continue...
Which is the right way to implement php exception (try{}catch(){}) in a foreach loop that looks like this:
foreach ($apis as $api)
{
$api = '_'.$api;
$searchResults[$api] = $this->$api($parameters);
}
I want to implement the php exceptions for if one of the $this->api(); returns an error message, than catch it and do a if inside the catch to display the right message for the error message returned.
Edit:
Also, when capturing the error and if the error message is 1 (for example) is it a good way to do:
$searchResults['api'] = $this->_api($parameters);
so it tries to do the function again and see if this time it brings valid data?
foreach ($apis as $api)
{
$api = '_'.$api;
try {
$searchResults[$api] = $this->$api($parameters);
}
catch(ParameterException $e) {
// parameterexception handling here
echo "A ParameterException was thrown";
}
catch(Exception $e) {
// All other exceptions
echo "Some other Exception was thrown";
}
}
You can differentiate between more Exception-Types as well.
Since the catch block will be executed only in case of an exception, it really makes no difference if you wrap the for-each loop inside the try block, or if you put the try-catch inside the loop's body.
You should take whatever adds more clarity. However, doing it inside the loop will enable you to handle more specific exceptions relevant to the loop's body if the need arises in the future.
Also, since exceptions are typed, you don't need to do an if, just put different catch clauses:
try {
:
} catch (FirstExceptionType $e) {
:
} catch (SecondExceptionType $e) {
:
}
The code you use will always fail, because you are trying to use a variable ($this->$api($params);) as a function. How ever, you could implement your try-catch as follows:
foreach ($apis as $api)
{
$api = '_'.$api;
try {
$searchResults[$api] = $this->$api($parameters);
}
catch(Exception $e) {
// handle exception
}
}
You can also handle multiple Exceptions of different types by adding another catch() with another Exception class inside it, like:
foreach ($apis as $api)
{
$api = '_'.$api;
try {
$searchResults[$api] = $this->$api($parameters);
}
catch(OtherException $e) {
// Handle it
}
catch(Exception $e) {
// Handle it
}
}
This question is in continuation from this as suggested by one of the user.
I am using the getIDs function as below to process the id's. CheckValid() will check if the id's is a valid one to be processed, if yes then it will go to the next one updateUsers(). Check valid just checks for a condition and if not it throws an exception. updateUsers() just updates a column if it passes checkValid().
Problem – If I get 4 id's as output from getIDs(), and with the execute(), it process 2 for example and if it fails for 2nd id, it doesn't continue for the rest 2 id's ..I want it to continue so I commented out the "throw $e in the catch block".
Function execute() {
for($i=0 ; $i<count($this->getIDs()); $i++) {
try {
$this->checkValid();
$this->updateUsers();
} catch(Exception $e) {
//throw $e;
}
have you try a simple continue in the catch block ? didn't test but maybe something like that:
Function execute() {
for($i=0 ; $i<count($this->getIDs()); $i++) {
try {
$this->checkValid();
$this->updateUsers();
} catch(Exception $e) {
//throw $e;
continue; // if not working try a continue 2;
}
}
}
It sounds like you're using exceptions as booleans, I'd suggest avoiding that, as it gets confusing quickly, unless you really need the contents of the exception. See if this makes any sense for your use case (I'll grant, it may not).
// returns true if valid, false otherwise
function checkValid(){
try {
// do your validation
return true;
} catch (Exception $e) {
// optional: save the exception in case we want to know about it
$this->last_error = $e;
return false;
}
}
function execute() {
for($i=0 ; $i<count($this->getIDs()); $i++) {
if($this->checkValid()){
$this->updateUsers();
}
// if you want to do something with an error, simply add an else clause
// and handle $this->last_error
}
}
Also, I obviously don't know your code or what exactly you're doing, but looping n times and calling checkValid() and updateUsers() without parameters seems like very poor practice. Much better to, for instance, loop over the list of IDs and check each ID and user in turn, something like this:
foreach($this->getIDs() as $id){
if($this->checkValid($id)){
$this->updateUser($id);
} else {
// an advantage of this is now we can know exactly which ID failed,
// because we have the $id variable
}
}