Re-throwing exceptions are not caught - php

I'm building a custom exception class to manage all exceptions:
class MyExceptions extends Exception
{
public function __construct($message = 'Unkown errror', $code = -1, Exception $previous = null) {
echo 'init!';
parent::__construct($message, $code, $previous);
}
}
Now, when a PDOException occurs, I want to re-throw it to MyExceptions:
class myDB
{
private $db;
public function dbConnect() {
try {
$this->db = new PDO('mysql:host=localhost;dbname=db;charset=utf8', 'user', 'pass');
}
catch (PDOException $e) {
throw new MyExceptions($e);
}
/* Updated */
catch (MyExceptions $e) {
echo 'caught!';
}
}
}
The problem is that when a db connection exception rises, I get the following fatal error on screen:
init!
Fatal error: Uncaught exception 'MyExceptions' with message...
So, the exception is not caught, although the MyExceptions __construct() is called (see the 'init!' displayed).
Every bit of resource I read points to the exact implementation as mine, I have no idea what I'm doing wrong.

You need
try {
try {
$this->db = new PDO('mysql:host=localhost;dbname=db;charset=utf8', 'user', 'pass');
} catch (PDOException $e) {
throw new MyExceptions($e);
}
} catch (MyExceptions $f) {
echo 'caught!';
}
Sequential catch blocks are for different types of exceptions thrown within the try.

You are throwing it:
throw new MyExceptions($e);
^^^^^
And then you don't catch it. So what do you wonder about?
Also you should add the previous exception at third position (for previous) instead of the first position (for message).

It doesn't go through all the catch blocks. Only the first one that matches. If you then throw another exception inside a catch block, you'd have to catch it in another try block around the first one.

Related

Can I use throw without any message?

Here is my code:
try {
if ( condition 1 ) {
throw;
} else {
// do something
}
// some code here
if ( condition 2 ){
throw;
}
} catch (Exception $e) {
echo "something is wrong";
}
As you see, my catch block has its own error message, And that message is a constant. So really I don't need to pass a message when I use throw like this:
throw new Exception('error message');
Well can I use throw without anything? I just need to jump into catch block.
Honestly writing an useless error message is annoying for me.
As you know my current code has a syntax error: (it referring to throw;)
Parse error: syntax error, unexpected ';' in {path}
message parameter is optional in the Exception constructor. So if you don't have/want to put - just don't:
throw new Exception;
But you still must throw an instance of the Exception class (or a class that extends it), since it is a part of the php language syntax.
If you want all your exceptions to have the same message, you can extend it and define the message in your class:
class AmbiguousException extends Exception {
public function __construct($message = 'Something is wrong.', $code = 0, Exception $previous = null) {
parent::__construct($message, $code, $previous);
}
}
Then:
throw new AmbiguousException();
You can use the below throw everytime you need.
throw new Exception();
and catch will remain same as your code.
As stated in the PHP manual:
The thrown object must be an instance of the Exception class or a subclass of Exception. Trying to throw an object that is not will result in a PHP Fatal Error.
You can throw an exception without any message:
throw new Exception();
Perhaps something to help you from duplicating the same exception is as follows:
$e = new Exception('something is wrong');
try {
throw $e;
} catch (Exception $ex) {
echo $ex->getMessage();
}
You can create an instance with default message and then throw that instance.
$Exception = new Exception("some error message!");
try {
throw $Exception;
} catch (Exception $ex) {
var_dump($ex);
}
You cannot use the throw keyword on its own. However, you can use throw new Exception(); without specify the $message parameter, because it'll just fallback to the default message. Check out the Exceptions section in the PHP manual: http://php.net/manual/en/language.exceptions.extending.php

Nesting custom Exception example

