What's the best practice to handle errors if using objects?
A) Before the method of object is called and not even getting to execute method if there's some error, or
B) Just pass parameters and perform error checking in method itself, returning error code or something.
Please pick your option and short description, why?
Thanks orlandu63, it is good practice, but what about non-fatal errors, such as user should provide a title for something, and he/she didn't?
class Sample {
var $err_no_title = 1;
function createNewRecord ($title) {
if (!$title) return $this->err_no_title;
}
}
Or use exceptions for these kind of errors also?
If you're using OO, you might as well use Exceptions. My answer is a mix of both A and B:
class DatabaseConnectionException extends Exception {}
class Database {
public function connect($user, $pass, $db) {
//Connection stuff.
if($baduser) {
throw new DatabaseConnectionException('Username (' . $user. ') is invalid.')
}
if($badpass) {
//''
}
}
}
$db = new Database;
try {
$db->connect($user, $pass, $db);
catch (DatabaseConnectionException $e) {
die('I cannot connect to the database:' . $e);
}
What are the advantages to this? I don't know, but it seems right.
You can read more on it on http://php.net/exceptions and google.
Regarding your second part,
First of all your example will treat it more of an error than a "warning" since you exit the function and thus don't create a record if you have no title. This shows that method B is flawed. So method A all the way.
To choose from options you offer it would be B, but don't use error codes and throw exceptions instead. All the logic (even validation of inputs) should be encapsulated in the function.
The reasons are:
The function may change and so may change requirements for inputs.
User of your function may not always know, what the inputs should be like.
You surely don't want to repeat the validation code everywhere you use the function.
Be careful though, as exceptions are raised by object oriented code only. For example this code does not fire an exception:
<?php
$number = $number / 0;
?>
Your example would be like:
<?php
class Sample {
function createNewRecord ($title) {
if (!$title) throw new Exception('Title required');
}
}
...
try {
$mysample->createNewRecord($title);
} catch ($ex) {
echo "Could not create record. Please try again. (Reason: $ex)";
}
...
?>
In the first place, this sort of thing should be validated in the user interface. So it would be A, but B needs to be there to. So final verdict would be: both.
Related
I've a question.
I need to handle the Mysql error (like duplicate key, foreign constraints...) for example:
$id=$db->insert ('user', $data);
if(!$id){
switch($db->getLastErrno()){
throw new Exception(... );
}
}
Here i use error number to select the right Exception.
But for the same error, what i've to do?
I think to use error string, for example:
if($db->getLastErrno()==1452 && strpos($db->getLastError(), "contraint name created on db")>-1){
throw new Exception(... );
}
But i don't know why, i think it's a little bit trash. Does anyone have other solutions?
Put the if statement inside the case. You don't need to repeat the error number test.
switch ($db->getLastErrno()) {
case 1452:
if (strpos($db->getLastError(), "constraint name created on db") !== false) {
throw new Exception(...);
}
break;
...
}
TL;DR:
My PHP-Exception only get caught, if i use a print-statement in the catch-block.
I am seeing some strange behaviour with a PHP try catch block. My PHP version is 7.0.14.
Here is a method that I've defined which simply explodes a string and stores the result in memory. If the exploded string doesn't have the expected amount of constituent parts, an Exception will be thrown.
public function importString($string) {
// separate the string with the delimiter.
$separated = explode($this->delimiter, $string);
// If there is a different number of segments to specified id's throw exception.
if (count($separated) != count($this->ids)) {
$class = static::class;
throw new \Exception("Invalid Pseudo ID '{$string}' for type '{$class}'.");
}
//store separated id strings
foreach($separated as $i => $item) {
$this->data[$this->ids[$i]] = $item;
}
}
This method is contained within a class called PseudoId from which the two classes below inherit.
Below is the code that calls the method defined above; the majority of the time I expect the imported string to be constructed from three different values (e.g. "one_two_three") but on occasion there can be strings with four components (e.g. "one_two_three_four"), therefore I first attempt to import the string into the object that expects the string to have three components, falling back to the object that expects four.
try {
//Added later for debug
throw new \Exception("error");
$productInfo = new PseudoIdFeedProduct(0, 0, 0);
$productInfo->importString($data['productId']);
} catch (\Exception $e) {
//Added later for debug
print "caught.";
$productInfo = new PseudoIdFeedProductIndividualBilling(0, 0, 0, 0);
$productInfo->importString($data['productId']);
}
// Added for debug
var_dump($productInfo);
Now here's the weird part: When passing in a string with four components, the Exception thrown in PseudoIdFeedProduct::importString() isn't caught. So for the sake of debugging I added an Exception to the top of the try block, calling the print function in the catch block as a check and it worked. So I removed the exception at the top of the try block, and it still worked. Slightly baffled, I removed the call to the print function and it stopped working...
Whether the thrown Exception is caught depends on whether the print function is called in the catch block, I added and removed it a couple of times to double check.
Clearly I don't want to have to call the print function here, what am I doing wrong here and how can I get this to work as expected?
I've read that exceptions shouldn't be used for directing the flow of your application but should be used to recover the application to a stable state when something "exceptional" happens, for example, when you fail to connect to a database.
An example of where an exception shouldn't be used would be a user providing an incorrect login. It wouldn't be an exception since it's expected that that will happen.
I'm not sure whether the following case is exceptional or not:
I'm currently designing a simple blog. A "post" is assigned to just one "category". In my posts table I have a category_id field with a foreign key constraint.
Now, I'm using Laravel so if I try to delete a category that currently has posts in it, I believe it should throw an \Illuminate\Database\QueryException because of the foreign key constraint. Therefore should I rely on this and write code like:
try {
$category->delete();
}
catch (\Illuminate\Database\QueryException $e) {
// Tell the user that they can't delete the category because there are posts assigned to it
}
or since I know how I want my blog to work, should I use:
if ($category->posts->isEmpty()) {
$category->delete();
}
else {
// Tell the user they can't delete...
}
Any advice would be appreciated. Thanks!
It is very opinion based, so i'll give you my opinion:
Exceptions are powerfull, because you can attach a lot of information with it - and you can send them "up the callstack" without having hundrets of methods checking the return value of any call and returning whatever to their own caller.
This allows you to easily handle an error at the desired layer in the callstack.
A Method should return, what is the result of the call (even if it's void). If the call fails for any reason, there should be no return value.
Errors should not be transported by returnvalues, but with exceptions.
Imagine a function doing db-queries: KeyAlreadyExistsException, InvalidSyntaxException and NullPointerException - most likely you want to handle this "errors" at very different parts in your code.
(One is a code-error, one is a query-error, one is a logical-error)
Example one, easy "handling":
try{
method1(1);
}catch (Exception $e){
//Handle all but NullpointerExceptions here.
}
---
method1($s){
try{
method2($s+2);
} catch (NullPointerException $e){
//only deal with NPEs here, others bubble up the call stack.
}
}
---
method2($s){
//Some Exception here.
}
Example two - you see the required "nesting", and the stack-depth is only 2 here.
$result = method1(1);
if ($result === 1){
//all good
}else{
//Handle all but NullpointerExceptions here.
}
---
method1($s){
$result = method2($s+2);
if ($result === 1){
return $result;
}else{
if ($result === "NullPointerException"){
//do something
}
}
method2($s){
//Exception here.
}
Especially for maintainance, Exceptions have huge advantages: If you add a new "Exception" - the worstcase will be an unhandled exception, but code execution will break.
If you add new "return errors", you need to make sure, that every Caller is aware of these new errors:
function getUsername($id){
// -1 = id not found
$name = doQuery(...);
if (id not found) return -1;
else return $name;
}
vs
function getUsername($id){
$name = doQuery(...);
if (id not found) throw new IdNotFoundException(...);
return $name;
}
Now consider the handling in both cases:
if (getUsername(4)=== -1) { //error } else { //use it }
vs
try{
$name = getUsername(4);
//use it
}catch (IdNotFoundException $e){
//error
}
And now, you add the return code -2: First way would assume the username to be -2, until the error code is implemented. Second way (Another Exception) would cause the execution to stop with an unhandled exception somewhere way up in the callstack.
Dealing with return values (of any kind) for error-transportation is error prone and errors might vanish somewhere, turning into a "wrong" interpreted result.
Using exceptions is safer: You either have a return value to use, or a (handled or unhandled) exception, but no "wrong values" due to autocasts etc.
I have the following code which results sometimes in a silent failure:
public function updateCoreGameTableIfNecessary($coreEm)
{
$game = $this->getCoreGameRecord($coreEm);
if (!$game) {
$game = new Game();
$game->setHomeSchool($this->getHomeSchool()->getCoreSchool($coreEm));
$game->setDatetime($this->getDatetime()->format('Y-m-d H:i:s'));
$game->setDate($this->getDatetime()->getTimestamp());
$game->setTime($this->getDatetime()->format('H:i:s'));
$game->setSport($coreEm->getRepository('VNNCoreBundle:Sport')->findOneByName($this->getSport()->getName()));
$game->setSeason($coreEm->getRepository('VNNCoreBundle:Season')->findCurrent());
$game->setEventType(strtolower($this->getEventType()->getName()));
$game->setMeetName($this->getMeetName());
$game->setRemoteUnique(md5(rand(0, 100000)));
$game->setNotes($this->getRecap());
$game->setHomeConfId(0); // This field is no longer used, so value doesn't matter.
$game->setAwayConfId(0); // This field is no longer used, so value doesn't matter.
$game->setConfStatus(''); // This field is going away as well.
}
if ($this->getEventType()->getName() == 'Game') {
$game->setHomeScore($this->getHomeScore());
$game->setAwayScore($this->getAwayScore());
$game->setAwaySchool($this->getAwaySchool()->getCoreSchool($coreEm));
} else {
$game->setPlace($this->getPlace());
$game->setPoints($this->getHomeScore());
}
$game->setOwnerId($this->getUser()->getSchool()->getCoreSchool($coreEm)->getId());
$coreEm->persist($game);
$coreEm->flush();
return $game->getId();
}
It always starts with a $this that's already saved. For certain instances of $this (i.e. certain records in the database), $game won't get saved. I won't get an error or anything like that. It will just fail silently.
Any suggestions for debugging? I guess I'll try to figure out what's different about those certain records, but it seems like an insert should never silently fail, for any reason.
In my PHP layer I'm receiving error codes as strings ("NOT_FOUND", "EXPIRED", etc). It's a small list of possible strings, perhaps a dozen.
What's the most efficient way of dealing with these? Using switch-case against string constants stored in a class, or should I parse them to numbers (or something) first? Or is PHP smart enough so it doesn't really matter?
You might want to consider using constants? Let's say you have a class Error and define all error codes there like this:
class Error {
const NOT_FOUND = 0;
const EXPIRED = 1;
// and so forth
}
And then you can use them in your code by accessing them like Error::NOT_FOUND and a switch statement wouldn't need to compare strings but has plain ints without downgrading readability.
It really depends on what you want to do with the strings. Do you want to output error messages? Then instead of a case statement you could use a lookup table like this:
$messages = array(
'NOT_FOUND' => 'The file was not found',
'EXPIRED' => 'The cookie expired'
// ETC
);
echo empty($messages[$error]) ? "Unknown error" : $messages[$error];
With PHP 5.3 you could also store code in the array to handle the error situations:
$handlers = array(
'NOT_FOUND' => function() { /* Error handling code here */ },
'EXPIRED' => function() { /* Other error handling code */ }
);
if(!empty($handlers[$error])) {
$handler = $handlers[$error];
$handler();
}
else {
echo "Could not handle error!"; die();
}
With a technique like this you avoid case statements that go over several pages.
With PHP < 5.3 you might look into call_user_func for dynamic dispatching of error handling functions.
Strings can't be recognised as class constants. But the answer on your question is that it doesnt really matter if you do it like this:
switch (className::{$errorCode}) { // $errorCode == name of the constant, like NOT_FOUND
// Cases here.
}