Error handling in my database class: Perhaps an Observer?

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

Post Reply
User avatar
Oren
DevNet Resident
Posts: 1640
Joined: Fri Apr 07, 2006 5:13 am
Location: Israel

Error handling in my database class: Perhaps an Observer?

Post by Oren »

I'm currently working on my database class. My constructor takes 4 arguments ($db_host, $db_username, $db_password, $db_name). I want it so when one or more arguments are missing an exception will be thrown and the missing arguments will be printed out.
For example, when $db_password and $db_name will be missing, an error like this will be printed:

Some information is missing (db_password, db_name)

Here is how I did it at first - this is the beginning of my constructor:

Code: Select all

public function __construct($db_host = null, $db_username = null, $db_password = null, $db_name = null)
{
	/* First, we make sure that all the required settings exist */


	/* Create an array from the arguments supplied to the constructor */

	$db_info_array = compact('db_host', 'db_username', 'db_password', 'db_name');


	/* Now we filter all the elements which are NOT null - so we are left with an array
	   which holds only the missing arguments */

	$db_info_array = array_filter($db_info_array, 'is_null');


	/* If one or more arguments were missing, the next 'if' will execute */

	if (count($db_info_array) !== 0)
	{
		/* Create an array from the keys of '$db_info_array' */

		$missing_info = array_keys($db_info_array);


		/* Converting it to a list of the missing settings separated by commas */

		$missing_info = implode(', ', $missing_info);



		/* Security... */

		unset($db_host, $db_username, $db_password, $db_name, $db_info_array);



		throw new exception('Some information is missing (' . $missing_info . ')');
	}



	/* If we reached here, all the required settings were found and therefore we try
	   to establish a connection */

	//...
}
But the I thought to myself: "Damn, all this error handling is over the scope of this class".
So I thought about replacing the current error handling part (as in the above code) with this:

Code: Select all

public function __construct($db_host = null, $db_username = null, $db_password = null, $db_name = null)
{
	if (func_num_args() !== 4)
	{
		// Don't know what to put here yet
	}

	//...
}
Now what should I put there? I'm new to design patterns, is this an Observer scenario? (thanks d11wtq :wink:)
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

The only way to get an observer working inside the constructor would be to pass the observer as an argument to the constructor, rather than loading it later.

Using an observer for error handling does provide flexibility though. Your classes only needs to know an error was generated, it need not worry what the practical implication of the error is.

You'd just trigger the error like:

Code: Select all

if (func_num_args() !== 4)
        {
                $this->errorMsg('4 arguments were expected but not seen');
        }
And the errorMsg() method might just look like:

Code: Select all

function errorMsg($error)
{
    foreach ($this->observers as $o)
    {
        $o->setError($error);
    }
}
If the above is PHP4 code you'd want to make sure you're working on the original objects and not a copy, thus using the keys from the loop to access the objects at their original location from the observers container.
User avatar
Weirdan
Moderator
Posts: 5978
Joined: Mon Nov 03, 2003 6:13 pm
Location: Odessa, Ukraine

Post by Weirdan »

what about this?

Code: Select all

if (func_num_args() !== 4) {
            throw new exception('Required argument is missing, expected (db_host, db_username,db_password, db_name)');
        }
Or just leave out the default values and let the php do the job for you.
User avatar
Oren
DevNet Resident
Posts: 1640
Joined: Fri Apr 07, 2006 5:13 am
Location: Israel

Post by Oren »

