views:

1099

answers:

10

I need to check if there exists an instance of class_A ,and if there does exist, get that instance.

How to do it in PHP?

As always,I think an simple example is best.

Now my problem has become:

$ins = new class_A();

How to storing the instance in a static member variable of class_A when instantiating?

It'll be better if the instance can be stored when calling __construct().Say,it should work without limitation on how it's instantiated.

A: 

if ($object instanceof class_A)

See PHP manual: Classes and objects

Pekka
I don't have direct access to `$object`
+2  A: 

You should implement the Singleton pattern. http://www.developertutorials.com/tutorials/php/php-singleton-design-pattern-050729/page1.html

Pikrass
If class_A is a class over which the user doesn't have control, the singleton pattern may be impossible to apply.
Dathan
class_A doesn't have to become the singleton. You could create a class_B that holds a single class_A.
Frank Farmer
That works if the user is going to be responsible for the instantiation of class_A, and can ensure that it's done through class_B. What if the instance of class_A is generated by some other piece of code that's unaware of class_B?
Dathan
@Dathan Then you're pretty screwed.
meagar
A: 

I think what you want is the Registry Pattern

AntonioCS
A: 

To expand on Pikrass answer, you basically will want to do something like this:

class class_A {
  private static $instance = false;

  public static function getInstance() {
    if (!self::$instance) {
      self::$instance = new class_A();
    }

    return self::$instance;
  }

  // actual class implementation goes here
}


// where you need to use the instance:
$mySingleton = class_A::getInstance();
// do something with $mySingleton
Aistina
I need to **get** already existing instance,not **create**
A: 

The singleton pattern, with a PHP example from Wikipedia that I've added a "checkExists" method to, as it sounds like you want to check for the existence of the class without necessarily creating it if it doesn't exit:

final class Singleton 
{
    protected static $_instance;

    protected function __construct() # we don't permit an explicit call of the constructor! (like $v = new Singleton())
    { }

    protected function __clone() # we don't permit cloning the singleton (like $x = clone $v)
    { }

    public static function getInstance() 
    {
      if( self::$_instance === NULL ) {
        self::$_instance = new self();
      }
      return self::$_instance;
    }

    public static function checkExists() 
    {
      return self::$_instance;
    }
}

if(Singleton::checkExists())
   $instance = Singleton::getInstance();
Karl B
I don't see how `Singleton::getInstance()` will return an **existing** instance.There is no operation on `self::$_instance` in `__construct()`
I've created the instance this way somewhere:`$ins = new class_A()`,so I need `Singleton::getInstance()` to work in this case
Why can't you change $ins = new class_A(); to $ins = Singleton::getInstance()?
Karl B
There will be too many places to change.So it'll be better if the instance can be stored when calling `__construct()`
If there are too many places to change, then it's likely that there'll be more than one instance in existence at any time, in which case the original question doesn't make much sense.
Karl B
Don't forget it's in web application.So there are multiple pages.
Use search and replace. Time spent refactoring is better than time spent making bad code worse.
Karl B
I'm not sure if there is a solution that will work without limitation on how it's instantiated.
Just make a little script to change every `new class_A()` to `class_A::getInstance()`. It can be done easily with sed. `__construct` will always create a new instance.
Pikrass
+1  A: 

Maybe you want something like

for (get_defined_vars() as $key=>$value)
{
  if ($value instanceof class_A)
    return $value;
}

EDIT: Upon further reading, you have to jump through some hoops to get object references. So you might want return $$key; instead of return $value;. Or some other tricks to get a reference to the object.

Dathan
Yes,that's what I want,but I also care about the performance
This is exactly what the OP asked for, I just hope you don't get down-voted for this one.
Alix Axel
@unknown (google): There is no magic bullet for that... And it can get worse if you want it to handle recursion (objects inside multi-dimensional arrays).
Alix Axel
@unknown, I believe that without being able to apply one of the other patterns described (which will require you to either control instantiation of the object or modify the object itself), this is the best you can do. However, you can merge the above with the registry pattern, so you only have to take the performance hit once.
Dathan
What about storing the instance in a static member variable of that class?Is it possible?What kind of modification should I make on `class_A`?I have full control over it.
In that case, I'd create a global registry and have the constructor for class_A add the instance to the registry at instantiation. I'd follow AntonioCS's link. The code example is very simple.
Dathan
If you have full control of the class then you should use the singleton pattern, and comment it as such. Then anyone who follows you and has to work with the code will know that's the intention and won't created more instances by accident.
Karl B
The code above won't work. There is no vars inside the function scope (plus it has syntax errors).
Gordon
@Gordon, ouch, you're right - it can't be a function. I've edited to solve that issue.
Dathan
@Dathan: You can use `$GLOBALS`.
Alix Axel
Ok, $GLOBALS works. But it still should be foreach.
Gordon
A: 

Remember that by using a singleton, you're basically creating a big global variable. If it's got state that changes, your code can become unpredictable. So use caution.

JW
+3  A: 

What you ask for is impossible (Well, perhaps not in a technical sense, but highly impractical). It suggests that you have a deeper misunderstanding about the purpose of objects and classes.

troelskn
+1 - I think you've hit the nail on the head.
Karl B
+2  A: 

Can you modify the constructor? So you could have:

class a {
    public static $instance;
    public function __construct() {
        self::$instance = $this;
    }
}

if ($a = a::$instance) {
    //do something with existing instance of a
}
Tom Haigh
Oh,it's working!+1
$this is the current object. self is the current class - which you use for accessing static members.
Tom Haigh
What is the UseCase for this?
Gordon
@Gordon,It's for templating engine.I use `extract` to populate PHP variables in template file.But I also need to populate the javascript variables,which can't be achieved with `extract`,but insert `<script>` at proper places,so I need a solution to get my instance in template file.Hopefully I've answered your question.
@unknown that sounds completely wrong and I still don't understand what you'd need the above code for. But I don't have to understand it, so go ahead :)
Gordon
Actually I'm adding a new feature to my own MVC class,which is assigning **javascript** variables.I've been using it all the time,not as functional as smarty,but I like it.You'll step into the same issue if you start to implement such a thing from scratch.
A: 

If the replacement of the singleton instantiation instrucion in your files is a problem you may turn into a constant-driven behaviour: constants are such for all the duration of the script, so in case of an instance which requirement is to be unique (for all the script duration) the construction method may be properly linked to the existence/value of a constant.

class superObject {
    public function __construct() {
        if (defined('SUPER_OBJECT')) {
            trigger_error('Super object '.__CLASS__.' already instantiated', E_USER_ERROR);
                    // ...or just do whatever you want to do in case of instances overlap
        } else {
            define('SUPER_OBJECT', true);
        }
    // the rest of your construct method
    // ...
    }
}
Emanuele Del Grande