Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 484
  • Last Modified:

Singleton in PHP not really a Singleton?

Let's say that I have the following singleton class:

==========
<?php
class Singleton
{

      private static $instance;

      private function __construct(){}
      
      public static function getInstance()
      {
            if(!isset(self::$instance))
            {
                  $object= __CLASS__;
                  self::$instance=new $object;
            }
            return self::$instance;
      }
      
      public function displayMessage()
      {
            echo 'I am a Singleton';
      }
}
?>
==========

Now I have two scripts, test.php, and test2.php

They each look like the following:

test.php
==========
<?php

require_once "singleton.php";

$singleton=Singleton::getInstance();
$singleton->displayMessage();// display message

$singleton2=Singleton::getInstance();
$singleton2->displayMessage();// display message

print "$singleton<br />";
print "$singleton2<br />";


      
?>
==========

test2.php
==========

require_once "singleton.php";

$e = new Exception();

$singleton=Singleton::getInstance();
$singleton->displayMessage();// display message

$singleton2=Singleton::getInstance();
$singleton2->displayMessage();// display message

print "$singleton<br />";
print "$singleton2<br />";
==========

Note that test2.php has created an exception object at the top.  So the output of test and test2 is the following:

I am a Singleton
I am a Singleton
Object id #1
Object id #1

I am a Singleton
I am a Singleton
Object id #2
Object id #2

So the Singleton only acts as a 'Singleton' within the current script.  On requests to other pages, it does NOT return the same object id.  On test, the object id is #1, but on test2, the object id is 2.  So this is not really a singleton like in Java?  I don't see how it could be since there is no container.  I thought maybe PHP did something behind the scenes.  And if you put some intialization code in the private constructor, it will run on every getInstance on separate scripts.  So if you have code that connects to the database, it is no different then connecting at the top of every script.  Am I missing something??


0
abstractionz
Asked:
abstractionz
  • 3
  • 2
  • 2
  • +1
2 Solutions
 
Brian BushSolutions ArchitectCommented:
Unless there is some new thing in PHP5 that I haven't seen, PHP is still completely
stateless and objects don't really persist the way they do in languages like JAVA.

So, the only way that I know of that you can create a truly persistent object is to
serve it from a daemon PHP application that you attach to at runtime.

Otherwise, the PHP script only stays alive and in memory while the page loads.

So, to answer your question about something like a database connection object...
No, I don't see any real benefit over making the connection in each script.

PHP Architect publishes a NanoBook on Design Patterns in PHP (including the
Singleton) that may be of more help:
http://www.phparch.com/shop_product.php?itemid=96

Good Luck,
--brian
0
 
RoonaanCommented:
PHP is still a scripting language, and as such, each script request runs in its own environment and memory space.

When you need to have persistent connections to databases or other resources you would have to resolve to the modules that provide the connections themselves. For mysql you have the mysql_pconnect(). Personally I don't exactly know what is themysqli equivalent to this function.

-r-

0
 
cully_larsonCommented:
Another solution would be to store your instance in a Session variable:

http://www.php.net/manual/en/ref.session.php

If the instance doesn't exist, check for it in the session.


Cully
0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
abstractionzAuthor Commented:
How do you put the instance into the Session?

I tried placing a database connection object into the session in one script, then in another tried to retrieve it and got the following fatal error:

Fatal error: main() [function.main]: The script tried to execute a method or access a property of an incomplete object. Please ensure that the class definition "DB_Mysql" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide a __autoload() function to load the class definition in C:\phpapps\\test2.php on line 10
0
 
Brian BushSolutions ArchitectCommented:
To hold an object in the session you have to instance the object before
getting or setting it to the session.

// To set the object...
require_once("MyObject.php");
session_start();

$_obj = new MyObject("param1", "param2", "param3");
$_SESSION['obj'] = $_obj;

// To get the object...
require_once("MyObject.php");
session_start();

$_obj = new MyObject();
$_obj = $_SESSION['obj'];

This way, PHP knows what the object is before it loads it.
Make sense? I know it probably seems weird, but that's the
way it works in PHP.

Anyway, give it a shot.
--brian
0
 
abstractionzAuthor Commented:
But it would not work if using a Singleton DB Connection object.
0
 
Brian BushSolutions ArchitectCommented:
Right, being that the whole point of the Singleton pattern is a single instantiation.
Typically, though, the Singleton class can handle the second instantiation attempt
and basically just ignore it.

Anyway, this is a pretty complex problem. I suggest you look at the PHP Design
Patterns book to see how they treat the Singleton. I haven't had a chance yet
myself, and for this example, it is very difficult to test. You would need to look at
the instance info like you have above and monitor the database connection to
see that it does persist and is not duplicated.

In the meantime, I can tell you that holding the object in the session is a good
attempt to overcome state, but it also writes to disk and may give you no better
performance than creating a new connection with each page.

Also, part of what Cully was suggesting might be to not implement a true
Singleton pattern, but to check for the object instance in the script or session
before instantiating any new ones. Of course that is the sort of thing that
typically takes place in a Singleton class constructor.

The last thing is about the error message you were getting... The one about
an incomplete object is basically saying you have to instantiate an empty object
locally (current script) before you can assign another object, say from the session,
to it.

I know this must feel like coding in circles. Sorry I can't be of more help.
--brian
0
 
cully_larsonCommented:
If you're just trying to get a persistent sql connection, use a function like mysql_pconnect().

Cully
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 3
  • 2
  • 2
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now