Why do I get an "Uncaught exception" error? - php

I have the following PHP code:
foreach (...) {
try {
$Object = MyDataMapper::getById(123);
if (!$Object->propertyIsTrue()) {
continue;
}
}
catch (Exception $e) {
continue;
}
}
MyDataMapper::getById() will throw an Exception if a database record is not found. Here is the definition of that method:
public static function getById($id) {
$query = "SELECT * FROM table WHERE id = $id";
$Connection = Database::getInstance();
$Statement = $Connection->prepare($query);
$Statement->execute();
if ($Statement->rowCount() == 0) {
throw new Exception("Record does not exist!");
return null;
}
$row = $Statement->fetch();
return self::create($row);
}
When this code is called for a database record id that does not exist, I get a fatal uncaught exception 'Exception' error.
Why is this? Clearly I am catching the exception... What am I doing wrong?
I am sure an exception is being thrown. Is there something wrong with how I am handling the exception--maybe with the continue?
EDIT
Thanks to help from jitter, the following workaround solves this problem:
if (!$Object->propertyIsTrue()) {
// Workaround to eAccelerator bug 291 (http://eaccelerator.net/ticket/291).
$foo = 555;
continue;
}

What PHP version? -> 5.2.9
Are you using eAccelerator (which version)? -> 0.9.5.3 with ionCube PHP Loader v3.1.34
What kind of exception do you throw? -> normal Exception
There are known problems in certain PHP + eAccelerator versions in regard to try-catch blocks being optimized away.
Check the eAccelerator bug-tracker:
For a starter check the tickets
291 Incorrect handling of exception
314 Exceptions not catched
317 Exception not caught
and try disabling eAccelerator.

I think it may be because you're calling a static method, but I could be wrong. Is it possible for you to test this by instantiating MyDataMapper and calling the method from the object itself?

Related

I can not catch exception in Yii framework

I am using Yii framework and have written code below. When there is no entry for a specific id it gives Error: Call to a member function delete() on a non-object which is a yii\base\ErrorException indicated in debug mode. The problem is that I am not able to catch this exception despite my inclusion of yii\base\ErrorException and specify it catch block. What is the problem here?
use yii\base\ErrorException;
try {
$model = BranchUser::findOne($_GET['id']);
$model->delete();
return $this->redirect(['index']);
} catch (ErrorException $e) {
return $this->redirect(['site/error']);
// Error, rollback transaction
throw $e;
// print_r($model->getErrors());
}
That is a fatal error and it is not possible to recover from it.
You should check that $model is something else than null before you try to use it.
if ($model === null) {
return $this->redirect(['site/error']);
}
Such errors are catchable in PHP 7.0, so that's good.

libcouchbase connection errors

Couchbase keeps complaining that I don't have a connection to Couchbase:
2013-10-28T11:15:46.580320-07:00 hoot77 apache2[30455]: PHP Warning: There is no active connection to couchbase in /ebs1/www/src/core/components/In/Couchbase/Bucket.php on line 112
The following is the piece of code that is trying to run, its a simple set.
*/
public function set($key, $doc, $try = 0) {
// Make sure designDoc and dataView are set
if(empty($this->designDoc) && empty($this->dataView)) {
throw new In_Exception('Missing Design Doc and/or View name for Couchbase', 400);
}
try {
$results = $this->cb->set($key, $doc);
} catch(CouchbaseLibcouchbaseException $e) {
// Connection not active, try to rebuild connection and query again
// Log stats on exception
Statsd::increment("web.Couchbase.Exception.LibCouchbaseException.{$this->instanceKey}");
Logger::error("LibCouchbaseException on {$this->instanceKey}: {$e->getMessage()}");
// Try to reconnect and query up to twice
$try++;
if($try <= 2) {
$this->rebuildConnection();
return $this->set($key, $doc, $try);
} else {
// Fail if we've already tried twice
throw new In_Exception('Could not connect to Couchbase', 500);
}
} catch(CouchbaseException $e) {
// Catch general exception, try to determine cause
// Log stats on exception
Statsd::increment("web.Couchbase.Exception.CouchbaseException.{$this->instanceKey}");
Logger::error("CouchbaseException on {$this->instanceKey}: {$e->getMessage()}");
// Throw exception if design document or view not found
if($this->getExceptionCode($e->getMessage()) == 404) {
throw new In_Exception('Design Document, or View not found in Couchbase', 404);
} else {
throw new In_Exception('Error with Couchbase, try again.', 500);
}
}
// Success, return results
Statsd::increment("web.couchbase.{$this->instanceKey}.success");
return $results;
}
The line that its complaining about is:
$results = $this->cb->set($key, $doc);
You can see that my quick solution was to try to reconnect up to twice on failure, but that doesn't seem to be helping at all, the errors still persist in great numbers.
It's actually not catching the exceptions and reporting them consistently either, which is annoying, because PHP is throwing these as warnings, not exceptions.
Let me know if you have any suggestions as to how to solve this, it would be greatly appreciated. Thanks!

