I have a database class dbconnect.php, and processform.php. Inside dbconnect.php there is a method for connecting to the database.
If there's an error, how do I throw an exception? Where do I put the try catch block, in the processform.php? People say I shouldn't echo an error directly from inside the class. Here's an example:
<?php
// dbconnect.php
class DbConnect
{
public function open_connection()
{
/* Should I do it like this? */
$this->conn = PDO($dsn, $this->username, $this->password);
if (!$this->conn) {
throw new Exception('Error connecting to the database.');
}
/* Or like this */
try {
$this->conn = PDO($dsn, $this->username, $this->password);
} catch (PDOException $e) {
echo 'Error: ', $e->getMessage(), '<br>';
}
}
?>
// processform.php
<?php
require_once 'dbconnect.php';
$pdo = new DbConnect($host, $username, $password);
try {
$pdo->open_connection();
} catch (PDOException $e) {
echo 'Error connecting to the database.');
}
?>
I really want to learn the correct way of implementing the try catch in my code.
You don't have to throw an exception manually, especially on a successful connect :-)
Instead you need to tell PDO that it needs to throw exceptions when something goes wrong and you can do that when you open your database connection:
$options = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION);
$this->conn = new PDO($dsn, $this->username, $this->password, $options);
Now you can put everything in try / catch blocks but that is not even necessary; if you don't do that, php will show you unhandled exceptions complete with a stack trace when you don't catch them manually.
And when you decide you want to fine-tune your error handling for your visitors, you can set your own exception handler using set_exception_handler(). That way you can handle everything at one place instead of wrapping different sections in try / catch blocks. Should you prefer that of course.
In my practice, I prefer to catch exception in bottom. I mean, second way in your DbConnect.
You can output error message to error log. And return an error code to front-end. So the front-end knows how to tell users an error occours in a friendly way.
What's more, you can use global error handler such as set_error_handler/set_exception_handler to do this. Redirect to an error page when error occours.
Related
I'm using PHP and PDO. Now I want to build a kind of log when things go wrong. What can go wrong with PDO?
Right now I have these tests:
Connection test
try {
$this->pdo = new PDO($dsn, $credentials['user'], $credentials['pass'], $options);
} catch(Exception $e) {
$this->file->put( date('Y-m-d') . '.txt', 'log', 'Database error');
}
Execute test
try {
$stmt->execute();
} catch(Exception $e) {
$this->error->log('SQL', 'query error');
}
Any more tests that are good?
You do not log your exception message in your logs. I suggest you to do something like this into your catch :
$this->error->log('SQL', $e . PHP_EOL);
This will give you more understandable and readable logs.
Regarding the exceptions to catch with PDO, you may read that post : How to handle PDO exceptions
Is there a way to setup a Pdo object to throw a custom exception instead of the default PDOException?
For example:
class MyCustomDbException extends PDOException{}
$pdo = new Pdo("mysql:host=localhost;dbname=myapp", "user_name", "secret_password");
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_EXCEPTION_CLASS, "MyCustomDbException");
try {
// Code is here
} catch (PDOException $e) {
// See exception manual if you want to path through message or anything else from pdo exception.
throw new YourException('PDO exception was thrown');
}
http://php.net/manual/en/language.exceptions.extending.php
to see how you can path through parameters.
I am currently writing a web app in PHP and have decided to use exceptions (duh!).
I could not find an answer to whether putting try and catch blocks in all functions would be considered bad code.
I am currently using Exceptions to handle Database errors (Application errors are handled via a simple function which just adds them to an array and then they are displayed to the user). The try blocks are placed on all functions which require a database connection.
The code in question is:
public function db_conn_verify()
{
if(!isset($this->_mysqli)){
throw new Exception("Network Error: Database connection could not be established.");
} else {
return Null;
}
}
And an example function using this code:
public function get_users() {
try {
$this->db_conn_verify();
//Rest of function code
return True;
} Catch(Exception $e) {
Core::system_error('function get_users()', $e->getMessage());
return False;
}
}
Also would it be better to extend the Exception class and then use that new Exception class to handle application errors?
Thanks
I suggest to you to use something like this:
public function get_users() {
try {
if( !isset($this->_mysqli) ) {
throw new Exception("Network Error: Database connection could not be established.");
}
//Rest of function code
} Catch(Exception $e) {
Core::system_error('function get_users()', $e->getMessage());
}
}
I prefer to use my exends of Exception, but is the same. For exdending exception you can see the PHP documentation to Example #5
EDIT: For an immediate use of try-catch on database connection error you can try this:
try{
$mysqli = new mysqli("localhost", "user", "password", "database");
if ($mysqli->connect_errno) {
throw new Exception("Network Error: Database connection could not be established.");
}
} Catch(Exception $e) {
Core::system_error('function get_users()', $e->getMessage());
}
Okay, so this is my code:
try {
$pdo = new PDO ('mysql:host=127.0.0.1;dbname=db_name','user','password');
} catch (PDOException $e) {
exit ('Database error.');
}
I tried so many different combinations with host name, username and password, and every time I get 'Database error'.
My question is:
What should I do to succesfully transfer MySQL database from localhost to my hosted server using this part of code (which is my connection.php file)?
Thank you, in advance.
Get rid of this try catch stuff. Leave it as
$pdo = new PDO ('mysql:host=127.0.0.1;dbname=db_name','user','password');
And see what it says (on-screen or logs)
Use this try and catch block for error trace
try {
$this->conn = new PDO('mysql:host=127.0.0.1;dbname=db_name','user','password');
$this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
echo 'Error: ' . $e->getMessage();
}
Here is Database.php:
<?php
/*Data Base Class
* MySQL - InnoDB
* PHP - PDO (PHP Data Object -So we could change databases if needed)
*/
class Database extends PDO{
private $DBH;
function __construct($host, $dbname, $user, $pass){
try {
$this->DBH = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass);
} catch (PDOException $e) {
return $e->getMessage();
}
}
public function alteration_query($sql){
/* Begin a transaction, turning off autocommit */
$this->DBH->beginTransaction();
try{
$count = $this->DBH->exec($sql);
$this->DBH->commit();
return $count;
}catch (PDOException $e) {
$this->DBH->rollback();
return $e;
}
}
}
?>
Here is test.php:
<?php
require('Database.php');
$dbo = new Database('***.***.com','***','***','***');
echo $dbo->alteration_query('DELETE * from T_Table');
?>
For some reason, it won't give me an error or delete the contents of the T_table.
EDIT: The problem in your case is that the argument is called $sql, but you're using $query to execute it (in the alteration_query method). Next time, please enable error reporting, and/or use a decent IDE, that can show you these errors. Like so:
EDIT2: Set PDO's error mode to exception, this way any error would throw an exception. See updated code.
Don't catch your exceptions inside of the functions, do it outside:
<?php
/*Data Base Class
* MySQL - InnoDB
* PHP - PDO (PHP Data Object -So we could change databases if needed)
*/
class Database
{
private $DBH;
function __construct($host, $dbname, $user, $pass)
{
$this->DBH = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass);
//Set PDO to throw exceptions on errors!
$this->DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
public function alteration_query($sql)
{
/* Begin a transaction, turning off autocommit */
$this->DBH->beginTransaction();
$count = $this->DBH->exec($query);
$this->DBH->commit();
return $count;
}
}
try {
$pdo = new Database("localhost", "dbname", "user", "pass");
$pdo->alteration_query("SELECT * FROM wrong_table");
}
catch (PDOException $e) {
die("An error has occured! " . $e->getMessage());
}
This way, you can catch the error exactly where you need it, and not force it inside of the function (which kinda beats the point of the exception).
Also, from the manual:
When the script ends or when a connection is about to be closed, if
you have an outstanding transaction, PDO will automatically roll it
back. This is a safety measure to help avoid inconsistency in the
cases where the script terminates unexpectedly--if you didn't
explicitly commit the transaction, then it is assumed that something
went awry, so the rollback is performed for the safety of your data.
Exceptions halt the execution of the function, meaning the commit() never happens, and it rolls back.
Try this line :
$this->DBH = new parent::__construct("mysql:host=$host;dbname=$dbname", $user, $pass);
Reason : __construct overwrite the main class function. I think that's why, really not sure.
If it's not working, try parrent::PDO. I am pretty sure it an overwrite problem.