Singleton class scope problem

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • jbieger@gmail.com

    Singleton class scope problem

    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::$instanc e === 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::__const ruct() must be public (as
    in class User) in class.member.ph p 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.

  • Bzdziul

    #2
    Re: Singleton class scope problem

    Uzytkownik <jbieger@gmail. com> napisal w wiadomosci
    news:1116508449 .646735.156290@ g47g2000cwa.goo glegroups.com.. .[color=blue]
    > Fatal error: Access level to Member::__const ruct() must be public (as
    > in class User) in class.member.ph p 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?[/color]

    Make it protected :-)

    Comment

    • Janwillem Borleffs

      #3
      Re: Singleton class scope problem

      jbieger@gmail.c om wrote:[color=blue]
      > But this gives me the following error:
      > Fatal error: Access level to Member::__const ruct() must be public (as
      > in class User) in class.member.ph p 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?
      >[/color]

      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



      Comment

      • Jordi

        #4
        Re: Singleton class scope problem

        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::getInstan ce(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?

        Comment

        • zimba

          #5
          Re: Singleton class scope problem

          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::$instanc e === NULL)
          {
          self::$canInsta nciate = true;
          self::$instance = new Member();
          self::$canInsta nciate = false;
          }
          return self::$instance ;
          }

          public function __construct ()
          {
          if (self::$canInst anciate !== 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::getInst ance();
          $x->test();

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

          ?>

          Cheers,
          .... zimba

          Comment

          • Jordi

            #6
            Re: Singleton class scope problem

            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?

            Comment

            • Janwillem Borleffs

              #7
              Re: Singleton class scope problem

              Jordi wrote:[color=blue]
              > What does 'thread-safe' mean?[/color]

              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($us er_id) {
              if (!isset(self::$ instances[$user_id])) {
              self::$canInsta nciate = true;
              self::$instance s[$user_id] = new Member($user_id );
              self::$canInsta nciate = false;
              }
              return self::$instance s[$user_id];
              }

              public function __construct($us er_id) {
              if (self::$canInst anciate !== 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::getInst ance(10);
              $m->setName('Joe') ;
              echo $m->getName(), '<br />';

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

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

              ?>


              JW



              Comment

              • Jordi

                #8
                Re: Singleton class scope problem

                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::getInst ance(10);
                $m->setName('Joe') ;
                echo $m->getName(), '<br />';

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

                $m3 = Member::getInst ance(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?

                Comment

                • Oli Filth

                  #9
                  Re: Singleton class scope problem

                  Janwillem Borleffs wrote:[color=blue]
                  > Jordi wrote:[color=green]
                  > > What does 'thread-safe' mean?[/color]
                  >
                  > When an application is thread-safe, it implies that each user gets a[/color]
                  unique[color=blue]
                  > object instance.
                  >
                  > Jordi's example is not considered thread-safe, because it returns the[/color]
                  same[color=blue]
                  > object for all users.[/color]

                  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

                  Comment

                  • Janwillem Borleffs

                    #10
                    Re: Singleton class scope problem

                    Jordi wrote:[color=blue]
                    > 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?[/color]

                    In that case, your script will do fine.


                    JW



                    Comment

                    • Janwillem Borleffs

                      #11
                      Re: Singleton class scope problem

                      Oli Filth wrote:[color=blue]
                      > Variables (including class instances and static members) are not
                      > shared between PHP runs.[/color]

                      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



                      Comment

                      Working...