By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
455,776 Members | 1,397 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 455,776 IT Pros & Developers. It's quick & easy.

Singleton class scope problem

P: n/a
On my site I want to make two classes. One that can be instantiated
normally and one with extended functionality that can only be
instantiated once. The Singleton pattern thus seems like a logical
choice for the second class. However, I would like the second
(singleton) class to extend the first. Something like this:
<?php
class User
{
public function __construct ()
{
doSomething();
}
}

class Member extends User
{
private static $instance = NULL;
public static function getInstance ()
{
if (self::$instance === NULL)
self::$instance = new Member;
return self::$instance;
}

private function __construct () {}
private function __clone () {}
}
?>
But this gives me the following error:
Fatal error: Access level to Member::__construct() must be public (as
in class User) in class.member.php on line 6

But I don't want the constructor to be public, because I want it to be
impossible to create more than one instance.

Does anybody know what to do about this?

Thanks.

Jul 17 '05 #1
Share this Question
Share on Google+
10 Replies


P: n/a
Uzytkownik <jb*****@gmail.com> napisal w wiadomosci
news:11**********************@g47g2000cwa.googlegr oups.com...
Fatal error: Access level to Member::__construct() must be public (as
in class User) in class.member.php on line 6

But I don't want the constructor to be public, because I want it to be
impossible to create more than one instance.

Does anybody know what to do about this?


Make it protected :-)

Jul 17 '05 #2

P: n/a
jb*****@gmail.com wrote:
But this gives me the following error:
Fatal error: Access level to Member::__construct() must be public (as
in class User) in class.member.php on line 6

But I don't want the constructor to be public, because I want it to be
impossible to create more than one instance.

Does anybody know what to do about this?


This is just how things are. If you want to extend a class and declare the
constructor of the extending class as private, the constructor of the parent
class should also be private. The only thing you could do is to define the
constructor method in your User class as private also and add a
getInstance() method which returns a freshly made instance each time it's
called...
JW

Jul 17 '05 #3

P: n/a
Thanks for the replies!

@Bzdziul: I can't make it protected, because that is still a stricter
access level than public and the contructor for the User-class really
needs to be public (unless Janwillem's can work).

@Janwillem: I kind of figured that this is just the way it is... Did I
understand that your suggestion is something like this:
<?php
class User
{
private function __construct ($iUserId) {
$this->iUserId = $iUserId;
}

public static function getInstance ($iUserId) {
return new User($iUserId);
}
}
/* And instead of this:
$user = new User(23);
I would use this:
$user = User::getInstance(23);*/
?>

Well, I guess that could work, although I don't really like it as a
solution, because User is supposed to be a normal class like every
other. But I guess it is either this or just using a public constructor
for the Member-class.
I was wondering if it was possible to somehow throw an error if the
constructor is called from somewhere other than the class itself. In
pseudocode:
public function __construct () {
if (called from global scope)
trigger_error (__CLASS__.' is not supposed to be instantiated
from the global scope because it is a Singleton class.', E_ERROR);
}

However, I don't know what to fill in in the if-statement. Any
suggestions?

Jul 17 '05 #4

P: n/a
What do you think of this solution ? It's not thread-safe however...

<?php

class User { }

class Member extends User
{
private static $instance = NULL;
private static $canInstanciate = false;
public static function getInstance ()
{
if (self::$instance === NULL)
{
self::$canInstanciate = true;
self::$instance = new Member();
self::$canInstanciate = false;
}
return self::$instance;
}

public function __construct ()
{
if (self::$canInstanciate !== true)
{
trigger_error (__CLASS__.' is not supposed to be
instantiated from the global scope because it is a Singleton class.',
E_USER_ERROR);
}
}
public function test () { echo 'Hello'; }
}

$x = Member::getInstance();
$x->test();

$x = new Member();
$x->test();

?>

Cheers,
.... zimba

Jul 17 '05 #5

P: n/a
That's actually what I came up with myself yesterday night. I like it,
although I was hoping for an even more elegant way, but I think I'm
going to use this.

What does 'thread-safe' mean?

Jul 17 '05 #6

P: n/a
Jordi wrote:
What does 'thread-safe' mean?


When an application is thread-safe, it implies that each user gets a unique
object instance.

Jordi's example is not considered thread-safe, because it returns the same
object for all users.

The following would make the class thread-safe for multiple users:

<?php
class User {}

class Member extends User {
private static $instances = array();
private static $canInstanciate = false;
private $user_id;
private $name;

public static function getInstance($user_id) {
if (!isset(self::$instances[$user_id])) {
self::$canInstanciate = true;
self::$instances[$user_id] = new Member($user_id);
self::$canInstanciate = false;
}
return self::$instances[$user_id];
}

public function __construct($user_id) {
if (self::$canInstanciate !== true) {
trigger_error('Unable to instantiate', E_USER_ERROR);
}
$this->user_id = $user_id;
}

public function setName($name) {
$this->name = $name;
}

public function getName() {
return $this->name;
}
}
$m = Member::getInstance(10);
$m->setName('Joe');
echo $m->getName(), '<br />';

$m2 = Member::getInstance(20);
$m2->setName('Bill');
echo $m2->getName(), '<br />';

$m3 = Member::getInstance(10);
echo $m3->getName(), '<br />';

?>
JW

Jul 17 '05 #7

P: n/a
So with the script I had so far, only one member can be logged in at a
time?

I don't need to be able to do this in a script:
$m = Member::getInstance(10);
$m->setName('Joe');
echo $m->getName(), '<br />';

$m2 = Member::getInstance(20);
$m2->setName('Bill');
echo $m2->getName(), '<br />';

$m3 = Member::getInstance(10);
echo $m3->getName(), '<br />';

There should only be one member per script execution, but it should be
possible for two different visitors to both instantiate their own
Member-object.
In order to accomplish that, do I need your example or will mine do?

Jul 17 '05 #8

P: n/a
Janwillem Borleffs wrote:
Jordi wrote:
What does 'thread-safe' mean?
When an application is thread-safe, it implies that each user gets a

unique object instance.

Jordi's example is not considered thread-safe, because it returns the same object for all users.


No it won't. The script starts from scratch on each request, with no
knowledge of what happened on previous (or simultaneous) runs.

Variables (including class instances and static members) are not shared
between PHP runs.
--
Oli

Jul 17 '05 #9

P: n/a
Jordi wrote:
There should only be one member per script execution, but it should be
possible for two different visitors to both instantiate their own
Member-object.
In order to accomplish that, do I need your example or will mine do?


In that case, your script will do fine.
JW

Jul 17 '05 #10

P: n/a
Oli Filth wrote:
Variables (including class instances and static members) are not
shared between PHP runs.


Totally correct and this is indeed the true meaning of 'thread-safety'.
However, the term is often abused in PHP to indicate shared object access
during a script run as it was introduced into this discussion.
JW

Jul 17 '05 #11

This discussion thread is closed

Replies have been disabled for this discussion.