Carl: Connection-Handle global verwenden

Hallo,

ich habe ein Problem mit mysqli.
Bei jedem Query muss so wie ich das verstehe der Rückgabewert der Verbindung mit übergeben werden. Aber: Diesen Wert habe ich nicht immer "zur Hand", insbesondere wenn ich mich in verschiedenen Klassen bewege. Natürlich könnte ich bei jedem Funktionsaufruf die Variable mit übergeben, aber das erscheint mir etwas umständig. Ich habe auch schon darüber nachgedacht der Wert in einer Sessionvariable zu übergeben, aber da bin ich mir nicht sicher, ob das der performanteste Weg ist.
Hat jemand von euch eine gute Lösung für mich?

Gruß
Carl

  1. echo $begrüßung;

    Bei jedem Query muss so wie ich das verstehe der Rückgabewert der Verbindung mit übergeben werden. Aber: Diesen Wert habe ich nicht immer "zur Hand", insbesondere wenn ich mich in verschiedenen Klassen bewege. Natürlich könnte ich bei jedem Funktionsaufruf die Variable mit übergeben, aber das erscheint mir etwas umständig.

    Hat jemand von euch eine gute Lösung für mich?

    Ob du sie auch gut findest, musst du selbst entscheiden :-)

    Ich entnehme deiner Beschreibung, dass du deine Datenbankverbindung einmal irgendwo "oben" geöffnet und deine Datenbankabfragen quer über das restliche Script verteilt hast.

    Ich kann mir mehrere Möglichkeiten vorstellen, dein Problem zu umgehen, aber alle laufen mehr oder weniger auf das Singleton-Muster hinaus. Ein Muster (Pattern) ist keine konkrete Implementation einer Lösung, sondern nur eine Art und Weise, ein Problem zu lösen. Singleton liefert allen Anfragenden die selbe Instanz eines Dinges. Gibt es dieses Ding noch nicht, wird es erzeugt, ansonsten wird immer nur diese eine erzeugte Instanz geliefert.

    Du könntest dir eine Funktion schreiben, die ein Datenbankhandle zurückgibt

    funktion dbConnection() {  
      static $conn = null;  
      
      if ($conn == NULL)  
        $conn = initialisierung();  
      
      return $conn;  
    }
    

    Das Connectionhandle wird in der statischen lokalen Variable $conn gespeichert, deren Inhalt auch dann erhalten bleibt, wenn die Funktion verlassen wird. $conn ist aber außerhalb der Funktion nicht ansprechbar. An allen Stellen, an denen du nun das DB-Handle brauchst, übergibst du es durch den Aufruf von dbConnection. (Funktionsaufrufe sind ja auch nicht durch Variablengültigkeitsbereiche eingeschränkt.)

    $result = query(dbConnection(), ...);

    Eine Grundinitialisierung im Script wird nicht benötigt, denn das erledigt dbConnection() bei Bedarf.

    Soweit die Lösung mit dem wenigsten Umstellungsaufwand deiner bisherigen Scripte. Da du aber sowieso schon mit Klassen arbeitest, bietet es sich eigentlich an, mit mysqli im OOP-Stil zu arbeiten, und nicht prozedural. Und auch hier bietet sich das Singleton-Muster an, eine Funktion oder statische Methode zu erstellen, die man mit der Lieferung und ggf. Erzeugung einer Instanz beauftragen kann.

    Eine weitere Möglichkeit ist, eine Datenbankabstraktionsschicht in die Anwendung einzubauen, um damit wieder mehr datenbankspezifischen Code von der eigentlichen Anwendungslogik zu entfernen. Das kann man soweit treiben, dass die Anwendung am Ende gar nicht mehr mitbekommt, wer der eigentliche Datenlieferant ist. Man ruft nur noch eine Funktion/Methode (ggf. mit Parametern) auf und erhält die Daten in bereits abgepackter Form (z.B. Array).

    echo "$verabschiedung $name";

    1. Hallo Freunde des gehobenen Forumsgenusses,

      Du könntest dir eine Funktion schreiben, die ein Datenbankhandle zurückgibt

      funktion dbConnection() {

      static $conn = null;

      if ($conn == NULL)
          $conn = initialisierung();

      return $conn;
      }

        
      Das ist eine wunderschöne Methode, nur eine einzige Datenbank-Verbindung zu erstellen und damit Rechenzeit und Speicher zu sparen, nur leider geht das erst ab PHP 5, weil PHP 4 keine statischen Klasseneigenschaften kennt.  
        
      Gruß  
      Alexander Brock
      
      -- 
      ![A](http://alexanderbrock.de/img/pavatar.png)  
      [V-Text-Categorizer - Ein Klasse in PHP, die Text anhand von Statistiken über Texte in Kategorien sortiert (z.B. in Spam und nicht-Spam).](http://alexanderbrock.de/v-text-categorizer/)
      
      1. echo $begrüßung;

        funktion dbConnection() {

        static $conn = null;

        Das ist eine wunderschöne Methode, nur eine einzige Datenbank-Verbindung zu erstellen und damit Rechenzeit und Speicher zu sparen, nur leider geht das erst ab PHP 5, weil PHP 4 keine statischen Klasseneigenschaften kennt.

        Du irrst hier ein wenig. Selbst wenn diese Funktion Bestandteil einer Klasse wäre, ist $conn nur eine lokale aber statische Variable, keine Klassenvariable. [link:http://de.php.net/manual/en/language.variables.scope.php#language.variables.scope.static@title=Statische Variablen in Funktionen] (und Methoden) gab es bereits in PHP 4. Als Klassenvariable hätte sie in einer Klasse, aber außerhalb einer Methode deklariert werden müssen. Beides im Beispiel:

        [code lang=php]class Test {

        static $baz;  // statische Klassenvariable, ab PHP 5 verwendbar

        function foo() {
            static $bar; // lokale statische Variable, bereits in PHP4 verwendbar
            ...
          }
        }

          
          
        echo "$verabschiedung $name";
        
    2. Hi

      erstmal danke.

      funktion dbConnection() {

      static $conn = null;

      if ($conn == NULL)
          $conn = initialisierung();

      return $conn;
      }

        
      Das wirklich eine gute Idee, aber leider klappts bei mir nicht so ganz mit der Umsetztung :)  
        
      So sieht die Klasse im Moment bei mir aus:  
        
      ~~~php
        
      class Database  
      {  
       function db_connect()  
       {  
        @$db = new MySQLi($DBCONFIG['host'], $DBCONFIG['user'], $DBCONFIG['pass'], $DBCONFIG['db_name']);  
        
        if(mysqli_connect_errno())  
        {  
         //Fehlermeldung  
        }  
        else  
        {  
         return $db;  
        }  
       }  
        
       function get_conn()  
       {  
        static $conn = NULL;  
        
        if($conn == NULL)  
         $conn = $this->db_connect();  
        
        return $conn;  
       }  
      }  
        
      
      

      Das Problem: Beim Aufruf bekomme ich folgende Fehlermeldung zurück:

      Fatal error: Using $this when not in object context in C:\Programme\xampp\htdocs\game\sitefiles\siteclasses\db.gameclass.php on line 33

      Habe leider weder im Archiv noch bei Google eine richtige Erklärung dieser Fehlermeldung finden können, aber nach allem was ich gelesen habe scheint dieser Aufruf der Methode aus einer Anderen heraus richtig zu sein, oder?

      Gruß
      Carl

      1. echo $begrüßung;

        Das Problem: Beim Aufruf bekomme ich folgende Fehlermeldung zurück:
        Fatal error: Using $this when not in object context in C:\Programme\xampp\htdocs\game\sitefiles\siteclasses\db.gameclass.php on line 33

        Der Aufruf erfolgt also in dieser Form:

        $carls_db_connection = Database::get_conn();

        Wenn du eine Methode einer Klasse statisch aufrufst, dann existiert keine Instanz, die mit $this angesprochen werden kann. Alle Bezüge auf Methoden der Klasse innerhalb dieser statischen Methode müssen ebenfalls statisch notiert werden. Statt

        $conn = $this->db_connect();

        notierst du

        $conn = Database::db_connect();

        oder mehr PHP-5-like:

        $conn = self::db_connect();

        Zusatz-Information:
        Wenn man aus einem statischen Methodenaufruf auf Eigenschaften der Klasse zugreifen will, können das nur statische Eigenschaften sein. Siehe Kapitel Static Keyword.

        Ein Verbesserungsvorschlag:
        Da du mit PHP5 arbeitest (mysqli gibt es ja unter PHP4 nicht) kannst du das eleganter lösen. Die lokale statische Variable $conn brauchst du nicht, denn es gibt statische Klassenvariablen. Du kannst eigentlich auch die Methode ganz einsparen.

        class Database {  
          
          private static $db = false;  
          
          public static function db_connect() {  
            if (!self::$db) {  
              @self::$db = new MySQLi($DBCONFIG['host'], $DBCONFIG['user'], $DBCONFIG['pass'], $DBCONFIG['db_name']);  
          
            if (mysqli_connect_errno()) {  
              self::$db == false;  
              throw new Exception(mysqli_connect_error());  
            }  
            return self::$db;  
          }  
          
        }  
          
        ...  
          
        try {  
          $carls_db_connection = Database::db_connect();  
          ...  
        } catch (Exception $ex) {  
          echo 'Fehler: ', $ex->getMessage();  
        }
        

        Es ist nicht Aufgabe der db_connect-Methode eine Fehlermeldung auszugeben, da diese Methode nicht weiß, in welchem Kontext sie aufgerufen wurde, und ob dort die Ausgabe einer Fehlermeldung erwünscht ist. Deswegen lasse ich den Fehlerzustand durch das Auslösen einer Exception signalisieren. Die Exception wird dann vom aufrufenden Teil behandelt. Hier kann sie ausgegeben werden, ins Logfile geschreiben werden, usw.

        Beachte auch die Deklaration von $db mit vorangehendem "private". Damit wird ein Direktzugriff verhindert. Dieser ist unerwünscht, weil dabei nicht garantiert werden kann, dass sich darin ein gültiges mysqli-Objekt befindet.

        echo "$verabschiedung $name";