Sympathizer: Ermitteln, wer den Konstruktor aufgerufen hat

Hallo,

ich habe eine Factory-Klasse, die mir die Singleton-Instanz der
Datenbankschicht liefert. In dem Konstruktor dieser DB-Klasse
moechte ich nun sicherstellen, dass eben jene Klasse ueber die
Factory-Methode initialisiert wurde - und nicht von einer beliebig
anderen Klasse, Datei oder Funktion.
Wie ist das moeglich?

Besten Dank.

Mit freundlichen Gruessen,
Sympathizer

--
"Was ist ist, was nicht ist ist moeglich"
  1. Hi,

    ich denke nur indirekt ueber die Auswertung von debug_backtrace();

    Schau dir die Dokumentation dazu auf php.net an.

    Eine elegante(re) Loesung is mir nicht bekannt.

    1. Hallo,

      erstmal Danke fuer deine Antwort.
      Aber so ganz zufrieden stellt mich das irgendwie auch nicht ;-(
      Denn man braucht lediglich ein Datei mit dem gleichen Namen zu
      erstellen, und die macht dann ganz einfach ein new SqlHandler().
      Naja, mal schauen ob es da noch was schoeneres - oder, wie du
      es ausgedrueckt hast: elegante(re)s - gibt.

        
      public function __construct()  
      {  
           // check whether this class was initialized by the factory method  
           $arr = debug_backtrace();  
           if(strpos($arr[0]["file"],"sql_factory.class.php")===false)  
            throw new Exception("Class is only allowed to be initialized by the sql_factory class.");  
           $this->Connect();  
      }  
      
      

      Wie auch immer, danke.

      Mit freundlichen Gruessen,
      Sympathizer

      --
      "Was ist ist, was nicht ist ist moeglich"
      1. Hi,

        lies dir nochmal die Beschreibung durch, du kannst das schon noch genauer machen als nur auf das file abzufragen, z.B. ueber die zuvor aufgerufene Funktion/Methode.

        Es wird die ja ein Stack zurueckgeliefert (daher "trace").

        Lass es dir einfach mal ausgeben mit var_dump(debug_backtrace()).

        Viel Erfolg!

  2. echo $begrüßung;

    ich habe eine Factory-Klasse, die mir die Singleton-Instanz der Datenbankschicht liefert.

    Du baust eine Fabrik für ein Einzelstück? Oder anders gefragt: Wenn ich mehrere ähnliche Dinge haben kann, warum darf ich dann keine gleichen Dinge haben?

    In dem Konstruktor dieser DB-Klasse moechte ich nun sicherstellen, dass eben jene Klasse ueber die Factory-Methode initialisiert wurde - und nicht von einer beliebig anderen Klasse, Datei oder Funktion.

    Im Allgemeinen verhindert man den Aufruf von Methoden, indem man sie als nicht öffentlich kennzeichnet. Mit so einer Kennzeichnung kümmmert sich PHP darum. Ohne eine solche bleibt dir nur der schon erwähnte Weg durch den Aufrufpfad.

    echo "$verabschiedung $name";

    1. Hi dedlfix,

      Im Allgemeinen verhindert man den Aufruf von Methoden, indem man sie als nicht öffentlich kennzeichnet. Mit so einer Kennzeichnung kümmmert sich PHP darum. Ohne eine solche bleibt dir nur der schon erwähnte Weg durch den Aufrufpfad.

      Wie wäre es mit hiermit?

      // Unsere Fabrik-Klasse  
      class Fabrik {  
        
        // Von der Fabrik-Klasse darf keine Instanz erzeugt werden!  
        private function __construct() {}  
        
        // in $objekt sollte ein gültiger Klassenname übergeben werde  
        static public function Erstelle($objekt) {  
          // Erstelle neue Instanz von sich selber  
          $fabrik = new self();  
          // hier wird die gewünschte Klasse erstellt und ihr die  
          // Fabrik übergeben  
          return new $objekt($fabrik);  
        }  
      }  
        
      // Beispiel-Klasse, welche von der Fabrik erstellt  
      // werden können soll  
      class FabriziertesObjekt {  
        
        // als erster Parameter muss ein Objekt der Fabrik-Klasse übergeben  
        public function __construct(Fabrik $fabrik) {  
          // hier folgt weiterer Code  
        }  
      }  
        
      // funktioniert  
      $obj = Fabrik::Erstelle('FabriziertesObjekt');  
        
      // funktioniert nicht, weil Fabrik nicht erstellt werden darf:  
      $fab = new Fabrik();  
        // Fatal error: Call to private Fabrik::__construct()  
        // from invalid context in [...]  
        
      // funktioniert nicht, weil Typ Fabrik erzwungen wird  
      $fab = new stdClass();  
      $obj = new FabriziertesObjekt($fab);  
        // Catchable fatal error: Argument 1 passed to FabriziertesObjekt::__construct()  
        // must be an instance of Fabrik, instance of stdClass given, called in  
        // [...] and defined in [...]
      

      Auf dieser Basis müsste man eigentlich arbeiten können...

      Viele Grüße,
        ~ Dennis.

      1. Hallo Dennis,

        ja, danke, das scheint mir eine saubere Basis zu sein.
        Wenn man das ganze noch mit einer weiteren Klasse kapselt, so
        dass dem Aufrufer der/die Name(n) der Klasse(n) nicht bekannt
        sein muss, hat man eine gute Loesung.

        Mit freundlichen Gruessen,
        Sympathizer

        --
        "Was ist ist, was nicht ist ist moeglich"
    2. Hallo,

      ich glaube wir scheinen einander vorbei zu reden ;)

      Wenn ich mehrere ähnliche Dinge haben kann, warum darf ich dann keine
      gleichen Dinge haben?

      Es geht mir um eine Datenbank-Klasse, von der - selbst in mehreren Threads -
      nur genau eine Instanz existieren darf. Dafuer gibt es viele Gruende;
      partikulare Steuerung des Connection-Pools, Zustandsbehaftung des
      Datenbank-Layers oder Caching von Resultsets.. um nur einige zu nennen.

      In dem Konstruktor dieser DB-Klasse moechte ich nun sicherstellen,
      dass eben jene Klasse ueber die Factory-Methode initialisiert wurde -
      und nicht von einer beliebig anderen Klasse, Datei oder Funktion.
      Im Allgemeinen verhindert man den Aufruf von Methoden, indem man sie als
      nicht öffentlich kennzeichnet. Mit so einer Kennzeichnung kümmmert sich
      PHP darum.

      Ich bin mit OOP bestens vertraut. Es geht mir wie gesagt um eine _Factory_-
      Klasse, ueber die - und _nur_ ueber die - die Klasse der Datenbankschicht
      initialisiert werden darf. Setze ich sie auf protected dann kann selbst die
      Factory-Klasse keine Instanz erstellen - ausser sie leitet sich von eben
      jener Klasse ab.. aber das wuerde im Falle einer Factory natuerlich keinen
      Sinn ergeben.

      Dennoch Danke fuer deine Antwort.

      Mit freundlichen Gruessen,
      Sympathizer

      --
      "Was ist ist, was nicht ist ist moeglich"
      1. echo $begrüßung;

        Es geht mir um eine Datenbank-Klasse, von der - selbst in mehreren Threads - nur genau eine Instanz existieren darf.

        Warum du eine Fabrik brauchst, habe ich immer noch nicht verstanden. Eine Fabrik setzt man doch ein, wenn man ihr sagen will: Produziere('Mutter'); Produziere('Schraube'); usw. Sie produziert bei jedem Aufruf das gewünschte Teil. Wenn du sie zweimal mit 'Mutter' aufrufst, hast du zwei Muttern. Wenn du sie einmal mit 'Mutter' und einmal mit 'Schraube' aufrufst, hast du auch zwei Teile.
        Möchtest du stattdessen nur ein einziges Teil von der Fabrik produziert haben? Wenn der erste Aufruf eine Mutter verlangt, der zweite aber eine Schraube, was soll deine Fabrik dann machen? Die selbe Mutter des ersten Aufrufs rausrücken? Wenn ja, dann scheint mir dieser Wunsch nicht im Sinne einer Fabrik zu sein. Oder möchtest du bei 'Mutter' immer die selbe Mutter, bei 'Schraube' aber eine Schraube, und zwar immer die selbe, so dass du nun bis zu zwei Objekte haben kannst, von denen das eine die Mutter und das andere die Schraube ist?

        Und was haben Threads mit PHP zu tun? In welchem Umfeld läuft denn dein PHP, außerhalb des üblichen Webserver-Umfelds?

        Deine "eine Datenbank-Klasse, von der"-Formulierung in der Einzahl und mit dem bestimmten Artikel "der" liest sich für mich, als ob du einfach nur ein ganz normales Singleton haben möchtest.
        Oder möchtest du ein Repository haben, das von verschiedenartigen Dingen genau eine Instanz rausrückt, die es sich jedoch erst beim Erstverlangen besorgt (instantiiert)?

        echo "$verabschiedung $name";