PHP try/catch and fatal error

I'm using the following script to use a database using PHP:
try{
$db = new PDO('mysql:host='.$host.';port='.$port.';dbname='.$db, $user, $pass, $options);
}
catch(Exception $e){
$GLOBALS['errors'][] = $e;
}
Now, I want to use this database handle to do a request using this code:
try{
$query = $db->prepare("INSERT INTO users (...) VALUES (...);");
$query->execute(array(
'...' => $...,
'...' => $...
));
}
catch(Exception $e){
$GLOBALS['errors'][] = $e;
}
Here is the problem:
When the connection to the DB is OK, everything works,
When the connection fails but I don't use the DB, I have the $GLOBALS['errors'][] array and the script is still running afterwards,
When the connection to the DB has failed, I get the following fatal error:
Notice: Undefined variable: db in C:\xampp\htdocs[...]\test.php on line 32
Fatal error: Call to a member function prepare() on a non-object in C:\xampp\htdocs[...]\test.php on line 32
Note: Line 32 is the $query = $db->prepare(...) instruction.
That is to say, the script crashes, and the try/catch seems to be useless. Do you know why this second try/catch don't works and how to solve it?
Thanks for the help!
EDIT: There are some really good replies. I've validated one which is not exactly what I wanted to do, but which is probably the best approach.
try/catch blocks only work for thrown exceptions (throw Exception or a subclass of Exception must be called). You cannot catch fatal errors using try/catch.
If your DB connection cannot be established, I would consider it fatal since you probably need your DB to do anything meaningful on the page.
PDO will throw an exception if the connection cannot be established. Your specific problem is that $db is not defined when you try to call a method with it so you get a null pointer (sort of) which is fatal. Rather than jump through if ($db == null) hoops as others are suggesting, you should just fix your code to make sure that $db is either always defined when you need it or have a less fragile way of making sure a DB connection is available in the code that uses it.
If you really want to "catch" fatal errors, use set_error_handler, but this still stops script execution on fatal errors.
In PHP7, we now can using try catch fatal error with simple work
try {
do some thing evil
} catch (Error $e) {
echo 'Now you can catch me!';
}
But usualy, we should avoid using catch Error, because it involve to miss code which is belong to programmer's reponsibility :-)
I will not report what has already been written about testing if $db is empty. Just add that a "clean" solution is to artificially create an exception if the connection to the database failed:
if ($db == NULL) throw new Exception('Connection failed.');
Insert the previous line in the try - catch as follow:
try{
// This line create an exception if $db is empty
if ($db == NULL) throw new Exception('Connection failed.');
$query = $db->prepare("INSERT INTO users (...) VALUES (...);");
$query->execute(array(
'...' => $...,
'...' => $...
));
}
catch(Exception $e){
$GLOBALS['errors'][] = $e;
}
Hope this will help others!
If database connection fails, $db from your first try .. catch block will be null. That's why later you cannot use a member of non-object, in your case $db->prepare(...). Before using this add
if ($db) {
// other try catch statement
}
This will ensure that you have db instance to work with it.
Try adding the following if statement :
if ($db) {
$query = $db->prepare("INSERT INTO users (...) VALUES (...);");
$query->execute(....);
}
else die('Connection lost');
try{
if(!is_null($db))
{
$query = $db->prepare("INSERT INTO users (...) VALUES (...);");
$query->execute(array(
'...' => $...,
'...' => $...
));
}
}
catch(Exception $e){
$GLOBALS['errors'][] = $e;
}

Global php PDO handling errors

I use try/catch block in my classes methods, If a get an exception, I log the error. But I would like to tell the "User" that a database query/etc failed - and the problem should be fixed soon.
I could use a die() on the Exception in my methods, but that wouldn't be DRY, as I would have to retype it a lot, so any suggestions on how I can do this.
Example method:
public function login($username, $password) {
try {
$this->STH = $this->DBH->prepare("SELECT id, baned, activated FROM users WHERE username = ? AND password = ?");
$this->STH->setFetchMode(PDO::FETCH_OBJ);
$this->STH->execute(array($username, $password));
if (($row = $this->STH->fetch()) !== false)
return $row;
} catch (PDOException $e) {
//Log $e->getMessage();
die('A database error occoured, we are working on the problem, and it should work in a few...');
}
}
If you need a quick fix, you can set a global exception handler, like this:
function pdo_exception_handler($exception) {
if ($exception instanceof PDOException) {
// do something specific for PDO exceptions
} else {
// since the normal exception handler won't be called anymore, you
// should handle normal exceptions yourself too
}
}
set_exception_handler('pdo_exception_handler');
It's OK to repeat yourself in this case because as each instance of die() passes a unique message.

correct way of using a throw try catch error handling

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.

Categories