Any tips on how to handle business logic errors? I do not mean Exceptions.
For example, lest assume that i have a class:
<?php
class Reactor () { // business class
public function shutdown() {
if($date > '2 pm') {
// show error message to user
echo 'you can't shutdown before 2 pm.';
} else {
// error while trying to shutdown
throw new Exception('Oh my God, it is gonna blow!!');
}
}
}
?>
The real question is how to pass the error message to my views?
Exceptions are good for exceptional cases. I'm very close to add ErroMessage and ErrorCode attributes to the base business class and check it every time i call a business class method.
You're actually on the right track here. You can handle the exceptions in your ErrorController - a convention modeled in Zend, but in many other frameworks too. You can create your own if you're rolling it DIY.
This thread has a more Zend-centric method of handling, but you can use the ErrorController to actually render your view. Handle the input of the $e exception class and get the message from that.
Throwing exceptions from model/view/controller in a Zend Framework application
If you're deep in the DIY route, you can display it gracefully if you wrap your larger blocks in try/catch and test all instances of the exception class. For instance:
class Reactor () { // business class
public function shutdown() {
if($date > '2 pm') {
// show error message to user
echo "you can't shutdown before 2 pm.";
} else {
// error while trying to shutdown
throw new Exception('Oh my God, it is gonna blow!!');
}
}
}
//later, in the controller
$reactor = new Reactor();
try{
$reactor->shutdown('1pm');
} catch(Your_Custom_Exception $e){
//pass to view
$this->view($e->getMessage());
} catch(Exception $e){
// woops, serious error. do something useful
}
Exceptions are exactly what you need in this case. State validation (this is what you're doing) shall lead either to silence or an exception. You shall handle Model-thrown exceptions in your Controller, convert them to messages and pass them to View.
I think you should have something like this.
Use attributes to store data and error message. And i think it is illogical to generate error for if and else too
class Reactor{
public $date;
public $error;
public $errorstatus = false;
//Use property to store data and errors
public function shutdown() {
if($date > 2) {
$this->errorstatus = true;
$this->error['date'] = "You cannot shutdown before 2 pm";
} else
return true;
}
}
$reactor = new Reactor();
$reactor->data = 3;
$reactor->shutdown();
if($reactor->errorstatus){
echo $reactor->error['date'];
}
else{
echo "Its already two you can shutdown";
}
echo "<br/>";
$reactor->data = 1;
$reactor->shutdown();
if($reactor->errorstatus){
echo $reactor->error['date'];
}
else{
echo "Its already two you can shutdown";
}
[UPDATE]
public function shutdown() {
if($date > 2) {
$this->errorstatus = true;
$this->error['date'] = "You cannot shutdown before 2 pm";
} else
if($this->poweroff)
return true;
else
throw new Exception("ERROR WHILE SHUTTING DOWN"):
}
private function poweroff()
{
//if power off then return true
//else return false
}
Related
I don't understand how to properly create and return useful error messages with PHP to the web.
I have a class
class Foo {
const OK_IT_WORKED = 0;
const ERR_IT_FAILED = 1;
const ERR_IT_TIMED_OUT = 3;
public function fooItUp(){
if(itFooed)
return OK_IT_WORKED;
elseif(itFooedUp)
return ERR_IT_FAILED;
elseif(itFooedOut)
return ERR_IT_TIMED_OUT;
}
}
And another class that uses this class to do something useful, then return the result to the user. I am just wondering where I put the string value for all my error messages.
class Bar {
public function doFooeyThings(stuff){
$res = $myFoo->fooItUp();
// now i need to tell the user what happened, but they don't understand error codes
if($res === Foo::OK_IT_WORKED)
return 'string result here? seems wrong';
elseif ($res === Foo::ERR_IT_FAILED)
return Foo::ERR_IT_FAILED_STRING; // seems redundant?
elseif($res === Foo:ERR_IT_TIMED_OUT)
return $res; // return number and have an "enum" in the client (js) ?
}
}
You should avoid returning error states whenever possible. Use exceptions instead. If you've never used exceptions before you can read about them here
There multiple ways you can utilize exceptions in your example. You could create custom exceptions for every error or for every category of error. More on custom exceptions here or you could create an instance of the default Exception class supplying it the error messages as strings.
The code below follows the second approach:
class Foo {
const OK_IT_WORKED = 0;
const ERR_IT_FAILED = 1;
const ERR_IT_TIMED_OUT = 3;
public function fooItUp(){
if(itFooed)
return OK_IT_WORKED;
else if(itFooedUp)
throw new Exception("It failed")
else if(itFooedOut)
throw new Exception("Request timed out");
}
}
I'm sure you can think of some more elegant messages than the ones I used. Anyway, you can then go ahead and handle those exceptions on the caller method using try/catch blocks:
class Bar {
public function doFooeyThings(stuff){
try
{
$res = myFoo->fooItUp();
}
catch(Exception $e)
{
//do something with the error message
}
}
}
Whatever exception is thrown from fooItUp will be "caught" by the catch block and handled by your code.
Two things you should also consider are:
It's best not to show your users detailed information about errors because those information could be used by users with malicious intent
Ideally you should have some kind of global exception handling
One solution is to use exceptions in conjunction with set_exception_handler().
<?php
set_exception_handler(function($e) {
echo "Error encountered: {$e->getMessage()}";
});
class ErrorMessageTest
{
public function isOk()
{
echo "This works okay. ";
}
public function isNotOkay()
{
echo "This will not work. ";
throw new RuntimeException("Violets are red, roses are blue!! Wha!?!?");
}
}
$test = new ErrorMessageTest();
$test->isOk();
$test->isNotOkay();
The set_exception_handler() method takes a callable that will accept an exception as its parameter. This let's you provide your own logic for a thrown exception in the event it isn't caught in a try/catch.
Live Demo
See also: set_exception_handler() documentation
I have to develop an exception handler that should handle like 5 different type of exceptions. Let's call them simply Ex1, Ex2, Ex3...
I though of doing a single class called ExHandler which will be instantiated like this:
...
} catch (Ex1 $e) { $h = new ExHandler($e); $h->render(); }
catch (Ex2 $e) { $h = new ExHandler($e); $h->render(); }
catch (Ex3 $e) { $h = new ExHandler($e); $h->render(); }
...
And inside ExHandler manage each different Exception differently using $e instance of Ex1, $e instance of Ex2, $e instance of Ex3...
But It doesn't seems a very good practice to me. Is it good? Is there any other way of doing this?
Should I create an Ex1Handler, Ex2Handler, Ex3Handler...? My S.O.L.I.D spirit tells me something is just wrong here. What is it?
I need to note before I answer this, that procedural programmers will look at this and think it's dumb :) but I can live with that, this is assuming an OOP application with HTML templating that outputs after the output_buffer is cleaned.
I always create a try/catch block encompassing the majority of my code in one call usually at the point where I start requiring other files as well as starting an output_buffer whilst in development.
ob_start();
try {
switch($appPage) {
case('work'):
require_once('im_bored_at_work.php');
break;
case('home'):
require_once('im_a_little_less_bored_at_home.php');
break;
default:
require_once('on_the_fence.php');
}
} catch (Exception $e) {
// Handle exception caught and apply formatting
}
$devOut = ob_get_contents();
ob_end_flush();
To give an example how I would handle the multiple exceptions you need to catch with a custom class
class CustomExceptionHandler extends Exception {
private $msg;
private $code;
private $otherVars;
public function __construct($msg,$code=0,$otherDebugVar=null){
$this->msg = $msg != null ? $msg : "An unknown exception was thrown";
$this->code = $code;
$this->otherVars = $otherDebugVar;
parent::__construct($msg,$code);
}
public function getOtherVars() {
return $this->otherVars;
}
}
The idea is to just keep the custom information within the exception object, and when you rethrow the exception at the end of a try/catch block as a standard exception you include the formatted custom message, it shouldn't really matter now which Exception handler picked up the original exception as all the info you will need will come downstream and be caught in the original try / catch block.
class BasicTemplate {
private $template;
private $path;
private $contents;
public function __construct($template, $path) {
$this->template = $template;
$this->path = $path;
$this->buildTemplate();
}
private function buildTemplate() {
if ($contents = #file_get_contents($this->path . $this->template)) {
$this->contents = $contents;
} else {
$e = new CustomExceptionHandler("Message",2,$this->path . $this->template);
// Do whatever else you want to do with custom exception handling class
throw $e;
}
}
}
Now you need to catch your exception and rethrow it:
try {
$html = new BasicTemplate($temp,$path);
} catch {CustomExceptionHandler $e) {
throw new Exception("Message: {$e->getMessage()} Other Info: {$e->getOtherVars()}",$e->getCode());
}
That's the rough idea anyhow, hope it helps.
What are best way of error handling? This is what I came up with:
class test {
public static function Payment($orderid, $total) {
if (empty($orderid) && empty($total)) {
return array('status' => 'fail', 'error' => 'Missing Data');
}
}
}
I heard about Try/Exceptions but how to fit that into my code? If you could provide example that would be great!
If you use PHP 5, you can handle error with exception :
http://fr2.php.net/manual/en/class.exception.php
This way is cleaner than manual set exception message, because you have access to a try catch system and you can isolate exception handling
As mentioned, use Exceptions. Specific to your example, you throw an exception if some condition fails. Then when you envoke the method that can throw an exception, you wrap it with a try/catch handling block.
class test {
public static function Payment( $orderid, $total ) {
if (empty( $orderid ) && empty( $total )) {
throw new Exception('Missing Data');
}
}
}
try {
test::Payment("1", "2"); //should be fine
test::Payment(); //should throw exception
} catch (Exception $e){
echo $e;
//do other things if you need
}
You could use exceptions.
However, in the use case you've posted, simply doing the checks at the controller level should suffice.
I also think that explicitly checking the return type for array (on fail) is counter intuitive.
Here is how you might modify your code to use an exception. It also helps to document the circumstances under which the exception is thrown.
class test {
/**
* [method description]
* #throws Exception if the order ID or total is empty
*/
public static function Payment($orderid, $total) {
if (empty($orderid) && empty($total)) {
throw new Exception("fail: Missing Data");
}
}
}
You can also create your own exception class if you want to include extra data in the exception.
class MyException extends Exception{
public $status, $error;
public function __construct($status, $error){
parent::__construct("$status: $error");
$this->status = $status;
$this->error = $error;
}
}
I tend to lean towards throwing exceptions, and then using the try/catch mechanism to deal with the aftermath. The man page is here: http://php.net/manual/en/language.exceptions.php
The best practice is to use Exceptions.
http://php.net/manual/en/language.exceptions.php
Consider a function hierarchy, Function Four() Calls Three() which calls Two() Which again calls One() to do the job:
Function One($x) {
if(!is_int($x)) {
throw Exception("X must be integer");
}
// .......... Do the Job ................
}
Function Two($x) {
if(!is_int($x)) {
throw Exception("X must be integer");
} else {
One($x);
}
}
Function Three($x) {
if(!is_int($x)) {
throw Exception("X must be integer");
} else {
Two($x);
}
}
Function Four($x) {
if(!is_int($x)) {
throw Exception("X must be integer");
} else {
Three($x);
}
}
If I call four with a String value it will cause an Exception to occure.
Now consider following code with Exception in parent function only.
Function One($x) {
if(!is_int($x)) {
throw Exception("X must be integer");
}
// .......... Do the Job ................
}
Function Two($x) {
One($x);
}
Function Three($x) {
Two($x);
}
Function Four($x) {
Three($x);
}
Here, I call Four() and pass a string, it will also cause an Exception to occure.
So which one is the best practice and why?
When I start writing code I end up writing a lot of exception handling, plz help.
If the functionality in function one needs $x and that is the only function that uses $x you can throw the exception only in function one. I assume function two, three and four will also do other things (otherwise they are useless). In that case you should check the value also in those functions. If they do not already use $x they may do in the future. In that case it is easy to forget to check the $x value and a bug is born.
IME it's good practice to fail as close to the problem as possible. That being said, I think option 1 is the way to go. This makes it so that when the exception occurs, you have confidence that it was the call to Four that was the problem and you can debug from there. Option 2 is easy but you don't know if the problem lies in Four, Three, Two or One. As your software grows in complexity so will your time debugging.
an alternative, i would know the trace and you can use as
Function One($x) {
if(!is_int($x)) {
throw Exception("X must be integer");
}
// .......... Do the Job ................
}
Function Two($x) {
try
{
One($x);
}
catch(Exception $e)
{
throw $e;
}
}
Function Three($x) {
try
{
Two($x);
}
catch(Exception $e)
{
throw $e;
}
}
Function Four($x) {
try
{
Three($x);
}
catch(Exception $e)
{
throw $e;
}
}
in this case you can know where is the error start, and only 1 is_int check.
I think it depends largely on what the functions are meant to do.
If the value of x is critical to the function, then the exception should be handled in that function. If it is just used for passing parameters, then you can let it slip through to the last function.
I am not sure of how the engine evaluates the function processing, but mostly it will push its contents onto the stack and then make the necessary jump, which in turn causes delay, so better to incorporate the exception handling then and there, when the values are generated, rather than letting it flow uselessly till it is being used just to save useless processing time.
Generally an exception means you have wasteful computation. So model 1 will make sure you don't do so.
Server Processing is precious to all... :)
go here and you may find the answer:
I'm writing a web application (PHP) for my friend and have decided to use my limited OOP training from Java.
My question is what is the best way to note in my class/application that specific critical things failed without actually breaking my page.
My problem is I have an Object "SummerCamper" which takes a camper_id as it's argument to load all of the necessary data into the object from the database. Say someone specifies a camper_id in the query string that does not exist, I pass it to my objects constructor and the load fails. I don't currently see a way for me to just return false from the constructor.
I have read I could possibly do this with Exceptions, throwing an exception if no records are found in the database or if some sort of validation fails on input of the camper_id from the application etc.
However, I have not really found a great way to alert my program that the Object Load has failed. I tried returning false from within the CATCH but the Object still persists in my php page. I do understand I could put a variable $is_valid = false if the load fails and then check the Object using a get method but I think there may be better ways.
What is the best way of achieving the essential termination of an object if a load fails? Should I load data into the object from outside the constructor? Is there some sort of design pattern that I should look into?
Any help would be appreciated.
function __construct($camper_id){
try{
$query = "SELECT * FROM campers WHERE camper_id = $camper_id";
$getResults = mysql_query($query);
$records = mysql_num_rows($getResults);
if ($records != 1) {
throw new Exception('Camper ID not Found.');
}
while($row = mysql_fetch_array($getResults))
{
$this->camper_id = $row['camper_id'];
$this->first_name = $row['first_name'];
$this->last_name = $row['last_name'];
$this->grade = $row['grade'];
$this->camper_age = $row['camper_age'];
$this->camper_gender = $row['gender'];
$this->return_camper = $row['return_camper'];
}
}
catch(Exception $e){
return false;
}
}
A constructor in PHP will always return void. This
public function __construct()
{
return FALSE;
}
will not work. Throwing an Exception in the constructor
public function __construct($camperId)
{
if($camperId === 1) {
throw new Exception('ID 1 is not in database');
}
}
would terminate script execution unless you catch it somewhere
try {
$camper = new SummerCamper(1);
} catch(Exception $e) {
$camper = FALSE;
}
You could move the above code into a static method of SummerCamper to create instances of it instead of using the new keyword (which is common in Java I heard)
class SummerCamper
{
protected function __construct($camperId)
{
if($camperId === 1) {
throw new Exception('ID 1 is not in database');
}
}
public static function create($camperId)
{
$camper = FALSE;
try {
$camper = new self($camperId);
} catch(Exception $e) {
// uncomment if you want PHP to raise a Notice about it
// trigger_error($e->getMessage(), E_USER_NOTICE);
}
return $camper;
}
}
This way you could do
$camper = SummerCamper::create(1);
and get FALSE in $camper when the $camper_id does not exist. Since statics are considered harmful, you might want to use a Factory instead.
Another option would be to decouple the database access from the SummerCamper altogether. Basically, SummerCamper is an Entity that should only be concerned about SummerCamper things. If you give it knowledge how to persist itself, you are effectively creating an ActiveRecord or RowDataGateway. You could go with a DataMapper approach:
class SummerCamperMapper
{
public function findById($id)
{
$camper = FALSE;
$data = $this->dbAdapter->query('SELECT id, name FROM campers where ?', $id);
if($data) {
$camper = new SummerCamper($data);
}
return $camper;
}
}
and your Entity
class SummerCamper
{
protected $id;
public function __construct(array $data)
{
$this->id = data['id'];
// other assignments
}
}
DataMapper is somewhat more complicated but it gives you decoupled code which is more maintainable and flexible in the end. Have a look around SO, there is a number of questions on these topics.
To add to the others' answers, keep in mind that you can throw different types of exceptions from a single method and handle them each differently:
try {
$camper = new SummerCamper($camper_id);
} catch (NoRecordsException $e) {
// handle no records
} catch (InvalidDataException $e) {
// handle invalid data
}
Throwing an exception from the constructor is probably the right approach. You can catch this in an appropriate place, and take the necessary action (e.g. display an error page). Since you didn't show any code, it's not clear where you were catching your exception or why that didn't seem to work.
try {
$camper = new SummerCamper($id);
$camper->display();
} catch (NonexistentCamper $ex) {
handleFailure($ex);
}