user3104270
user3104270

Reputation: 625

Function calling itself infinitely?

I was doing a little experiment with PHP clases, and I encountered this weird problem.

The class is intended to assign its $instance property an instance of itself in case $instance is null, but this mechanism which is supposed to prevent infinite self-procreation seems to fail, and this is what happens:

Fatal error: Maximum function nesting level of '100' reached, aborting!

<?php
class SeemsLikeInfinity {

public $instance;

public function __construct() {

    if ( $this->instance == null ) {

        $this->instance = new self;

    }
}

}

$looping = new SeemsLikeInfinity();

?>

Why does this happen? The __construct merely creates a new instance of the class which is blank, thus has the empty $instance, and therefore creates the instance again, making the loop go infinite?

Thank you very much

Upvotes: 1

Views: 1148

Answers (3)

ZiupeX
ZiupeX

Reputation: 338

That happen beacuse the param $instance is always null. Each time you create new object inside class. If you want implements singleton you should change __construct to private and use one static method to create just one object

 class SeemsLikeInfinity {

   private static $instance;

   private function __construct() {
       // some action;
   }
   public static function generate_singleton(){
     if ( self::$instance == null ) {
         self::$instance = new self;
     }
     return self::$instance
   }
}

$singleton = SeemsLikeInfinity::generate_singleton();
// here you have singleton and you cant create more tha one object

Upvotes: 2

Damien Black
Damien Black

Reputation: 5647

When you make an object with the 'new' keyword, it calls the constructor. If you use new self in the constructor, it will call the construction again. Causing an infinite loop.

A new instance is automatically made when you use new, so you don't have to store something like $this->instance. The variable $this is your instance.

The important thing to remember is that each instance of the class has its own variable $instance. So it will always be null the whole way down.

Now, if you are trying to make a singleton, you actually have to make the constructor private:

private function __construct() {}

Then we need instance to be a static variable:

static private $instance;

No no one can create a new object using the new keyword. So then we need to provide a static function to create an instance:

static function newInstance() {
    if ( self::instance == null ) {
        self::instance = new self;
    }
    return self::instance;
}

Now you get new instances using this:

$x = SeemsLikeInfinity::newInstance();

Now there will only ever be one SeemsLikeInfinity object and you can always access it with SeemsLikeInfinity::newInstance()

Upvotes: 1

CD001
CD001

Reputation: 8482

The reason you have to use static variables rather than $this is that $this is relative only to the current object - every time you create a new SeemsLikeInfinity object you're creating a new $this for that object - therefore $this->instance is always null when you instantiate the class.

So, what's happening in your constructor:

if ( $this->instance == null ) {
  $this->instance = new self;
}

... is a new $this->instance (with no assigned value) is created when the object is constructed so a new object is constructed with a new $this->instance, again without a value, so a new object is constructed with a new $this->instance, again without a value ... and so on, forever.

Static variables, however, are relative to the class itself... you can instantiate the class as many times as you like and each object created will inherit the last set values of the static variables from the class.

What you're trying to do is create a Singleton so you never call the constructor directly, you instantiate and access the class via a static getInstance() method:

// I've made this a "final" class - you can't really
// extend Singletons without getting into a mess
final class SeemsLikeInfinity {

  // this needs to be a static variable as it'll
  // be checked from the static self::getInstance() method
  // it should also be private as you'll never call it from
  // outside the class
  private static $instance;

  // the constructor function should also be private
  // as it'll ONLY ever be called from the 
  // self::getInstance() method
  private function __construct() {
    // ... do stuff here to instantiate your class
  }

  // Singletons can't be cloned
  public function __clone() {
    throw new Exception("ERROR : you can't clone Singletons", E_USER_ERROR);
  }

  // this is the main getInstance() method called
  // to actually instantiate or call the class
  public static function getInstance() {
    if(!self::$instance) { self::$instance = new self(); }
    return self::$instance;
  }
}

// now, to instantiate or access your class you'd use getInstance()
// you'll no longer have permanently reiterating classes and you
// should be golden
$looping = SeemsLikeInfinity::getInstance();

As an aside, the best use I've ever found for Singletons is building a session management wrapper since a session, by its very nature, has just one instance.

Upvotes: 0

Related Questions