PHP when to use try/catch? - php

I was just wondering something. In index.php, I am currently doing something like this
function performFtpOperation() {
global $config;
try {
$ftp = new FTP\FtpClient();
$ftp->connect($config::FTP_SERVER);
$ftp->login($config::FTP_USER, $config::FTP_PASSWORD);
} catch (Exception $e) {
echo 'Error: ', $e->getMessage();
}
}
What I was wondering is if that try catch block is needed? Reason I question it is because my FTP class throws errors if something goes wrong. For instance this is the connect function
public function connect($host, $ssl = false, $port = 21, $timeout = 90)
{
if ($ssl) {
$this->conn = #$this->ftp->ssl_connect($host, $port, $timeout);
} else {
$this->conn = #$this->ftp->connect($host, $port, $timeout);
}
if (!$this->conn) {
throw new Exception('Unable to connect');
}
return $this;
}
So would a try/catch be needed if errors are handled within the class?
Thanks

When an exception is thrown, the code following it will not be executed, and PHP will try to find the matching "catch" block.
If an exception is not caught, a fatal error will be issued with an "Uncaught Exception" message.
Proper exception code should include:
Try - A function using an exception should be in a "try" block. If the exception does not trigger, the code will continue as normal. However if the exception triggers, an exception is "thrown"
Throw - This is how you trigger an exception. Each "throw" must have at least one "catch"
Catch - A "catch" block retrieves an exception and creates an object containing the exception information

The connect class throws exceptions that you need to catch and handle somewhere in your code. It is up to you where to handle it depending on your application design and requirements.
If you decided that you wanted to handle them in the performFtpOperation function, then your use of try...catch there is correct.
If you don't handle them in the performFtpOperation function, then they will bubble up to the code that calls the performFtpOperation function and you can catch & handle them there if you like using try...catch similar to how you did it here. Just remember that you need to catch them somewhere.

Well since you are throwing an exception from within your FTP code, then Yes.

You need to try catch if you work with exeptions, otherwise you generate fatal errors and your script/site will stop work at this point, so try/catch is a part of the exeption handling.
you can inform yourself about this in the php manual
http://php.net/manual/en/language.exceptions.php

Related

How can I find out all the errors that can possibly be thrown by a block of PHP code?

I want to know what errors can be thrown that I am not catching, for dynamic code - not static code. For example, my code may run without throwing any Exceptions for 10 years and then throw UncaughtException
I want to specifically (non-generically) catch every type of Exception that can be thrown by the methods I am using. How can I know what Exceptions MAY be thrown by these methods?
I want to non-generically catch every type of error that can possibly be thrown for a section of PHP code.
Examples of exceptions that may be thrown:
PDOException
ExpiredException
Now I have this around everything:
try{
...
}catch(Exception $e){
...
}
I'd like to replace it with something like this:
try{
...
}catch(PDOException $e){
...
}catch(ExpiredException $e){
...
}catch(Exception $e){
...
}
I'd like to be confident that I am catching all different kinds of Exception that can be thrown by the methods in the section of code
And if I catch all Exceptions individually, will it be safe to remove this part?:
catch(Exception $e){
...
}
Or are there methods which will simply throw Exception?
My solution preference list (1 is the most-preferred solution):
1: A flag I can turn on that will cause php.exe to warn me about each and every possible type of Exception that is not specifically being caught
2: A way to individually check each method and see what errors can be thrown. Is the documentation the only way to check? or is there some IDE or PHP block that will tell me which Exceptions may be thrown by individual methods?
You can set callback function by using register_shutdown_function() which will call on every end of your php code execution. In this callback function you can check whether any error occurs or not using error_get_last().
For Example:
// Register shutdown function
register_shutdown_function("shutdownTracker");
// Define all error types you want to catch and handle
define('E_FATAL', E_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR);
function shutdownTracker() {
$error = error_get_last(); // This will return empty if no error occurs while executing php code.
if(!empty($error) && ($error['type'] & E_FATAL)) {
// Write your code here to handle you error
}
}
Note: You should include this code on top of your code.
Well if you are talking exceptions, you already have the answer
try{
...
}catch(PDOException $e){
...
}catch(ExpiredException $e){
...
}catch(Exception $e){
echo get_class($e); // get's the class of unrecorded exceptions.
//catches any exceptions missed by the above
}
Now if you are talking about "errors" you can do is use a custom error handler
if(!function_exists('myErrorHandler')){
function myErrorHandler($severity, $message, $file = 'UNKNOWN', $line = 'UNKNOWN')
{
throw new ErrorException(
$message,
1,
$severity,
$file,
$line
);
}
set_error_handler('myErrorHandler');
}
What it does is convert all PHP errors to exceptions or rather to ErrorExceptoins.
Now you can go a step further and use these other two functions.
register_shutdown_function
AND
set_exception_handler
I'm actually working on porting what I use to it's own stand alone github project. Right after I finish my eJinn project, which you may be interested in. eJinn is designed to build exception classes based off a config file, so you can have one error per exception file and unique error codes in a project.
You can catch all exceptions without even call try.
function hello($e)
{
if ($e instanceof PDOException){
echo "something".
}else echo $e->getMessage();
}
set_exception_handler('hello');
this should catch all exceptions.
UPDATE 2
I've edited the code so you know what exceptions will be thrown using get_class();
class mycustomException extends Exception{} // making new exception
function hello($e)
{
if ($e instanceof PDOException){ // exception already known
echo "something";
}else{
echo get_class($e); // get exception name.
}
}
set_exception_handler('hello');
throw new mycustomException(); // throw exception that we made.

