40 votes

Dans une classe PHP5, quand un constructeur privé est-il appelé?

Disons que j'écris une classe PHP (> = 5.0) qui est 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 instanciée directement.

Donc, si j'ai quelque chose comme ça:

 class SillyDB
{
  private function __construct()
  {

  }

  public static function getConnection()
  {

  }
}
 

Y a-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 de l'intérieur de lui-même?

65voto

Brian Warshaw Points 8806

__construct() ne serait que de l'appeler si vous l'avez appelé dans une méthode de la classe contenant le constructeur privé. Donc, pour votre Singleton, vous pouvez avoir une méthode comme suit:

class DBConnection
{
   private static $Connection = null;

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

   private function __construct()
   {

   }
}

$dbConnection = DBConnection::getConnection();

La raison vous pouvez/souhaitez instancier la classe de l'intérieur lui-même est de sorte que vous pouvez vérifier pour s'assurer qu'une seule instance existe à un moment donné. C'est le point de l'ensemble d'un Singleton, après tout. À l'aide d'un Singleton pour une connexion de base de données permet de garantir que votre application n'est pas en faisant une tonne de DB connexions à la fois.

5voto

Mark Biek Points 41769

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

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

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

        return TheDate::$DateInstance;
    }

    public static function getDateVal()
    {
        return TheDate::$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()
    {

    }
}
 

4voto

Brian Warshaw Points 8806

OK, j'ai couru quelques tests de mon propre.

  • Si vous ne déclarez pas votre propre constructeur de la classe, en essayant de les instancier qu'il va jeter une erreur fatale, car elle tente d'appeler le constructeur de la superclasse.
  • Dans le cas d'une connexion DB, quand vous êtes probablement de retour (en PHP, de toute façon) un mysqli instance ou de la ressource retournée par l' mysql_connect() de la fonction (ou un autre lien vers un autre SGBD), aussi longtemps que vous marquez l'instance privée, il n'y a pas de menace de quelqu'un sous-classement et l'altération de la liaison.
  • Comme je l'ai mentionné avant, si quelqu'un veut vraiment tenir compte de votre comportement et de faire de multiples connexions, ils pourraient tout aussi bien le faire par l'écriture d'une nouvelle classe.

2voto

Brian Warshaw Points 8806

Tester le code, Marque, et laissez-moi savoir ce que vous trouver.

EDIT: Aussi, dans cette situation particulière, je ne suis pas sûr de savoir pourquoi vous avez besoin de se préoccuper de la prévention d'une personne à partir de sous-classement. Si quelqu'un a accès à votre code PHP à la sous-classe, puis ils ont également accès à votre code à copier et de le modifier modificateurs d'accès à quelque chose qu'ils (pour quelque raison que ce soit) conviennent.

L'utilité pratique de l'Singleton dans ce cas, c'est que, en l'utilisant, vous pouvez vous assurer que vous êtes toujours en utilisant la même connexion à la base de donnée de la requête HTTP. Il accomplit cela. Les autres trucs (à l'aide d' final et les constructeurs privés) est utile de savoir à partir d'une perspective de la théorie, et même plus utile de savoir si vous souhaitez distribuer API code de qualité à d'autres programmeurs, mais dans le cas de cet exemple particulier, tous les mots clés, est l'ajout d'octets à votre fichier de classe de taille.

1voto

Allain Lalonde Points 28717

Un petit choix: Pour être complet, vous déclareriez probablement 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 intercepte la surcharge d'un constructeur privé, mais je ne pense pas que ce soit le cas)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X