Welcome! Log In Create A New Profile

Advanced

[PHP] Singletons

Posted by Christoph Boget 
Christoph Boget
[PHP] Singletons
October 20, 2008 07:10PM
Ok, so why isn't this working as (I, at the very least) expected?

class singleTon
{
private static $thisObj = NULL;
private $thisProp = NULL;

public function __construct()
{
echo 'singleTon::__construct()<br>';
if( !is_null( singleTon::$thisObj ))
{
echo '$thisObj already set. returning it...<br>';
return singleTon::$thisObj;
}
singleTon::$thisObj = $this;
}

public static function singleton()
{
echo 'singleTon::singleton()<br>';
if( is_null( singleTon::$thisObj ))
{
$retval = new singleTon();
}
return singleTon::$thisObj;

}

public function setThisProp( $sVal )
{
$this->thisProp = $sVal;
}

public function getThisProp()
{
return $this->thisProp;
}
}

$one = singleTon::singleton();
$one->setThisProp( 'Joe' );
echo '$one->getThisProp();: [' . $one->getThisProp() . ']<br>';
echo '$one: [<pre>' . var_export( $one, TRUE ) . '</pre>]<br>';
$two = new singleTon();
echo '$two->getThisProp();: [' . $two->getThisProp() . ']<br>';
$two->setThisProp( 'Bob' );
echo '$two: [<pre>' . var_export( $two, TRUE ) . '</pre>]<br>';
echo '$one->getThisProp();: [' . $one->getThisProp() . ']<br>';
echo '$two->getThisProp();: [' . $two->getThisProp() . ']<br>';
echo '$one->getThisProp();: [' . $one->getThisProp() . ']<br>';

I would have thought that both $one and $two would be referencing the
same object but they aren't. Apart from making the constructor
private, is there any way I can ensure that there is ever only one
instance of an object?

thnx,
Christoph

--
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php
n3or
Re: [PHP] Singletons
October 20, 2008 07:20PM
Christoph Boget schrieb:
> Apart from making the constructor
> private, is there any way I can ensure that there is ever only one
> instance of an object?
you could use the magic method __clone.