Custom messages for php exception handling

I'm using an external file with $errmsg array for displaying errors, like:
'app_init' => 'Cannot initialize application',
Using conditionals, I call the function to display the message on failure:
if(!$condition)
{
$arraywithmessages->functionforfiltering($err,'app_init',$aim);
}
...where $err is the array of messages, and $aim is predefined method of publishing error (e-mail, view, etc...)
Now I'd like to make use of Exception Handling, but I don't know where to start. Can anyone help? This doesn't seem to work:
try {
if (!$condition) {
throw new Exception('app_init');
}
// continue
} catch (Exception $e) {
$arraywithmessages->functionforfiltering($err,$e->getMessage(),$aim);
}
I don't know exactly what you want to achive but you should remember that try, catch should be used wisely. It should be used for Exceptional situations only. If you don't use them in that way then it's GOTO code.
About exceptions, remmeber that you can extend Exception class and make your own exceptions and catch them in multiple catch blocks, there is also finally block.
About the constructor of Exception. It has the second param which is $code you can use it to show proper message.
$err = array(0x1 => 'my error app init');
try {
if (!$condition) {
throw new Exception('app_init', 0x1);
}
// continue
} catch (Exception $e) {
echo $err[$e->getCode()]; //it shouldn't be only echo it should do some tries to fix the code close streams etc. not just echo.
}
There is also function
set_exception_handler(). which:
Sets the default exception handler if an exception is not caught within a try/catch block. Execution will stop after the exception_handler is called.
Consider using it. There are a lot of things that can be found in manual.

Detect if an exception has been thrown manually without using a custom exception class