I don't understand why this code:
class MyException extends Exception {};
try {
try {
throw new MyException;
} catch (Exception $e) {
echo "1:";
throw $e;
} catch (MyException $e) {
echo "2:";
throw $e;
}
}
catch (Exception $e) {
echo get_class($e);
}
Returns: 1:MyException.
Isn't it supposed to catch the second one MyException and therefore return 2?
I thought with multiple exceptions it looks for the current try/catch first, but it looks like it catches the exception from the first try? or is it because MyException is empty and it uses Exception instead?
Exception here is a base class for your MyException class. Your $e variable has class MyException, so everything is right. If you make:
echo "1:";
var_dump($e);
throw $e;
you will see that $e is object(MyException). You haven't cast types, you just using polymorphism.
All your objects that have type Exception or it's subtypes will be caught in the 1-st block. Code will be executed in first by order block that can apply the exception.
Catch blocks are processed in the order they appear. Your code for catching MyException will never be called, because all subclasses of Exception are caught in your first catch block.

How can I check if file exists with exception handeling

I am trying to use exception handling in case a file does not exists. For example when I run the model method and pass a string usr (which I know there is no file with that name) . It gives me the following error message
Fatal error: Uncaught exception 'Exception' with message 'Usr.php was not found' in /app/core/controller.php on line 14
I can't figure out whats wrong here. Can someone please help me figure this out?
Below is my code. Thanks alot!
class Controllers{
public function model($model){
if(!file_exists("../app/models/".$model.".php")) {
throw new exception("{$model}.php was not found");
}
try {
require ("../app/models/".$model.".php");
} catch(Exception $e) {
echo $e->getMessage();
}
return new $model();
}
}
You can't throw an exception without catching it; this automatically causes the PHP script to crash. So, you need to surround your entire function in the try-catch block, or the "model not found" exception will be uncaught. Your code should be something like this:
<?php
class Controllers {
public function model($model){
try {
if (!file_exists("../app/models/".$model.".php")) {
throw new Exception("{$model}.php was not found");
}
require ("../app/models/".$model.".php");
} catch(Exception $e) {
echo $e->getMessage();
}
return new $model();
}
}
Never mind guys! I found out I needed to use the try/catch blocks in the file where my method is being invoked
Example..
class Home extends Controllers{
public function index($name = ""){
try{
$user = $this->model('Usr');
}catch (Exception $e){
echo $e->getMessage();
}
//var_dump($user);
}

Is it possible to have Try/Catch Throw with multiple exceptions

i have the following code and i'm wondering if i can use try & catch as below:
class fun_database implements idbInfo{
private $srvr=idbInfo::srvr_name;
private $usr=idbInfo::usrnm;
private $pass=idbInfo::psswrd;
private $db=idbInfo::db_name;
public function connct(){
$hookup = new mysqli($this->srvr, $this->usr, $this->pass, $this->db);
if ($hookup->connect_errno)
{
throw new Exception("Error Processing Request", 1);
}
}
public function sql_require_all($table_name, $table_col){
$hookup = new connct();
$result = $hookup->query("SELECT $table_col FROM $table_name");
if($hookup->error()){
throw new Exception("Error Processing Request", 1);
}
return $result->num_rows;
}
}
This is a simple connection to the mysql and performing some querying there. Here is and the actual call of the functions above:
$conn = new fun_database();
try{
$result = $conn->sql_require_all('wordtypes', 'types');
}
catch(Exception $err){
echo "Problems at:". $err->getMessage();
}
return "<option>".$result."</option>";
What i'm asking is a bit theory. Most probably this code is NOT WORKING (i didn't test it yet). I just want to know is it possible with one 'try' to 'catch' two exceptions (as you can see the first 'throw' is in the second method of fun_database, and the second 'throw' is in the first method of the same object which is only called from the second method).
sorry for making it too complicated but still can't figure it out id this structure of try/catch is working.
you can only catch different types of exception...
class fun_database implements idbInfo{
private $srvr=idbInfo::srvr_name;
private $usr=idbInfo::usrnm;
private $pass=idbInfo::psswrd;
private $db=idbInfo::db_name;
public function connct(){
$hookup = new mysqli($this->srvr, $this->usr, $this->pass, $this->db);
if ($hookup->connect_errno)
{
throw new DomainException("Error Processing Request", 1);
}
}
public function sql_require_all($table_name, $table_col){
$hookup = new connct();
$result = $hookup->query("SELECT $table_col FROM $table_name");
if($hookup->error()){
throw new Exception("Error Processing Request", 1);
}
return $result->num_rows;
}
}
Then:
try{
$conn = new fun_database();
$result = $conn->sql_require_all('wordtypes', 'types');
}
catch(DomainException $err){
echo "This Problem at:". $err->getMessage();
}
catch(Exception $err){
echo "That Problem at:". $err->getMessage();
}
return "<option>".$result."</option>";
you would need your class instantiation inside that try block though I believe.
It wouldn't catch the two exceptions because as soon as the first exception is thrown, it goes straight to the catch block, thereby skipping the second exception directly.
You could wrap each code which may throw an exception in its own try-catch block.
Yes and no. Your code is able to catch two of this exceptions but not both of them at the same time. When one of exception will be thrown, program execution will look for closest catch block, which fits to catch Exception class. Rest of code will be omitted.
You can throw an exception at an point in the program (not after an excpetion if it is not caught).
As soon as it hits this point it will stop and try to make the fallback to the a try catch block. As soon as it finds one it will do this block (if it is a good catch)
You could make a try catch around your entire program or just a function.
You can throw different classes of exceptions:
class ConnectException extends Exception {}
class QueryException extends Exception {}
and then catch different exceptions:
try {
// something
}
catch (ConnectException $ex) {
// connect exception
}
catch (QueryException $ex) {
// query exception
}
It is not possible because when you throw
throw new Exception("Error Processing Request", 1);
this exception it will be caught in this line
catch(Exception $err){
echo "This Problem at:". $err->getMessage();
}
you will not reach the line that can throw the other exception if first exception was thrown

