Page 1 of 2

A "class" that only has one "instance"?

Posted: Thu Feb 24, 2005 9:21 pm
by The Monkey
I just recently purchased "Advanced PHP Programming" and found something very interesting; namely, you can call methods in classes without creating an instance of that class:

Code: Select all

class Test
{
    function foo()
    {
        return 'foo';
    }
}

echo Test::foo(); // echoes 'foo'
However, in my DB class, you would never need multiple instances of the class. It merely prepares sql statements, queries the database, and
increments the number of queries by one (for cool statistic stuff).

In PHP5, you can declare static variables in classes:

Code: Select all

class Test
{
    public static $num = 0;
}
In PHP4, you can simulate this with a function:

Code: Select all

class Test
{
    function static_num()
    {
        static $num = 0;
        return ++$num;
    }
}
And then call Test::static_num();

You could do the same for query results, too; with a function like result() storing a static $result.

The reason I'm bringing all of this up, is because it appears to me that I could use my DB class in this way, and then when my functions need to query the database, I don't have to call global $db everytime.

Is there some reason this method of database querying would be a bad practice or has some hidden problem, that you guys see and I don't?

- Monkey

Posted: Thu Feb 24, 2005 9:33 pm
by timvw
if that is what you want i don't see a reason why you shouldn't use it....

if you want more info: just do a websearch for singleton pattern..


sometimes i think "static" as in one instance for the whole environment is somewhat silly in php because for each page/script a new environment is set up.

