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

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

The Monkey
Forum Contributor
Posts: 168
Joined: Tue Mar 09, 2004 9:05 am
Location: Arkansas, USA

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

Post 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
timvw
DevNet Master
Posts: 4897
Joined: Mon Jan 19, 2004 11:11 pm
Location: Leuven, Belgium

Post 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....
User avatar
feyd
Neighborhood Spidermoddy
Posts: 31559
Joined: Mon Mar 29, 2004 3:24 pm
Location: Bothell, Washington, USA

Post by feyd »

I'd suggest a singleton factory too.
The Monkey
Forum Contributor
Posts: 168
Joined: Tue Mar 09, 2004 9:05 am
Location: Arkansas, USA

Post by The Monkey »

Oh. I looked it up in the "Advanced PHP Programming" index, and there it was. Page 56-57 discusses Singletons.

Thanks!
User avatar
smpdawg
Forum Contributor
Posts: 292
Joined: Thu Jan 27, 2005 3:10 pm
Location: Houston, TX
Contact:

Post 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.
The Monkey
Forum Contributor
Posts: 168
Joined: Tue Mar 09, 2004 9:05 am
Location: Arkansas, USA

Post 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.
User avatar
smpdawg
Forum Contributor
Posts: 292
Joined: Thu Jan 27, 2005 3:10 pm
Location: Houston, TX
Contact:

Post 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.
The Monkey
Forum Contributor
Posts: 168
Joined: Tue Mar 09, 2004 9:05 am
Location: Arkansas, USA

Post 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.
User avatar
feyd
Neighborhood Spidermoddy
Posts: 31559
Joined: Mon Mar 29, 2004 3:24 pm
Location: Bothell, Washington, USA

Post by feyd »

you can use a singleton as a db handler.. and another class as the results processor.. or similar..
User avatar
smpdawg
Forum Contributor
Posts: 292
Joined: Thu Jan 27, 2005 3:10 pm
Location: Houston, TX
Contact:

Post 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...
McGruff
DevNet Master
Posts: 2893
Joined: Thu Jan 30, 2003 8:26 pm
Location: Glasgow, Scotland

Post 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.
bg
Forum Contributor
Posts: 157
Joined: Fri Sep 12, 2003 11:01 am

Post 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 />' );
?>
timvw
DevNet Master
Posts: 4897
Joined: Mon Jan 19, 2004 11:11 pm
Location: Leuven, Belgium

Post 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();
bg
Forum Contributor
Posts: 157
Joined: Fri Sep 12, 2003 11:01 am

Post 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?
User avatar
feyd
Neighborhood Spidermoddy
Posts: 31559
Joined: Mon Mar 29, 2004 3:24 pm
Location: Bothell, Washington, USA

Post by feyd »

no. You set them once in the Singleton. They should be set via a set function.. ;)
Post Reply