I got a try-catch block in my php application like this:
try {
if ($userForgotToEnterField) {
throw new Exception('You need to fill in your name!');
}
...
doDifferentThingsThatCanThrowExceptions();
...
} catch (ExpectedException $e) {
$template->setError('A database error occured.');
} catch (Exception $e) {
$template->setError($e->getMessage());
}
I would like to only output $e->getMessage() for the exceptions I have manually thrown with a custom error text and not the ones that have been thrown by the other code as these might contain sensitive information or very technical info that the user should not see.
Is it possible to differentiate from a manually thrown exception and a random exception thrown by some method without using a custom exception class?
I agree that it might be best to just write your own exceptions. If for whatever reason you don't want to, you could set a custom error message and a custom error code (the second parameter for the Exception constructor.) Check each thrown Exception if the error code is yours, and display only those:
public Exception::__construct() ([ string $message = "" [,int $code = 0[, Exception $previous = NULL ]]] )
and then use getCode
I've thought about this a bit and I'd say that what you are doing DOES call for a custom exception class. If you want to get around it (which in the end is going to be more confusing), you would basically create a global (or same-scope) variable that all exceptions can modify, and in your throw block flag it.
$threwCustomException = false;
try {
if ($userForgotToEnterField) {
throw new Exception('You need to fill in your name!');
$threwCustomException = true;
}
...
doDifferentThingsThatCanThrowExceptions();
...
} catch (ExpectedException $e) {
$template->setError('A database error occured.');
} catch (Exception $e) {
if($threwCustomException){
//Whatever custom exception handling you wanted here....
}
$template->setError($e->getMessage());
}
That's the best I can think of. However, this is a bad idea, and it's the whole reason you are allowed to create your own exception classes. I know you're not looking for this answer, but since you look like you're trying not to create a TON of extra code, I would just extend Exception to "CustomException" or some other name specific to your project, and throw that for all cases, and handle it that way.
Hope that helps.

Include $_POST, $_GET, $_SERVER values in PHP Error Log

I have code like this
try {
header("Location: http://www.google.com\n-abc");
}
catch (Exception $e) {
error_log(print_r($_POST, true));
error_log(print_r($_GET, true));
error_log(print_r($_SERVER, true));
}
Without the try {} catch {} block, I can see the POST, GET and SERVER variables in my error_log, but with the try {} catch {} block, I only see the default PHP error.
Is there a way to show the POST, GET, and SERVER variables in a try {} catch {} block?
Is there a way to have PHP include POST, GET, and SERVER variables for ALL errors that get logged to file and not just wherever I have added error_log(print_r($_POST, true)); ....?
try/catch is for when you want to throw an exception to prevent php fatal errors from killing the page or to make debugging easier, generally speaking. This is how you would use a try/catch:
try {
if($a === true)
{
header("Location: http://www.google.com\n-abc");
}
else
{
throw new Exception('$a was not true');
}
}
catch (Exception $e) {
error_log(print_r($_POST, true));
error_log(print_r($_GET, true));
error_log(print_r($_SERVER, true));
echo $e->getMessage(); // $a was not true
}
The reason you don't see your error logs in the catch block in your example is because you never threw an exception so PHP will never look inside that catch block to log your variables.
If you simply want to get your example to work you'd just throw an exception to get PHP in that catch block:
try
{
throw new Exception('redirecting...');
}
catch (Exception $e)
{
error_log(print_r($_POST, true));
error_log(print_r($_GET, true));
error_log(print_r($_SERVER, true));
header("Location: http://www.google.com\n-abc");
}
That's just silly though :)
But default PHP functions like header will not throw exceptions.
If you want them to throw exceptions you will need to set the error handler to use ErrorException:
function exception_error_handler($errno, $errstr, $errfile, $errline ) {
throw new ErrorException($errstr, $errno, 0, $errfile, $errline);
}
set_error_handler("exception_error_handler");
I think you have a few questions/issues here.
First, a try/catch block is used for Exceptions. The catch {} code is only executed if a Exception of the type specified is thrown.
Second, the header() function does not throw exceptions. Instead it just generates a PHP error directly.
Thirdly, to log those variables for all errors take a look at set_error_handler(), which should also take care of the above, second issue.
try/catch would only work if you're using an object that actually throws exception. header() is NOT an object and will NEVER throw an exception. Like I said in my answer to your previous version of this question, you need to set up a custom error handler.
That's how try/catch is supposed to work: the catch block executes when an exception is thrown in the try block (and only in that case).
The header() function may generate a warning if headers are already sent, but it will never throw an exception.
Answering your questions:
Your catch block is just fine but you need code that can actually throw exceptions (typically object-oriented code, but not necessarily). However, you can configure PHP to convert regular errors into exceptions if you use set_error_handler() to create a custom error handler and use throw inside of it.
Same as above: set_error_handler() and set_exception_handler().
Sounds like you want to have some extra information output to your log when an error is thrown. You should check out custom error handling in PHP. You can define specific ways to handle errors in your scripts and add functionality that is not there by default.PHP Set error handler