but static as a mechanism to have a variable that maintains it value (meaning: if the function is called for the second time, it won't be initialised again) can be a helpful....

Posted: Thu Feb 24, 2005 9:39 pm
by feyd
I'd suggest a singleton factory too.

Posted: Thu Feb 24, 2005 9:52 pm
by The Monkey
Oh. I looked it up in the "Advanced PHP Programming" index, and there it was. Page 56-57 discusses Singletons.

Thanks!

Posted: Thu Feb 24, 2005 9:53 pm
by smpdawg
Singletons/static classes can be used for all sorts of cool and useful things. I use static classes as containers for variables. This frees me from having globals and I can have different classes representing different data.

However:
You could do the same for query results, too; with a function like result() storing a static $result.
My question would be how are you going to handle this single result? Are you suggesting that you would only have one result/recordset available at any time? Depending on your need it may be handy but there are many times that you would need multiple recordsets available.

Posted: Thu Feb 24, 2005 10:02 pm
by The Monkey
smpdawg wrote:My question would be how are you going to handle this single result? Are you suggesting that you would only have one result/recordset available at any time? Depending on your need it may be handy but there are many times that you would need multiple recordsets available.
That's interesting, I had not considered that. The "test code" I had written had 1 while loop... however, I now realize I could have been stuck if I needed multiple loops.

Posted: Thu Feb 24, 2005 10:15 pm
by smpdawg
The reason I brought that up is that I was modifying some code to use a DB abstraction layer. It turned out that the one that I have selected allowed for only one result at a time. It didn't seem like a problem until I had some code that ran a query and then went through some other functions and surprise one of them run a query and trashed my recordset. That is when I switched to ADODB.

But singletons or static classes - and they aren't the same BTW - are still very useful.

Posted: Thu Feb 24, 2005 10:30 pm
by The Monkey
Ah, I see what you mean. ADODB, however, brings back the old problem of requiring a global $db at the top of every function... which is what I'm (unnecessarily?) trying to avoid.

Posted: Thu Feb 24, 2005 10:32 pm
by feyd
you can use a singleton as a db handler.. and another class as the results processor.. or similar..

Posted: Thu Feb 24, 2005 10:45 pm
by smpdawg
The Monkey wrote:Ah, I see what you mean. ADODB, however, brings back the old problem of requiring a global $db at the top of every function... which is what I'm (unnecessarily?) trying to avoid.
I agree, that is why I use a static class to store those types of things.

I think that avoiding globals is not unecessary but instead is very helpful thing to do. If you start cluttering the namespace with globals it could become difficult to find variables that have inadverntly been named the same.

You also open the door for unmanaged access to the contents of the globals. It is certainly a lot easier to understand the origins of a variable if it has some kind of container. And since it is in a container, you can trap access to the variable in the event that you need to find the code that modified the contents of a variable. This is infinitely easier in PHP 5 since you can create an object that has overloaded get and set methods and you can put debugging code in there.

Plus if it is in a container, you have one object that you could stream to disk or DB if you wanted to save state data.

But I digress...

Posted: Fri Feb 25, 2005 9:21 am
by McGruff
See: The Registry.

Globals are evil. If you are trying to create an OOP design they'll drive a coach and horses right through it.

Posted: Fri Feb 25, 2005 9:51 am
by bg
Ok, so i started looking into this singleton stuff. From the example Ive seen, instead of each function needing to access the class having

Code: Select all

global $obj


it instead has

Code: Select all

$obj = Object::instance();
Is this the case, and if so, what benefit does this have? Here is the example I looked at.

Code: Select all

<?php
class Singleton &#123;
   /**
   * The singleton instance is stored here
   */
   static private $instance = false;

   private $text = 'Empty message';

   /**
   * Make the constructor private to prevent the class being
   * instantiated directly
   */
   private function __construct() &#123;&#125;

   /**
   * Use this static method to get a singleton instance
   */
   static function instance() &#123;
       if(!Singleton::$instance) &#123;
           Singleton::$instance = new Singleton();
       &#125;
       return Singleton::$instance;
   &#125;

   function setText($text) &#123;
       $this->text = $text;
   &#125;

   function getText() &#123;
       return $this->text;
   &#125;
&#125;

class Hello &#123;
   function __construct() &#123;
       $single = Singleton::instance();
       $single->setText('Hello World!');
   &#125;
&#125;

class Goodbye &#123;
   function __construct() &#123;
       $single = Singleton::instance();
       $single->setText('Goodbye World!');
   &#125;
&#125;

$single = Singleton::instance();

echo ( $single->getText().'<br />' );

$hello = new Hello();

echo ( $single->getText().'<br />' );

$hello = new Goodbye();

echo ( $single->getText().'<br />' );
?>

Posted: Fri Feb 25, 2005 10:08 am
by timvw
bgzee wrote:Ok, so i started looking into this singleton stuff. From the example Ive seen, instead of each function needing to access the class having

Code: Select all

global $obj


it instead has

Code: Select all

$obj = Object::instance();
Is this the case, and if so, what benefit does this have? Here is the example I looked at.
If you access $obj directly it is possible that $obj is still NULL.
And it is impossible to assign a valid class instance (=object) to it because the construtor is private...

So, with the static method instance you can test if $obj is still NULL, and in case it is, call the constructor (as this is a method in the same class, it can access the private methods..)

Now, if you take a singleton class, withouth the setText and getText you can easily extend it..... this way you don't to copy/paste the code for each singleton class you want to implement... (= taking advantage of oop)

Code: Select all

class BgzeeSingleton extends Singleton
{
      // only write your proper function....
}

$bgzee = BgzeeSingleton::Instance();
$bgzee->ProperFunction();

Posted: Fri Feb 25, 2005 10:27 am
by bg
timvw wrote:
bgzee wrote:Ok, so i started looking into this singleton stuff. From the example Ive seen, instead of each function needing to access the class having

Code: Select all

global $obj


it instead has

Code: Select all

$obj = Object::instance();
Is this the case, and if so, what benefit does this have? Here is the example I looked at.
If you access $obj directly it is possible that $obj is still NULL.
And it is impossible to assign a valid class instance (=object) to it because the construtor is private...

So, with the static method instance you can test if $obj is still NULL, and in case it is, call the constructor (as this is a method in the same class, it can access the private methods..)

Now, if you take a singleton class, withouth the setText and getText you can easily extend it..... this way you don't to copy/paste the code for each singleton class you want to implement... (= taking advantage of oop)

Code: Select all

class BgzeeSingleton extends Singleton
{
      // only write your proper function....
}

$bgzee = BgzeeSingleton::Instance();
$bgzee->ProperFunction();
Ahh, ok, that makes sense. What if the singleton requires parameters for the construct? For example I use a database object, and for the construct I pass the usual... host, user, pass, database. If i were to use the singleton method wouldnt I have to pass these parameters to the instance() function each time?

Posted: Fri Feb 25, 2005 10:30 am
by feyd
no. You set them once in the Singleton. They should be set via a set function.. ;)