d11wtq wrote:You'd just trigger the error like:
I know how to do it (I've read your article :D), that's not the question. The question was: An Observer is the right solution here?
d11wtq wrote:If the above is PHP4 code
Does it look like PHP 4? Don't you see the __construct()? :P
Weirdan wrote:what about this?

Code: Select all

if (func_num_args() !== 4) {
            throw new exception('Required argument is missing, expected (db_host, db_username,db_password, db_name)');
        }
I guess you are right, this would be the fastest solution since it does not check which argumets were missing. Now, when I think about it more, printing out the missing arguments will not help that much anyway.

Thanks guys :D
User avatar
BDKR
DevNet Resident
Posts: 1207
Joined: Sat Jun 08, 2002 1:24 pm
Location: Florida
Contact:

Post by BDKR »

d11wtq wrote:

Code: Select all

function errorMsg($error)
{
    foreach ($this->observers as $o)
    {
        $o->setError($error);
    }
}
Hmmmm.......???? So then all observers have a setError() method? Or is setError() just a "setter" and the actual processing or display of the error is handled by a different method or object?

Observers are certianly cool but this doesn't seem right. What's wrong with some good old message passing to an error object that the db class is aware of? The db can hold a referrence to it as a member variable then just do ...

Code: Select all

$this->errorObject->processError('Something blew up holmes!');
Perhaps the constructor could look like ...

Code: Select all

function dbClass($arg1, $arg2, $arg3, &$error)
    { 
    /* Do something with the $args */
    $this->errorObject=$error;
    /* Do something constructive */
    }
I hope none of that sounds like it's way out in space. :oops:

Cheers,
BDKR
User avatar
Oren
DevNet Resident
Posts: 1640
Joined: Fri Apr 07, 2006 5:13 am
Location: Israel

Post by Oren »

BDKR wrote:Hmmmm.......???? So then all observers have a setError() method? Or is setError() just a "setter" and the actual processing or display of the error is handled by a different method or object?
Yes, all Observers have a setError() method.
For more information about the Observer read this: http://phpbook.quantum-star.com/doku.ph ... e_observer
Yossarian
Forum Contributor
Posts: 101
Joined: Fri Jun 30, 2006 4:43 am

Post by Yossarian »

What kind of stymies me is that I want to make sure the calling script can detect the error and "degrade gracefully" with a nice helpful message.

I mean in an mvc environment, does your Observer force a View to appear with a nice helpful message?

I am fairly new to patterns myself.

It isnt a dbconn class, but does something similar - which includes dbconn

I decided to create 2 attributes $msg and $err. $err would be given things like missing args messages.

This was the only way I could figure out how to unit test it too -
assertPattern('/missing/',$this->err);

If $err contains anything the calling script knows to stop.

Code: Select all

$conn= new conn;

....

if($conn->err){
   //load a view containing that error message

}else{
//get on with it

}
However - like the original poster says - it feels my dbconn class is doing too much.
User avatar
feyd
Neighborhood Spidermoddy
Posts: 31559
Joined: Mon Mar 29, 2004 3:24 pm
Location: Bothell, Washington, USA

Post by feyd »

Oren wrote:
BDKR wrote:Hmmmm.......???? So then all observers have a setError() method? Or is setError() just a "setter" and the actual processing or display of the error is handled by a different method or object?
Yes, all Observers have a setError() method.
For more information about the Observer read this: http://phpbook.quantum-star.com/doku.ph ... e_observer
Since when has all Observers had a setError() method? Last I checked, the "standard" Observer needed only one method: Update(). The Observable would have three methods: Attach(), Detach(), and Notify().
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

In my example I just indicate that the observer contains a method the observable is aware of of. Not all observers have a setError() method, that would be silly. But in my example, the observers which get loaded do. Common practice is to name methods notify() in both the observer and the observable, but it's not so descriptive and needn't use those names if the observers loaded need only deal with a certain task.

Attach, detach, aka loadObserver() and removeObserver() (if you provided keys to do so). I don't think the names matter... it's just the concept of passing messages between loosely coupled objects that needs to be understood.
User avatar
Oren
DevNet Resident
Posts: 1640
Joined: Fri Apr 07, 2006 5:13 am
Location: Israel

Post by Oren »

feyd wrote:Since when has all Observers had a setError() method? Last I checked, the "standard" Observer needed only one method: Update(). The Observable would have three methods: Attach(), Detach(), and Notify().
d11wtq wrote:In my example I just indicate that the observer contains a method the observable is aware of of.
User avatar
BDKR
DevNet Resident
Posts: 1207
Joined: Sat Jun 08, 2002 1:24 pm
Location: Florida
Contact:

Post by BDKR »

d11wtq wrote: In my example I just indicate that the observer contains a method the observable is aware of of. Not all observers have a setError() method, that would be silly. But in my example, the observers which get loaded do. Common practice is to name methods notify() in both the observer and the observable, but it's not so descriptive and needn't use those names if the observers loaded need only deal with a certain task.

Attach, detach, aka loadObserver() and removeObserver() (if you provided keys to do so). I don't think the names matter... it's just the concept of passing messages between loosely coupled objects that needs to be understood.
Ahhh....., I see now. Ultimately, my response was guided by my practice. :D

Do I like this observer stuff? Not really, but once again, this is because of practice. However, the bit about ...
d11wtq wrote: ...passing messages between loosely coupled objects...
... is a key point here. In a library that I work with, it can't be said that the error object is loosely coupled.
:wink:

However.....
d11wtq wrote: In my example I just indicate that the observer contains a method the observable is aware of.
If this is the case, couldn't the mechanism used for notifying this particular observer be simplified and direct instead of looping through the array of
all of the observers and notifiying all of them?

Now having just asked that question, I can still see usage for Observers in a project as long as their scope isn't too broad. As stated, it
really can help get loosely coupled objects to pass messages amongst one another without either having to know the others interface.

Cheers,
BDKR
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: Error handling in my database class: Perhaps an Observer

Post by Christopher »

If the parameters are required and you want to throw an exception then I would just do:

Code: Select all

public function __construct($db_host, $db_username, $db_password, $db_name)
{
     if (! ($db_host && $db_username && $db_password && $db_name)) {
          throw new exception("Some information is missing ($db_host, $db_username, password, $db_name)");
     }
}
Or if you want to handle errors with by checking an isError() method, which I prefer, then:

Code: Select all

public function __construct($db_host, $db_username, $db_password, $db_name)
{
     if (! ($db_host && $db_username && $db_password && $db_name)) {
          $this->errMsg = "Some information is missing ($db_host, $db_username, password, $db_name)";
     }
}
(#10850)
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

~BDKR, I think observers only really start to become noticably useful when you have more than one respoding to messages at the same time. I can see how just using the one may seem pointless when you can just use tight coupling on the assumption that errors will always be given to a particular interface.
User avatar
BDKR
DevNet Resident
Posts: 1207
Joined: Sat Jun 08, 2002 1:24 pm
Location: Florida
Contact:

Post by BDKR »

d11wtq wrote:~BDKR, I think observers only really start to become noticably useful when you have more than one respoding to messages at the same time. I can see how just using the one may seem pointless when you can just use tight coupling on the assumption that errors will always be given to a particular interface.
100% agreed!! I was trying to get across that I can see how using Observers makes sense (in spite of my meandering) depending on the needs at hand. I just happened to be continuously developing my own lib of sorts so there is a good deal of close coupling involved. This is the point of view i'm speaking from.

Anyway, I see your point. :D
matthijs
DevNet Master
Posts: 3360
Joined: Thu Oct 06, 2005 3:57 pm

Post by matthijs »

BDKR, I think observers only really start to become noticably useful when you have more than one respoding to messages at the same time
That's why your example on the book site is pretty cool. For a login class it's quite realistic that at some point you not only want to throw an error but also want to log the errors (failed login attempts f.e.) in some way.

I can imagine that in the regular app you don't have to be notified of each failed attempt to connect to the db, isn't it? Or maybe you would...
Post Reply