try catch vs if else in PDO and some other things

There is this question that I found:
What is the advantage of using try {} catch {} versus if {} else {}
If you can add anything to it then please do as I am new to PDO, also what does this mean;
$dbc->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
On the MySQL website it says "ensures the creation of exceptions rather than errors" but I do not understand this, can anyone please elaborate on it please.
Exceptions are catchable via try/catch and are classes with properties, while proceedural errors cannot and are not. Proceedural errors are instead handled by PHP's native error handling.
You can observe the behavior difference by manually triggering them.
to throw an Exception:
throw new Exception();
to trigger a proceedural error:
trigger_error($message, U_USER_ERROR);
Exceptions are bassically the OO way of error handling. Find more information about Exceptions here: http://php.net/manual/en/language.exceptions.php
Well, they are pretty similar. In PHP native error handling you can trow your own errors with trigger_error($error, [$level]) as you can throw your own exceptions with throw new MyException($error); you can set a default error handler with set_error_handler() which will manage all PHP error (except parsing) your own way as you can set a default exception handler with set_exception_handler(). Both PHP native errors and exceptions are automatically triggered/thrown somehow: PHP native errors compiling the script, exceptions if you are using specific items such as (PDO) or something.
Now let's try the same code with different approaches:
With PHP native errors you can do things such as:
$db = new Database();
if ($db === NULL) { trigger_error("Cannot connect to the database", E_USER_ERROR); }
$result = $db->query("UPDATE charlieiscool SET iloveunicorns = 1 WHERE userid = 1");
if (!$result) { trigger_error("Error updating table", E_USER_ERROR); }
$file = 'log.php';
if (!file_exists($file) or !file_get_contents($file)) { trigger_error("$file not found", E_USER_ERROR); }
require($file);
I think this does not really need any explanation. If an error is triggered, the entire script is skipped and you see the error. There are no more things you can do; you could set E_USER_ERROR or E_USER_NOTICE or E_USER_WARNING and handle them differently, but you have not that big choice. Now take a look at a possible OOP approach with try{} catch() {} blocks:
try {
$db = new Database();
if (!$db) { throw new DBEx("Cannot connect to the database"); }
$result = $db->query("UPDATE charlieiscool SET iloveunicorns = 1 WHERE userid = 1");
if (!$result) { throw new QueryEx("Query failed"); }
} catch (PDOException $e) {
echo $e->getMessage();
} catch (DBEx $e) {
$e->customFunction();
} catch (QueryEx) {
$e->customFunctionForQuery();
}
try {
$file = 'log.php';
if (!file_exists($file) or !file_get_contents($file)) { throw new FileEx("$file does not exists"); }
require($file);
} catch (FileEx) {
$e->fileGenerate();
$e->logError();
}
The main difference is that if the first try{} block throw an exception the second try{} will be executed any way. In fact if an exception is thrown, only the rest of the script inside that try{} block will be skipped.
Another difference (the one i love most) is that you can create several classes (extending mains Exception or PDOException or others) and customize very much your error handling behavior. You have unlimited possibilities to customize your classes, adding functions, editing already existing ones. You can add specific function (such as $e->fileGenerate();) and call them inside the catch() {} block where needed.
Notice also that if you want your entire script to stop if an error occurred, means that that error needs trigger_error(); instead if you want that an error only stops a specific block of code related to that error then it's time for try and catch.
You should not use one replacing the other, you should use one beside the other evaluating each errors as it is.
By the way PDO::setAttribute() change default values and options in your database handler. You can for example change your default fetch (used in PDOStatement::fetch()) with $dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);.
References:
PDO::setAttribute()
set_error_handler()
set_exception_handler()
Exceptions
Predefined exceptions

Categories