For example:
public function __clone() { trigger_error('The singleton pattern avoids
cloning this instance', E_USER_ERROR); }

--
Viele Gruessee
Hi,
Dominik Strauss - www.n3or.de
Webentwicklung, PHP und Linux

Mobil: 0178 4940605
Internet: www.n3or.de
E-Mail: info@n3or.de


--
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php
Eric Butera
Re: [PHP] Singletons
October 20, 2008 07:25PM
On Mon, Oct 20, 2008 at 1:07 PM, Christoph Boget
<[email protected]> wrote:
> Ok, so why isn't this working as (I, at the very least) expected?
>
> class singleTon
> {
> private static $thisObj = NULL;
> private $thisProp = NULL;
>
> public function __construct()
> {
> echo 'singleTon::__construct()<br>';
> if( !is_null( singleTon::$thisObj ))
> {
> echo '$thisObj already set. returning it...<br>';
> return singleTon::$thisObj;
> }
> singleTon::$thisObj = $this;
> }
>
> public static function singleton()
> {
> echo 'singleTon::singleton()<br>';
> if( is_null( singleTon::$thisObj ))
> {
> $retval = new singleTon();
> }
> return singleTon::$thisObj;
>
> }
>
> public function setThisProp( $sVal )
> {
> $this->thisProp = $sVal;
> }
>
> public function getThisProp()
> {
> return $this->thisProp;
> }
> }
>
> $one = singleTon::singleton();
> $one->setThisProp( 'Joe' );
> echo '$one->getThisProp();: [' . $one->getThisProp() . ']<br>';
> echo '$one: [<pre>' . var_export( $one, TRUE ) . '</pre>]<br>';
> $two = new singleTon();
> echo '$two->getThisProp();: [' . $two->getThisProp() . ']<br>';
> $two->setThisProp( 'Bob' );
> echo '$two: [<pre>' . var_export( $two, TRUE ) . '</pre>]<br>';
> echo '$one->getThisProp();: [' . $one->getThisProp() . ']<br>';
> echo '$two->getThisProp();: [' . $two->getThisProp() . ']<br>';
> echo '$one->getThisProp();: [' . $one->getThisProp() . ']<br>';
>
> I would have thought that both $one and $two would be referencing the
> same object but they aren't. Apart from making the constructor
> private, is there any way I can ensure that there is ever only one
> instance of an object?
>
> thnx,
> Christoph
>
> --
> PHP General Mailing List (http://www.php.net/)
> To unsubscribe, visit: http://www.php.net/unsub.php
>
>

Look at http://us3.php.net/manual/en/language.oop5.patterns.php for a
working singleton example.

--
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php
Nathan Rixham
[PHP] Re: Singletons
October 20, 2008 07:25PM
Christoph Boget wrote:
> Ok, so why isn't this working as (I, at the very least) expected?
>
> class singleTon
> {
> private static $thisObj = NULL;
> private $thisProp = NULL;
>
> public function __construct()
> {
> echo 'singleTon::__construct()<br>';
> if( !is_null( singleTon::$thisObj ))
> {
> echo '$thisObj already set. returning it...<br>';
> return singleTon::$thisObj;
> }
> singleTon::$thisObj = $this;
> }
>
> public static function singleton()
> {
> echo 'singleTon::singleton()<br>';
> if( is_null( singleTon::$thisObj ))
> {
> $retval = new singleTon();
> }
> return singleTon::$thisObj;
>
> }
>
> public function setThisProp( $sVal )
> {
> $this->thisProp = $sVal;
> }
>
> public function getThisProp()
> {
> return $this->thisProp;
> }
> }
>
> $one = singleTon::singleton();
> $one->setThisProp( 'Joe' );
> echo '$one->getThisProp();: [' . $one->getThisProp() . ']<br>';
> echo '$one: [<pre>' . var_export( $one, TRUE ) . '</pre>]<br>';
> $two = new singleTon();
> echo '$two->getThisProp();: [' . $two->getThisProp() . ']<br>';
> $two->setThisProp( 'Bob' );
> echo '$two: [<pre>' . var_export( $two, TRUE ) . '</pre>]<br>';
> echo '$one->getThisProp();: [' . $one->getThisProp() . ']<br>';
> echo '$two->getThisProp();: [' . $two->getThisProp() . ']<br>';
> echo '$one->getThisProp();: [' . $one->getThisProp() . ']<br>';
>
> I would have thought that both $one and $two would be referencing the
> same object but they aren't. Apart from making the constructor
> private, is there any way I can ensure that there is ever only one
> instance of an object?
>
> thnx,
> Christoph

you can't return from a constructor; thus always use the static
singleton method()

i.e.: $two = singleTon::singleton();

--
nathan ( nathan@kraya.co.uk )
{
Senior Web Developer
php + java + flex + xmpp + xml + ecmascript
web development edinburgh | http://kraya.co.uk/
}

--
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php
Christoph Boget
Re: [PHP] Singletons
October 20, 2008 07:35PM
>> Apart from making the constructor
>> private, is there any way I can ensure that there is ever only one
>> instance of an object?
> you could use the magic method __clone.
> For example:
> public function __clone() { trigger_error('The singleton pattern avoids
> cloning this instance', E_USER_ERROR); }

Adding the above to my sample class (from my OP) did nothing. Should it have?

thnx,
Christoph

--
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php
n3or
Re: [PHP] Singletons
October 20, 2008 08:15PM
Christoph Boget schrieb:
>>> Apart from making the constructor
>>> private, is there any way I can ensure that there is ever only one
>>> instance of an object?
>>>
>> you could use the magic method __clone.
>> For example:
>> public function __clone() { trigger_error('The singleton pattern avoids
>> cloning this instance', E_USER_ERROR); }
>>
>
> Adding the above to my sample class (from my OP) did nothing. Should it have?
>
> thnx,
> Christoph
>
>
Hi,
it avoids cloning of the object:
$newObject = clone $oldObject;

--
Viele Gruessee

Dominik Strauss - www.n3or.de
Webentwicklung, PHP und Linux

Mobil: 0178 4940605
Internet: www.n3or.de
E-Mail: info@n3or.de
Stut
Re: [PHP] Singletons
October 20, 2008 08:50PM
On 20 Oct 2008, at 18:07, Christoph Boget wrote:
> Ok, so why isn't this working as (I, at the very least) expected?

Hmm, where to start...

> class singleTon
> {
> private static $thisObj = NULL;
> private $thisProp = NULL;
>
> public function __construct()

A singleton would usually have a private constructor to prevent non-
singleton instances.

> {
> echo 'singleTon::__construct()<br>';
> if( !is_null( singleTon::$thisObj ))
> {
> echo '$thisObj already set. returning it...<br>';
> return singleTon::$thisObj;
> }
> singleTon::$thisObj = $this;

1) You don't return it unless it already exists, not that it matters
because this is the constructor and you can't return anything from that.

2) The constructor has no involvement in management of the singleton
instance so this is just all wrong.

> }
>
> public static function singleton()
> {
> echo 'singleTon::singleton()<br>';
> if( is_null( singleTon::$thisObj ))
> {
> $retval = new singleTon();
> }
> return singleTon::$thisObj;
> }

That method has the same name as the class. I'm not sure what effect
this will have but it's certainly to be discouraged.

> public function setThisProp( $sVal )
> {
> $this->thisProp = $sVal;
> }
>
> public function getThisProp()
> {
> return $this->thisProp;
> }
> }
>
> $one = singleTon::singleton();
> $one->setThisProp( 'Joe' );
> echo '$one->getThisProp();: [' . $one->getThisProp() . ']<br>';
> echo '$one: [<pre>' . var_export( $one, TRUE ) . '</pre>]<br>';
> $two = new singleTon();
> echo '$two->getThisProp();: [' . $two->getThisProp() . ']<br>';
> $two->setThisProp( 'Bob' );
> echo '$two: [<pre>' . var_export( $two, TRUE ) . '</pre>]<br>';
> echo '$one->getThisProp();: [' . $one->getThisProp() . ']<br>';
> echo '$two->getThisProp();: [' . $two->getThisProp() . ']<br>';
> echo '$one->getThisProp();: [' . $one->getThisProp() . ']<br>';
>
> I would have thought that both $one and $two would be referencing the
> same object but they aren't. Apart from making the constructor
> private, is there any way I can ensure that there is ever only one
> instance of an object?


Here's the simplest example I can think of (untested, typed straight
into my mail client)...

class Singleton
{
static private $_instance = null;

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

private function __construct()
{
// Do normal instance initialisation here
// Nothing singleton-related should be present
}

public function __destruct()
{
// This is just here to remind you that the
// destructor must be public even in the case
// of a singleton.
}

private $var = '';

public function SetVar($val)
{
$this->var = $val;
}

public function GetVar()
{
return $this->var;
}
}

$obj1 = Singleton::Instance();
$obj1->SetVar('arse');
$obj2 = Singleton::Instance();
echo $obj2->GetVar(); // This will echo 'arse'

Singletons are not rocket science, but as with all patterns you really
need to understand the theory before trying to implement and use it.

-Stut

--
http://stut.net/

--
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php
Christoph Boget
Re: [PHP] Singletons
October 20, 2008 09:30PM
>> public function __construct()
> A singleton would usually have a private constructor to prevent
> non-singleton instances.

The problem being if the class in question derives from another class
that has a public constructor... If you are in that particular
situation (which I am), you're basically SOL and the statement above
has no bearing.

>> {
>> echo 'singleTon::__construct()<br>';
>> if( !is_null( singleTon::$thisObj ))
>> {
>> echo '$thisObj already set. returning it...<br>';
>> return singleTon::$thisObj;
>> }
>> singleTon::$thisObj = $this;
> 1) You don't return it unless it already exists, not that it matters because
> this is the constructor and you can't return anything from that.

> 2) The constructor has no involvement in management of the singleton
> instance so this is just all wrong.

I did this mainly to see if it would have any effect.

>> public static function singleton()
>> {
> That method has the same name as the class. I'm not sure what effect this
> will have but it's certainly to be discouraged.

It has no effect. And yes, that is true in general, but this is just
a test foobar class.

> Here's the simplest example I can think of (untested, typed straight into my
> mail client)...

This won't work if derived from a class with a public constructor.
That's why my test class' constructor was defined public.

> Singletons are not rocket science, but as with all patterns you really need
> to understand the theory before trying to implement and use it.

Agreed. But apparently implementing them in PHP leaves things to be desired.

thnx,
Christoph

--
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php
Stut
Re: [PHP] Singletons
October 20, 2008 09:40PM
On 20 Oct 2008, at 20:24, Christoph Boget wrote:
>>> public function __construct()
>> A singleton would usually have a private constructor to prevent
>> non-singleton instances.
>
> The problem being if the class in question derives from another class
> that has a public constructor... If you are in that particular
> situation (which I am), you're basically SOL and the statement above
> has no bearing.

Correct, but you're then breaking one of the rules of the singleton
pattern. If you're stuck with that then you'll need to enforce the
singleton aspect in non-technical ways (policy, regular beatings, etc).

>> Singletons are not rocket science, but as with all patterns you
>> really need
>> to understand the theory before trying to implement and use it.
>
> Agreed. But apparently implementing them in PHP leaves things to be
> desired.

Not really, not if you do it correctly. As far as I can tell, apart
from getting it completely wrong (it would have been wrong in all
languages I can think of) the only issue you've come across is not
being able to extend a class with a public constructor. If that's the
only issue you can find then I don't see much to be desired.

I don't know the exact reason for this limitation but I'm sure there's
a good one. The core PHP devs don't make a habit of enforcing
arbitrary limitations like that. If you think it's worth fixing feel
free to report it as a bug at http://bugs.php.net/ and you'll probably
get told the reason it's like that.

-Stut

--
http://stut.net/

--
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php
Tony Marston
Re: [PHP] Singletons
October 20, 2008 10:00PM
""Christoph Boget"" <[email protected]> wrote in message
news:[email protected]
>
<snip>
>
>> Singletons are not rocket science, but as with all patterns you really
>> need
>> to understand the theory before trying to implement and use it.
>
> Agreed. But apparently implementing them in PHP leaves things to be
> desired.

There is absolutely nothing in PHP which prevents you from implementing the
singleton pattern. There are several ways in which it can be done (take a
look at http://www.tonymarston.net/php-mysql/singleton.html for an example)
but your attempt is doomed to failure. What makes you think that a singleton
class has to inherit from another class? Why can't it be a separate class,
or even a separate method in an existing class? If you use a static method
then the activities of the constructor are irrelevant.

--
Tony Marston
http://www.tonymarston.net
http://www.radicore.org



--
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php
Christoph Boget
Re: [PHP] Singletons
October 20, 2008 10:10PM
> There is absolutely nothing in PHP which prevents you from implementing the
> singleton pattern.

It does if the constructor must be public.

> but your attempt is doomed to failure. What makes you think that a singleton
> class has to inherit from another class?

Nothing at all. Except that in my particular case, I do need to
inherit from another class which has a public constructor. And the
class I'm trying to write needs to be a singleton.

I guess that teaches me not to post a question without including a
doctoral thesis about what it is I'm trying to do. I figured just
including the most base and/or basic parts of what I was dealing with
would be sufficient. Though, I will say I probably shouldn't have
included all of that junk in the constructor in my OP. That was just
a hail-mary-pray-it-might-be-a-workable-workround on my part. I was
pretty sure it wouldn't be, but *shrug*

> Why can't it be a separate class,

In general, it can. In my case, it can't. Not unless I want to
completely duplicate an already existing class.

> or even a separate method in an existing class? If you use a static method
> then the activities of the constructor are irrelevant.

They aren't irrelevant if the class can be instantiated directly.
That sort of kind of breaks the whole singleton thing...

thnx,
Christoph

--
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php
Stut
Re: [PHP] Singletons
October 20, 2008 10:20PM
On 20 Oct 2008, at 21:06, Christoph Boget wrote:
>> Why can't it be a separate class,
>
> In general, it can. In my case, it can't. Not unless I want to
> completely duplicate an already existing class.

Create your singleton class without extending the class you need to
extend. Create an instance of that class in your object. Implement the
__call magic method to proxy function calls through to that instance
throwing an exception (or error) if the method requested doesn't
exist. Not particularly pretty, but definitely simple.

-Stut

--
http://stut.net/

--
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php
Christoph Boget
Re: [PHP] Singletons
October 20, 2008 11:00PM
> Create your singleton class without extending the class you need to extend.
> Create an instance of that class in your object. Implement the __call magic
> method to proxy function calls through to that instance throwing an
> exception (or error) if the method requested doesn't exist. Not particularly
> pretty, but definitely simple.

No, not pretty at all though it would address my issues. Thanks for the idea!

thnx,
Christoph

--
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php
Jochem Maas
Re: [PHP] Singletons
October 21, 2008 03:20AM
Christoph Boget schreef:
>> Create your singleton class without extending the class you need to extend.
>> Create an instance of that class in your object. Implement the __call magic
>> method to proxy function calls through to that instance throwing an
>> exception (or error) if the method requested doesn't exist. Not particularly
>> pretty, but definitely simple.
>
> No, not pretty at all though it would address my issues. Thanks for the idea!

or use a registry pattern to store your singleton objects and use the registry
to retrieve the instances. this requires some discipline in that the registry should
always be the interface through which your objects are retrieved ... discipline
is always and issue when writing code :-)



>
> thnx,
> Christoph
>


--
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php
Colin Guthrie
[PHP] Re: Singletons
October 22, 2008 11:15AM
Stut wrote:
> On 20 Oct 2008, at 20:24, Christoph Boget wrote:
>>>> public function __construct()
>>> A singleton would usually have a private constructor to prevent
>>> non-singleton instances.
>>
>> The problem being if the class in question derives from another class
>> that has a public constructor... If you are in that particular
>> situation (which I am), you're basically SOL and the statement above
>> has no bearing.
>
> Correct, but you're then breaking one of the rules of the singleton
> pattern. If you're stuck with that then you'll need to enforce the
> singleton aspect in non-technical ways (policy, regular beatings, etc).


I disagree (not with the regular beatings... that's very important for
moral!), but with the statement that says you are SOL if you want to
create a singleton that derives from another class with a public
constructor, you just have to make the derived class' constructor
private and call the parent's constructor:


class Base
{
private $foo;
public function __construct($foo)
{
$this->foo = $foo;
}

public function getFoo()
{
return $this->foo;
}
}

class Singleton extends Base
{
private function __construct()
{
parent::__construct("Singleton");
}

public static function getInstance()
{
static $instance = null;
if (!isset($instance))
$instance = new self();
return $instance;
}
}


$bar = Singleton::getInstance();
$bar->getFoo(); // "Singleton"


(entirely untested)

Col

--

Colin Guthrie
gmane(at)colin.guthr.ie
http://colin.guthr.ie/

Day Job:
Tribalogic Limited [http://www.tribalogic.net/]
Open Source:
Mandriva Linux Contributor [http://www.mandriva.com/]
PulseAudio Hacker [http://www.pulseaudio.org/]
Trac Hacker [http://trac.edgewall.org/]


--
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php
Carlos Medina
[PHP] Re: Singletons
October 22, 2008 11:30AM
Colin Guthrie schrieb:
> Stut wrote:
>> On 20 Oct 2008, at 20:24, Christoph Boget wrote:
>>>>> public function __construct()
>>>> A singleton would usually have a private constructor to prevent
>>>> non-singleton instances.
>>>
>>> The problem being if the class in question derives from another class
>>> that has a public constructor... If you are in that particular
>>> situation (which I am), you're basically SOL and the statement above
>>> has no bearing.
>>
>> Correct, but you're then breaking one of the rules of the singleton
>> pattern. If you're stuck with that then you'll need to enforce the
>> singleton aspect in non-technical ways (policy, regular beatings, etc).
>
>
> I disagree (not with the regular beatings... that's very important for
> moral!), but with the statement that says you are SOL if you want to
> create a singleton that derives from another class with a public
> constructor, you just have to make the derived class' constructor
> private and call the parent's constructor:
>
>
> class Base
> {
> private $foo;
> public function __construct($foo)
> {
> $this->foo = $foo;
> }
>
> public function getFoo()
> {
> return $this->foo;
> }
> }
>
> class Singleton extends Base
> {
> private function __construct()
> {
> parent::__construct("Singleton");
> }
>
> public static function getInstance()
> {
> static $instance = null;
> if (!isset($instance))
> $instance = new self();
> return $instance;
> }
> }
>
>
> $bar = Singleton::getInstance();
> $bar->getFoo(); // "Singleton"
>
>
> (entirely untested)
>
> Col
>
Hallo,
this is the Result of my test with your Code:

Fatal error: Access level to Singleton::__construct() must be public (as
in class Base) in C:\Users\cmedina\Documents\test1.php on line 30

Regards

Carlos

--
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php
Carlos Medina
[PHP] Re: Singletons
October 22, 2008 11:35AM
Hi,
here is in my opinion, what you can do:

class Base
{
private $foo;
private function __construct()
{}

public function getFoo()
{
return $this->foo;
}

public function setFoo( $foo )
{
$this->foo = $foo;
}
}

class Singleton extends Base
{
public function __construct()
{}

private function __clone()
{}

public static function getInstance()
{
static $instance = null;
if (!isset($instance))
$instance = new self();
$instance->setFoo( 'singleton' );
return $instance;
}
}


$bar = Singleton::getInstance();
echo $bar->getFoo(); // "Singleton"

Regards

Carlos

--
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php
Christoph Boget
Re: [PHP] Re: Singletons
October 22, 2008 03:10PM
> here is in my opinion, what you can do:
> class Base {
> private function __construct()

Except that in one of my follow up posts I indicated that my singleton
class was deriving from a class that had a public constructor.

Thanks anyway. I ended up just using Stut's suggestion. As he said,
it's not pretty but it is simple.

thnx,
Christoph

--
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php
Colin Guthrie
[PHP] Re: Singletons
October 22, 2008 03:30PM
Carlos Medina wrote:

> this is the Result of my test with your Code:
>
> Fatal error: Access level to Singleton::__construct() must be public (as
> in class Base) in C:\Users\cmedina\Documents\test1.php on line 30

Hmmm, that'll learn me for not running it first I sps :s

Well that is completely crap. I didn't realise there was such a
limitation in PHP's object heirarchy. Wonder why it's like this... Can't
think of a valid reason...

Col


--

Colin Guthrie
gmane(at)colin.guthr.ie
http://colin.guthr.ie/

Day Job:
Tribalogic Limited [http://www.tribalogic.net/]
Open Source:
Mandriva Linux Contributor [http://www.mandriva.com/]
PulseAudio Hacker [http://www.pulseaudio.org/]
Trac Hacker [http://trac.edgewall.org/]


--
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php
Sorry, only registered users may post in this forum.

Click here to login