16

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 a simple example is best.

Now my problem has become:

$ins = new class_A();

How to store 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.

bool.dev
  • 17,508
  • 5
  • 69
  • 93
user198729
  • 61,774
  • 108
  • 250
  • 348
  • 1
    There's no magic way to find an object, knowing only its class. You're going to have to put your instance somewhere you can find it later. – Frank Farmer Jan 21 '10 at 15:51
  • 1
    With at least eight answers and Singleton, Registry and instanceof, etc all mentioned, you might want to be more precise about what you are trying to do. – Gordon Jan 21 '10 at 16:52

12 Answers12

36

What you have described is essentially the singleton pattern. Please see this question for good reasons why you might not want to do this.

If you really want to do it, you could implement something like this:

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

    public static function get() {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }
}

$a = a::get();
Community
  • 1
  • 1
Tom Haigh
  • 57,217
  • 21
  • 114
  • 142
  • 1
    $this is the current object. self is the current class - which you use for accessing static members. – Tom Haigh Jan 21 '10 at 17:03
  • 1
    What is the UseCase for this? – Gordon Jan 21 '10 at 17:10
  • 1
    @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 ` – user198729 Jan 21 '10 at 17:13
  • 1
    @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 Jan 21 '10 at 17:19
  • 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. – user198729 Jan 21 '10 at 17:23
  • This is like a Singleton. For me this is wrong for correct OOP proposes. I my vision the solution is some factory(so test instanceof from the concrect result from factory). – Maykonn May 31 '13 at 14:42
  • Continuing: see why singleton is bad http://stackoverflow.com/questions/137975/what-is-so-bad-about-singletons – Maykonn May 31 '13 at 14:44
6

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
  • 115,121
  • 27
  • 131
  • 155
  • 3
    This is a common use case for the Singleton pattern, which is indeed possible to implement in PHP. – feeela Apr 08 '13 at 10:03
4

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

Pik'
  • 6,819
  • 1
  • 28
  • 24
4

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
  • 7,266
  • 3
  • 27
  • 46
  • 2
    This is exactly what the OP asked for, I just hope you don't get down-voted for this one. – Alix Axel Jan 21 '10 at 15:55
  • @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 Jan 21 '10 at 15:57
  • 1
    @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 Jan 21 '10 at 15:58
  • 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. – user198729 Jan 21 '10 at 15:59
  • 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 Jan 21 '10 at 16:03
  • 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 Jan 21 '10 at 16:04
  • 2
    The code above won't work. There is no vars inside the function scope (plus it has syntax errors). – Gordon Jan 21 '10 at 16:05
  • @Gordon, ouch, you're right - it can't be a function. I've edited to solve that issue. – Dathan Jan 21 '10 at 16:09
  • @Dathan: You can use `$GLOBALS`. – Alix Axel Jan 21 '10 at 16:24
2

if ($object instanceof class_A)

See PHP manual: Classes and objects

Pekka
  • 442,112
  • 142
  • 972
  • 1,088
2

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
  • 12,435
  • 13
  • 69
  • 89
2

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
  • 1,597
  • 8
  • 9
  • I don't see how `Singleton::getInstance()` will return an **existing** instance.There is no operation on `self::$_instance` in `__construct()` – user198729 Jan 21 '10 at 16:07
  • I've created the instance this way somewhere:`$ins = new class_A()`,so I need `Singleton::getInstance()` to work in this case – user198729 Jan 21 '10 at 16:16
  • Why can't you change $ins = new class_A(); to $ins = Singleton::getInstance()? – Karl B Jan 21 '10 at 16:23
  • There will be too many places to change.So it'll be better if the instance can be stored when calling `__construct()` – user198729 Jan 21 '10 at 16:28
  • 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 Jan 21 '10 at 16:33
  • Don't forget it's in web application.So there are multiple pages. – user198729 Jan 21 '10 at 16:35
  • Use search and replace. Time spent refactoring is better than time spent making bad code worse. – Karl B Jan 21 '10 at 16:42
  • I'm not sure if there is a solution that will work without limitation on how it's instantiated. – user198729 Jan 21 '10 at 16:45
  • 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. – Pik' Jan 21 '10 at 16:58
1

I think what you want is the Registry Pattern

AntonioCS
  • 8,335
  • 18
  • 63
  • 92
0

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.
  • 50,691
  • 36
  • 115
  • 143
0

The code below has a caching quality that promotes efficiency:

class Object {

  public $instance_variable;
  public $last_added_global_variable;

  public function __construct(){
    //we are saving the global variable before this one so that
    //we can be confident that we will always get the correct value
    $this->last_added_global_variable = $this->get_last_variable_added()[count($array_of_global_variables)-1];
  }

  //runs everytime a function is called in this class
  public function __call(){
    //remember, this is skipped whenever the variable name is saved
    if(!$this->instance_variable){
      for($i=0; $i=count($this->get_last_variable_added()); $i++){
        if($this->last_added_global_variable == get_last_variable_added()[$i]){
          $this->instance_variable = get_last_variable_added()[$i+1];
        }
      }
    }
  }

  private function get_last_variable_added(){
    $array_of_global_variables = array();

    foreach($GLOBALS as $g=>$v){
      array_push($array_of_global_variables, $g);
    }

    //return last added global variable
    return $array_of_global_variables;
  }

}

Although appearing costly, it is negligible.

You may note that finding the last added variable through a global-variable loop is impossible while still in the constructing function.

0

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
    // ...
    }
}
yodabar
  • 4,651
  • 2
  • 33
  • 38
0

In last version you can this


class Foo
{
}
$object=new Foo();
echo $object::class;
dılo sürücü
  • 3,821
  • 1
  • 26
  • 28