Question

Disons que j'écris une classe PHP (>= 5.0) censée être un singleton.Tous les documents que j'ai lus disent de rendre le constructeur de classe privé afin que la classe ne puisse pas être directement instanciée.

Donc si j'ai quelque chose comme ça :

class SillyDB
{
  private function __construct()
  {

  }

  public static function getConnection()
  {

  }
}

Existe-t-il des cas où __construct() est appelé autrement que si je fais un

new SillyDB() 

appeler à l'intérieur de la classe elle-même ?

Et pourquoi suis-je autorisé à instancier SillyDB depuis l'intérieur de lui-même ?

Était-ce utile?

La solution

__construct() ne serait appelé que si vous l'appeliez depuis une méthode pour la classe contenant le constructeur privé.Donc pour votre Singleton, vous pourriez avoir une méthode comme celle-ci :

class DBConnection
{
   private static $Connection = null;

   public static function getConnection()
   {
      if(!isset(self::$Connection))
      {
         self::$Connection = new DBConnection();
      }
      return self::$Connection;
   }

   private function __construct()
   {

   }
}

$dbConnection = DBConnection::getConnection();

La raison pour laquelle vous pouvez / voudriez instancier la classe à partir d'elle-même est que vous pouvez vérifier qu'une seule instance existe à un moment donné.C’est tout l’intérêt d’un Singleton, après tout.L'utilisation d'un Singleton pour une connexion à une base de données garantit que votre application n'établit pas une tonne de connexions à la base de données à la fois.


Modifier: Ajout de $, comme suggéré par @emanuele-del-grande

Autres conseils

Voici un singleton très simple qui génère simplement une chaîne date/heure :

class TheDate
{
    private static $DateInstance = null;
    private $dateVal;

    public static function getDateInstance()
    {
        if(!isset(self::$DateInstance))
        {
            self::$DateInstance = new TheDate();
        }

        return self::$DateInstance;
    }

    public static function getDateVal()
    {
        return self::$DateInstance->dateVal;
    }

    private function __construct()
    {
        $this->dateVal = strftime("%Y-%m-%d %H:%M:%S");
    }
}

Faire quelque chose comme ça me donne évidemment la même date encore et encore :

$date1 = TheDate::getDateInstance();
echo $date1->getDateVal() . "<br />";

$date2 = TheDate::getDateInstance();
echo $date2->getDateVal() . "<br />";

Et cela ne génère aucune erreur :

class NewDate extends TheDate
{
    public function __construct()
    {

    }
}

OK, j'ai fait mes propres tests.

  • Si vous ne déclarez pas votre propre constructeur dans la sous-classe, essayer de l'instancier générera une erreur fatale, car il essaie d'appeler le constructeur de la superclasse.
  • Dans le cas d'une connexion à une base de données, lorsque vous renvoyez probablement (en PHP, en tout cas) une instance mysqli ou la ressource renvoyée par le mysql_connect() fonction (ou un autre lien vers un autre SGBDR), tant que vous marquez l'instance comme privée, il n'y a aucune menace que quelqu'un la sous-classe et altère le lien.
  • Comme je l'ai déjà mentionné, si quelqu'un veut vraiment contourner votre comportement et établir plusieurs connexions, il pourrait tout aussi bien le faire en écrivant une nouvelle classe.

Testez le code, Mark, et faites-moi savoir ce que vous découvrez.

MODIFIER:De plus, dans cette situation particulière, je ne sais pas pourquoi vous devriez vous soucier d'empêcher une personne de sous-classer.Si quelqu'un a accès à votre code PHP pour le sous-classer, il a également accès à votre code pour le copier et modifier les modificateurs d'accès en quelque chose qu'il trouve (pour une raison quelconque) approprié.

L'utilité pratique du Singleton dans ce cas est qu'en l'utilisant, vous pouvez vous assurer que vous utilisez toujours la même connexion à la base de données pour une requête HTTP donnée.Cela accomplit cela.Les autres trucs (en utilisant final et constructeurs privés) est utile à connaître d'un point de vue théorique, et encore plus utile à savoir si vous souhaitez distribuer du code de qualité API à d'autres programmeurs, mais dans le cas de cet exemple particulier, tout ce que les mots-clés font est d'ajouter des octets à la taille de votre fichier de classe.

Un peu de brouillon :Pour être complet, vous feriez probablement déclarer la classe comme finale aussi, car vous ne voudriez pas que quelqu'un sous-classe cette classe et implémente son propre constructeur public.

(Pardonnez-moi si le compilateur détecte le remplacement d'un constructeur privé, mais je ne pense pas que ce soit le cas)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top