How to make several tests using MDB2 with PHPUnit DataBase?

I use PHPUnit DataBase to test some class using MDB2.
All is well, since I encounter the second test, which returns an error:
Caught exception: Object of class
MDB2_Error could not be converted to
string
When I place the second test in place of the first one, the new first test is OK, but the second one returns the same error!
And the next ones also!
Maybe the MDB2 connection is closed after the first test?
Here is my constructor:
public function __construct()
{
$this->pdo = new PDO('connectionstring', 'user', 'passwd');
try {
$this->mdb2 = new MyDBA($this->dsn);
}
catch (Exception $e) {
error_log(' __construct Caught exception: '.$e->getMessage());
}
}
MyDBA returns a singleton.
No exception is raised inside the constructor...
Here are the two first tests:
public function testTranslationAdd()
{
try {
$id = $this->mdb2->addTranslation("This is the second english translation.","en");
}
catch (Exception $e) {
error_log(' testTranslationAdd Caught exception: '.$e->getMessage());
}
$xml_dataset = $this->createFlatXMLDataSet(dirname(__FILE__).'/state/twotranslations.xml');
$this->assertDataSetsEqual($xml_dataset,
$this->getConnection()->createDataSet(array("translation")));
}
public function testTranslationGet()
{
try {
$text = $this->mdb2->getTranslation(1,"en");
}
catch (Exception $e) {
error_log(' testTranslationGet Caught exception: '.$e->getMessage());
}
$this->assertEquals("This is the first english translation.",$text);
}
You should really add assertions that your mdb2 result is no error:
$this->assertFalse(MDB2::isError($this->mdb2), 'MDB2 error');
That unfortunately does not give you any hint what the error is, and using getMessage() directly in the assertion will fail badly if you don't have an error. That why you should write something along that way:
if (MDB2::isError($this->mdb2)) {
$this->fail('MDB2 error: ' . $this->mdb2->getMessage());
}

Categories