Chris: Komplettes Projekt in OOP v2

0 77

Komplettes Projekt in OOP v2

Chris
  • php
  1. 0
    Patrick Figel
  2. 0
    Sympathisant
    1. 0
      Chris
      1. 0
        Sympathisant
        1. 0
          Sven Rautenberg
          1. 0
            Sympathisant
      2. 1
        Sven Rautenberg
        1. 0
          dedlfix
      3. 0
        CHris
  3. 0
    Tom
    1. 0
      Chris
      1. 0
        Tom
      2. 0
        Sympathisant
        1. 0
          Tom
          1. 0
            Sven Rautenberg
            1. 0
              Tom
              1. 0
                Sympathisant
                1. 0
                  Tom
                  1. 0
                    Tom
                    1. 0
                      Sympathisant
                      1. 0
                        Tom
                        1. 0
                          dedlfix
                    2. 0
                      dedlfix
                  2. 0
                    Sympathisant
                    1. 0
                      Tom
                      1. 0
                        Sympathisant
                2. 0
                  Sven Rautenberg
                  1. 0
                    Tom
                    1. 0
                      dedlfix
                3. 0
                  dedlfix
                  1. 0
                    Sympathisant
                    1. 0
                      dedlfix
                      1. 0
                        Sympathisant
              2. 0
                dedlfix
                1. 0
                  Tom
          2. 0
            Sympathisant
        2. 0
          dedlfix
    2. 0
      dedlfix
      1. 0
        Tom
        1. 0
          dedlfix
          1. 0
            Tom
            1. 0
              dedlfix
              1. 0
                Tom
  4. 0

    PDF-Doku für OOP mit PHP5

    Tom
    1. 0
      dedlfix
      1. 0
        Tom
        1. 0
          dedlfix
  5. 0

    Und noch ein eBook für PHP OOP

    Tom
  6. 4
    dedlfix
    1. 0
      Tom
      1. 0
        dedlfix
  7. 0
    Chris
    1. 0
      dedlfix
      1. 0
        Chris
        1. 0
          Tom
          1. 0
            Chris
            1. 0
              Sympathisant
              1. 0
                Tom
        2. 0
          dedlfix
      2. 0
        Chris
        1. 0
          dedlfix
          1. 0
            Chris
            1. 0
              dedlfix
              1. 0
                Chris
                1. 1
                  dedlfix
                  1. 0
                    Chris
                    1. 0
                      dedlfix
                      1. 0
                        Chris
                        1. 0
                          dedlfix
                          1. 0
                            Chris
                            1. 0
                              Tom
                              1. 0
                                dedlfix
                            2. 0
                              dedlfix
                              1. 0
                                Chris
                                1. 0
                                  dedlfix
                                  1. 0
                                    Chris

Hallo.

Fortsetzung von Komplettes Projekt in OOP.
Ich rufe hiermit den großen Dedlfix und Co. auf, mich weiterhin zu unterstützen ;).

Ich hatte private Probleme die letzten Tage und konnte mich deshalb nicht mehr darum kümmern.

Hier ein erster Anlauf aber ich hab direkt Probleme mit der DB-Klasse:

  
class db{  
  
	private static $instance;  
	public static $db_host;  
	public static $db_user;  
	public static $db_pw;  
	public static $db_name;  
	public static $db_connection;  
	  
	  
	  
	# Konstruktor - private - kann nicht aufgerufen werden  
	private function __construct(){}  
	  
	# Singleton  
	public static function db_singleton()  
    {  
        if (!isset(self::$instance)) {  
            $c = __CLASS__;  
            self::$instance = new $c;  
        }  
  
        return self::$instance;  
    }  
	  
	  
	# Datenbankwerte setzen  
	public function db_set_vars($host,$name,$pw,$dbname){  
		$db_host=$host;  
		$db_user=$user;  
		$db_pw=$pw;  
		$db_name=$dbname;  
		  
	}  
	  
	  
	# Zur Datenbank verbinden  
	public function db_connect()  
    {  
       $db_connection = new MySQLi($db_host,$db_user,$db_pw,$db_name);  
	   if (mysqli_connect_errno()) {  
   			printf("Connect failed: %s\n", mysqli_connect_error());  
    		exit();  
	   } else {  
	   		echo "alles korrekt";  
	   }  
    }  
	  
	  
	# Query ausführen  
	public function db_query($query){  
		$db_connection->query($query);  
	}  
  
}  
  
db::db_set_vars('localhost','root','philz','allethemen');  
db::db_connect();  
$user="name";  
$pw="pw";  
$sql="INSERT INTO users(user,pw) VALUES('".$user."','".$pw."')";  
db::db_query($sql);  
  

Fehler:
alles korrekt
Fatal error: Call to a member function query() on a non-object in C:\xampp\htdocs\_next\allethemen\classes\class.db.php on line 52

Line: 52 $db_connection->query($query);

Was ist denn daran falsch? Warum ist es kein Objekt, ich habe es doch oben als Objekt instanziert:

$db_connection = new MySQLi($db_host,$db_user,$db_pw,$db_name);

und er gibt auch "alles korrekt" aus.

Ich komm nicht weiter.

Lg, Chris

  1. Um die (statischen) Eigenschaften der Klasse anzusprechen, musst du self::$propertyName (also in deinem Fall self::$db_connection) verwenden. Wenn du innerhalb einer Methode das MySQLi-Objekt mit $db_connection = new ... instanzierst, handelt es sich bei $db_connection um eine lokale Variable im Methoden-Kontext und nicht um die Eigenschaft der Klasse.

    Bei nicht-statischen Eigenschaften funktioniert das ganze übrigens mit $this->propertyName.

  2. Hai Chris,

    auch wenn ich den urspruenglichen Thread nicht verfolgt habe, faellt mir bei deinem Code direkt folgendes auf:

    »» private function __construct(){}  
    
    > public static function db_singleton()  
    > public function db_set_vars($host,$name,$pw,$dbname){  
    > public function db_connect()  
    > public function db_query($query){
    
    

    Die einzige Funktion, welche als Static deklariert ist, ist die Singleton-Methode. Jedoch machst Du weiter unten im Code:

    »» db::db_set_vars('localhost','root','philz','allethemen');  
    
    > db::db_connect();  
    > $user="name";  
    > $pw="pw";  
    > $sql="INSERT INTO users(user,pw) VALUES('".$user."','".$pw."')";  
    > db::db_query($sql);
    
    

    Die Aufrufe muessen mit der _Instanz_ der DB-Klasse erfolgen.
    Also

    $db = [hier_die_Instanz_erstellen];  
    $db->db_set_vars('localhost','root','philz','allethemen');  
    $db->db_connect();  
    $db->db_query($sql);
    

    MfG,
    Sympatisant

    --
    "If the future isn't bright, at least it is colorful"
    1. Hi,

      ich habs mal geändert, klappt aber immernoch nicht:

      class db{  
        
      	private static $instance;  
      	public static $db_host;  
      	public static $db_user;  
      	public static $db_pw;  
      	public static $db_name;  
      	public static $db_connection;  
      	  
      	  
      	  
      	# Konstruktor - private - kann nicht aufgerufen werden  
      	private function __construct(){}  
      	  
      	# Singleton  
      	public static function db_singleton()  
          {  
              if (!isset(self::$instance)) {  
                  $c = __CLASS__;  
                  self::$instance = new $c;  
              }  
        
              return self::$instance;  
          }  
      	  
      	# Datenbankwerte setzen  
      	public static function db_set_vars($host,$name,$pw,$dbname){  
      		$db_host=$host;  
      		$db_user=$user;  
      		$db_pw=$pw;  
      		$db_name=$dbname;  
      		  
      	}  
      	  
      	  
      	# Zur Datenbank verbinden  
      	public static function db_connect()  
          {  
             $db_connection = new MySQLi($db_host,$db_user,$db_pw,$db_name);  
      	   if (mysqli_connect_errno()) {  
         			printf("Connect failed: %s\n", mysqli_connect_error());  
          		exit();  
      	   } else {  
      	   		echo "alles korrekt";  
      	   }  
          }  
      	  
      	  
      	# Query ausführen  
      	public static function db_query($query){  
      		$db_connection->query($query);  
      	}  
        
        
      $db=db::db_singleton();  
      $db->db_set_vars('localhost','root','philz','allethemen');  
      $db->db_connect();  
      $user="name";  
      $pw="pw";  
      $sql="INSERT INTO users(user,pw) VALUES('".$user."','".$pw."')";  
      $db->db_query($sql);  
        
      
      

      Ausgabe ist immernoch:

      alles korrekt
      Fatal error: Call to a member function query() on a non-object in

      Muss ich die db_connect Funktion irgendwie in die Singleton-Fkt. einbeziehen?

      lg,

      chris

      1. Hai chris,

        wie ich bereits geschrieben habe solltest du dein Konzept in Bezug auf die Datenbankverbindungsdaten noch mal ueberdenken.

        Nichts destro trotz - des Fehler wegen - hier die Erklaerung der Fehlermeldung:

        class db{  
          public static $db_connection;  
          
          public static function db_query($query){  
            $db_connection->query($query);  
          }  
        
        

        Du greifst auf eine nicht vorhandene Variable zu. $db_connection existiert in dem Scope nicht. In deinem Falle muesste es self::$db_connection heissen. Also:

          
        public static function db_query($query){  
            self::$db_connection->query($query);  
        }  
        
        

        Allerdings sei noch erwaehnt, dass es an dieser Stelle zu einer Nullpointer-Exception kommen kann. Naemlich genau dann, wenn die db_connect()-Methode vorher nicht aufgerufen wuerde.

        MfG,
        Sympatisant

        --
        "If the future isn't bright, at least it is colorful"
        1. Moin!

          Du greifst auf eine nicht vorhandene Variable zu. $db_connection existiert in dem Scope nicht. In deinem Falle muesste es self::$db_connection heissen.

          Das Singleton-Pattern arbeitet - außer in der getInstance-Methode - nicht mit statischen Methoden und Eigenschaften - zumindest kann man sich, wenn man den ganzen Kram statisch macht, eigentlich die Singleton-Methoden sparen.

          public static function db_query($query){
              self::$db_connection->query($query);
          }

          
          >   
          > Allerdings sei noch erwaehnt, dass es an dieser Stelle zu einer Nullpointer-Exception kommen kann. Naemlich genau dann, wenn die db\_connect()-Methode vorher nicht aufgerufen wuerde.  
            
          Nullpointer in PHP? Hm....  
            
           - Sven Rautenberg
          
          1. Hai Sven,

            Das Singleton-Pattern arbeitet - außer in der getInstance-Methode - nicht mit statischen Methoden und Eigenschaften - zumindest kann man sich, wenn man den ganzen Kram statisch macht, eigentlich die Singleton-Methoden sparen.

            Das sehe ich auch so, es ging mir lediglich um die Fehlermeldung. Die Vermischung von statischen Properties und Singleton ist in seinem Beispiel nicht gerade gut gewaehlt.

            Nullpointer in PHP? Hm....

            Ja, is' ja schon gut.. ;-) Aber ich nehme an, dass jeder etwas damit anfangen kann.. ob Java oder nicht.

            MfG,
            Sympatisant

            --
            "If the future isn't bright, at least it is colorful"
      2. Moin!

        class db{

        private static $instance;

        Diese Variable willst du nur protected haben, weil sie ggf. weitervererbt werden soll, wenn du die Klasse db erweiterst.

        public static $db_host;
        public static $db_user;
        public static $db_pw;
        public static $db_name;
        public static $db_connection;

        Diese ganzen Variablen gehören ebenfalls protected. Und als Namenskonvention: Protected- und Private-Variablen schreibt man mit einem Unterstrich als erstem Zeichen. Dann sieht man ihnen auf den ersten Blick ihre nichtöffentliche Zugriffsmöglichkeit an.

        Konstruktor - private - kann nicht aufgerufen werden

        private function __construct(){}

        Dasselbe gilt für den Konstruktor. Protected, nicht private.

        Datenbankwerte setzen

        public static function db_set_vars($host,$name,$pw,$dbname){
        $db_host=$host;
        $db_user=$user;
        $db_pw=$pw;
        $db_name=$dbname;
        }

        Schon mal überlegt, was diese Funktion macht? Sie kopiert Daten - aber nicht in die Variablen der Klasse, sondern nur in lokale Variablen der Funktion!

        Zur Datenbank verbinden

        public static function db_connect()
            {
               $db_connection = new MySQLi($db_host,$db_user,$db_pw,$db_name);

        Schon mal überlegt, wo diese Variablen herkommen? Mit Error-Level E_ALL hättest du hier viermal NOTICE gekriegt, weil du auf uninitialisierte lokale Variablen zugreifst.

        if (mysqli_connect_errno()) {
            printf("Connect failed: %s\n", mysqli_connect_error());
             exit();

        Ein sehr uneleganter Ausstieg. Aber das kriegen wir später... :)

        } else {
            echo "alles korrekt";
           }
            }

        Query ausführen

        public static function db_query($query){
        $db_connection->query($query);

        Ebenfalls gilt hier: Worauf greifst du in Form von $db_connection zu? Tipp: Es ist nicht die in dem Objekt gespeicherte Variable $this->db_connection ... ;)

        }

          
         - Sven Rautenberg
        
        1. echo $begrüßung;

          » private static $instance;
          Diese Variable willst du nur protected haben, weil sie ggf. weitervererbt werden soll, wenn du die Klasse db erweiterst.

          Nein, will er nicht. Singleton und Vererbung schließen sich gegenseitig aus. Prinzipiell. Man kann nicht von einer Klasse nur eine einzelne Instanz haben wollen und dann per Vererbung dafür sorgen, dass neben ihr ein Kind erzeugt werden kann.

          Die anderen Empfehlungen zu protected statt private sind damit auch hinfällig.

          echo "$verabschiedung $name";

      3. Jetzt hab ich eure Ratschläge mal beachtet:

          
        error_reporting((E_ALL | E_STRICT));  
        ini_set('display_errors', 1);  
          
        class db{  
          
        	protected static $_instance;  
        	protected static $_db_host;  
        	protected static $_db_user;  
        	protected static $_db_pw;  
        	protected static $_db_name;  
        	protected static $_db_connection;  
        	  
        	  
        	  
        	# Konstruktor - private - kann nicht aufgerufen werden  
        	private function __construct(){}  
        	  
        	# Singleton  
        	protected static function db_singleton()  
            {  
                if (!isset(self::$instance)) {  
                    $c = __CLASS__;  
                    self::$instance = new $c;  
                }  
          
                return self::$instance;  
            }  
        	  
        	# Datenbankwerte setzen  
        	public static function db_set_vars($host,$name,$pw,$dbname){  
        		self::$db_host=$host;  
        		self::$db_user=$user;  
        		self::$db_pw=$pw;  
        		self::$db_name=$dbname;  
        		  
        	}  
        	  
        	  
        	# Zur Datenbank verbinden  
        	public static function db_connect()  
            {  
               self::$db_connection = new MySQLi($_db_host,$_db_user,$_db_pw,$_db_name);  
        	   if (mysqli_connect_errno()) {  
           			printf("Connect failed: %s\n", mysqli_connect_error());  
            		exit();  
        	   } else {  
        	   		echo "alles korrekt";  
        	   }  
            }  
        	  
        	  
        	# Query ausführen  
        	public static function db_query($query){  
        		self::$db_connection->query($query);  
        	}  
        }  
          
        $db=db::db_singleton();  
        $db->db_set_vars('localhost','root','pw','dbname');  
        $db->db_connect();  
        $user="name";  
        $pw="pw";  
        $sql="INSERT INTO users(user,pw) VALUES('".$user."','".$pw."')";  
        $db->db_query($sql);  
        
        

        Fehlermeldung:

        Fatal error: Call to private method db::db_singleton() from context '' in

        Es ist ihm auch latte ob ich die Singletonfkt auf private setze.

        Hab einiges ausprobiert aber klappt nicht.

        Lg,

        Chris

  3. Hello Chris,

    Du fängst gleich mit einem richtigen Hammer an. Das ist nicht unbedingt Förderlich, um die Zusammenhänge zu verstehen.

    unter http://www.flashbattle.de/forumv2/thread.php?threadid=3751

    ist mMn ein gutes Beispiel für den Anfang zu finden.

    • Eigenschaften der Klasse sollten nicht public sein

    • Der Konstruktor sollte die wichtigste Aufgabe der Klasse bei der Instantiierung übernehmen,
        also hier das Beschaffen der Zugangsdaten und den Erstaufbau der Datenbank-Verbindung.

    • Der Destruktor sollte für ein geeordnetes Lebensende der Klasse sorgen, also hier das
        Beenden der Datenbankverbindung.

    usw.

    Liebe Grüße aus dem Cyberspace

    Tom vom Berg

    --
    Nur selber lernen macht schlau
    http://bergpost.annerschbarrich.de
    1. Hallo Tom.

      • Eigenschaften der Klasse sollten nicht public sein

      Okay dann werde ich die Datenbank Daten static aber nicht Publik lassen.

      • Der Konstruktor sollte die wichtigste Aufgabe der Klasse bei der Instantiierung übernehmen,
          also hier das Beschaffen der Zugangsdaten und den Erstaufbau der Datenbank-Verbindung.

      Aber es soll doch eine Singleton Klasse sein.

      • Der Destruktor sollte für ein geeordnetes Lebensende der Klasse sorgen, also hier das
          Beenden der Datenbankverbindung.

      Den Destruktor habe ich rausgelassen weil er nichts mit meinem Problem atm zu tun hat.
      lg, Chris

      1. Hello,

        Aber es soll doch eine Singleton Klasse sein.

        Das habe ich zwar gesehen, aber nicht wirklich registriert, sorry.
        Bei einer Datenbankklasse halte ich das auch nicht für unbedingt sinnvoll.
        Mehrere Verbindungen zur Datenbank oder unterschiedlichen Datenbanken können durchaus sinnvoll sein.

        Aber zum Üben ist alles erlaubt ;-)

        siehe http://www.talkphp.com/advanced-php-programming/1304-how-use-singleton-design-pattern.html

        Liebe Grüße aus dem Cyberspace

        Tom vom Berg

        --
        Nur selber lernen macht schlau
        http://bergpost.annerschbarrich.de
      2. Hai Chris,

        »» - Eigenschaften der Klasse sollten nicht public sein

        Es kommt darauf an. Man kann sie durchaus public setzen und dann mittels Overloading entsprechend intervenieren. Somit spart man sich die Getter- und Setter-Methoden fuer Properties, die keine weiteren Behandlungen benoetigen.

        Okay dann werde ich die Datenbank Daten static aber nicht Publik lassen.

        Irgendwie ist da ein wenig der Wurm drin ;)
        Zum einen ergibt es recht wenig Sinn die Datenbankverbindungsdaten als static zu deklarieren. Denn wenn eine Connection einmal anhand dieser Daten erstellt wurde dann ist das nachtraegliche Aendern dieser Daten wirkungslos.
        Du koenntest die benoetigten Werte als Parameter der connect()-Methode definieren und somit auf die db_set_vars-Methode verzichten.

        »»   also hier das Beschaffen der Zugangsdaten und den Erstaufbau der Datenbank-Verbindung.
        Aber es soll doch eine Singleton Klasse sein.

        Siehe oben.

        »» - Der Destruktor sollte für ein geeordnetes Lebensende der Klasse sorgen, also hier das
        »»   Beenden der Datenbankverbindung.

        Mit der Verwendung von Destruktoren unter PHP muss man recht achtsam sein, denn "The destructor method will be called as soon as all references to a particular object are removed or when the object is explicitly destroyed or in any order in shutdown sequence.". Und ein Aufrufer wird nur in den seltesten Faellen mueszig genug sein und den Destruktor explizit aufrufen.

        MfG,
        Sympatisant

        --
        "If the future isn't bright, at least it is colorful"
        1. Hello,

          »» - Der Destruktor sollte für ein geeordnetes Lebensende der Klasse sorgen, also hier das
          »»   Beenden der Datenbankverbindung.
          Mit der Verwendung von Destruktoren unter PHP muss man recht achtsam sein, denn "The destructor method will be called as soon as all references to a particular object are removed or when the object is explicitly destroyed or in any order in shutdown sequence.". Und ein Aufrufer wird nur in den seltesten Faellen mueszig genug sein und den Destruktor explizit aufrufen.

          Eben dies soll er ja auch gar nicht.
          Das Problem ist aber, dass hier ein Lost Handle erzeugt werden würde, wenn nicht spätestens der Destruktor die Verbindung zur DB kappt. Das DB-Handle zu löschen, hebt die Verbindung mMn nicht auf.

          Oder habe ich da irgendwas nicht mitbekommen?

          Liebe Grüße aus dem Cyberspace

          Tom vom Berg

          --
          Nur selber lernen macht schlau
          http://bergpost.annerschbarrich.de
          1. Moin!

            »» > »» - Der Destruktor sollte für ein geeordnetes Lebensende der Klasse sorgen, also hier das
            »» > »»   Beenden der Datenbankverbindung.
            »» Mit der Verwendung von Destruktoren unter PHP muss man recht achtsam sein, denn "The destructor method will be called as soon as all references to a particular object are removed or when the object is explicitly destroyed or in any order in shutdown sequence.". Und ein Aufrufer wird nur in den seltesten Faellen mueszig genug sein und den Destruktor explizit aufrufen.

            Eben dies soll er ja auch gar nicht.
            Das Problem ist aber, dass hier ein Lost Handle erzeugt werden würde, wenn nicht spätestens der Destruktor die Verbindung zur DB kappt. Das DB-Handle zu löschen, hebt die Verbindung mMn nicht auf.

            Die DB-Verbindung wird am Skriptende gekappt, wenn man sie nicht explizit vorher löscht.

            Ich würde dafür allerdings keinen Destruktor bemühen. Die Dinger sind, wie erwähnt, offensichtlich diffizil, und sollten für die Aufgaben vorbehalten bleiben, die wirklich wichtig sind. Mir fällt kein gutes Beispiel ein, aber das Beenden einer DB-Verbindung gehört nicht dazu.

            - Sven Rautenberg

            1. Hello,

              Eben dies soll er ja auch gar nicht.
              Das Problem ist aber, dass hier ein Lost Handle erzeugt werden würde, wenn nicht spätestens der Destruktor die Verbindung zur DB kappt. Das DB-Handle zu löschen, hebt die Verbindung mMn nicht auf.

              Die DB-Verbindung wird am Skriptende gekappt, wenn man sie nicht explizit vorher löscht.

              Das ist mir klar. Ein Script könnte aber auch durchaus etwas länger laufen und es wäre möglich, dass jemand auf die Idee kommt, mehrere Datenbankverbindungen nacheinander aufzubauen (wenn Chris die DB-Klasse als Singleton Pattern aufbaut, geht es ja nur nacheinander... oder? Geht es überhaupt ein zweites Mal, so wie er es gebaut hat? Werden Static Vars auch gelöscht, wenn die Klasse stirbt?)

              Ich würde dafür allerdings keinen Destruktor bemühen. Die Dinger sind, wie erwähnt, offensichtlich diffizil, und sollten für die Aufgaben vorbehalten bleiben, die wirklich wichtig sind. Mir fällt kein gutes Beispiel ein, aber das Beenden einer DB-Verbindung gehört nicht dazu.

              Jedenfalls halte ich gerade für diese Aufgabe den Destruktor für den richtigen Ort, da das Handle nicht in den Einzugsbereich von PHP, sondern den des DBMS gehört und daher ordentlich zurückgegeben werden muss. Das Gleiche gilt für Dateihandles, Speicherhandles der Image-Funktionen usw.

              Sollte es anders sein, muss das wieder ganz tief drinnen begründet sein ;-))

              Liebe Grüße aus dem Cyberspace

              Tom vom Berg

              --
              Nur selber lernen macht schlau
              http://bergpost.annerschbarrich.de
              1. Hai,

                Das ist mir klar. Ein Script könnte aber auch durchaus etwas länger laufen und es wäre möglich, dass jemand auf die Idee kommt, mehrere Datenbankverbindungen nacheinander aufzubauen (wenn Chris die DB-Klasse als Singleton Pattern aufbaut, geht es ja nur nacheinander... oder?

                Das Singleton-Pattern fuer Datenbankklassen soll ja eben genau das verhindern.
                Allerdings ist ein Singleton unter PHP nicht das gleiche wie in anderen Sprachen. Unter Java oder C# oder.. wird tatsaechlich fuer alle Anfragen eine _einzige Instanz_ genutzt - und zwar immer exakt die Selbe. Unter PHP hat zB jeder Benutzer fuer jeden Request seine eigene (neue) Instanz, da die Instanz nach jedem Request wieder verworfen wird.

                Geht es überhaupt ein zweites Mal, so wie er es gebaut hat? Werden Static Vars auch gelöscht, wenn die Klasse stirbt?)

                Da static-Variablen zustandlos sind - dass heisst, sie sind nicht an eine Instanz gebunden -, existieren sie auch noch nach dem "Sterben" einer Klasse.

                MfG,
                Sympatisant

                --
                "If the future isn't bright, at least it is colorful"
                1. Hello,

                  Das ist mir klar. Ein Script könnte aber auch durchaus etwas länger laufen und es wäre möglich, dass jemand auf die Idee kommt, mehrere Datenbankverbindungen nacheinander aufzubauen (wenn Chris die DB-Klasse als Singleton Pattern aufbaut, geht es ja nur nacheinander... oder?
                  Das Singleton-Pattern fuer Datenbankklassen soll ja eben genau das verhindern.

                  Das meinte ich nicht mit dem "oder?"
                  Damit meinte ich, dass die Klasse auf diese Weise nicht zweimal nacheinander, also erzeugen, zerstören, erzeugen ... benutzt werden kann, weil die Static-Variable auch nach dem Tod der Klasse erhalten bleibt. Die muss, soll die nochmalige Verwendung im selben Script erlaubt sein, dediziert aufgeräumt werden.

                  PHP ist da vielleicht etwas anders gestrickt als C++?

                  Hierzu Dein Beispiel etwas aufgebohrt:

                  <?php   ### oop-001.php ###

                  class Test
                  {
                      static $_name;

                  public function __construct($name)
                      {
                          echo "Hello $name";
                          self::$_name = $name;
                      }

                  public function DoSth($var)
                      {
                          echo $var;
                      }

                  public function __destruct()
                      {
                          echo "World";
                      }
                  }

                  $Test = new Test('Thomas');
                  $Test->DoSth(' this is my ');

                  flush();
                  sleep(10);

                  echo " Klasse zerstören: ";
                  unset($Test);

                  flush();
                  sleep(10);

                  echo "ENDE ";
                  echo Test::$_name;

                  ?>

                  Liebe Grüße aus dem Cyberspace

                  Tom vom Berg

                  --
                  Nur selber lernen macht schlau
                  http://bergpost.annerschbarrich.de
                  1. Hello,

                    mal eine ganz verdutzte Frage dazu:

                    Wenn ich eine normale dynamische Klasse habe, kann ich die mittels unset($klassenvariable) wieder zerstören. Wie muss ich das denn bei einer Singleton-Klasse machen? Die bleibt von dem unset($singletonclass) unbeindruckt.

                    Liebe Grüße aus dem Cyberspace

                    Tom vom Berg

                    --
                    Nur selber lernen macht schlau
                    http://bergpost.annerschbarrich.de
                    1. Hai,

                      Wenn ich eine normale dynamische Klasse habe, kann ich die mittels unset($klassenvariable) wieder zerstören. Wie muss ich das denn bei einer Singleton-Klasse machen? Die bleibt von dem unset($singletonclass) unbeindruckt.

                      Es ist nicht moeglich eine statische Variable zu zerstoeren. Man kann lediglich die Referenz innerhalb des aktuellen Kontextes zerstoeren. Ein darauffolgendes static Statement stellt die Referenz automatisch wieder her.
                      Und in unserem Beispiel wird die Singleton-Instanz in einer statischen Variable gehalten - von daher kann sie nicht zerstoert werden. (1)

                      MfG,
                      Sympatisant

                      (1) Beispiel:

                      <?php  
                        
                      class Singleton  
                      {  
                          static $Instance;	  
                      	protected $myvar;  
                      	  
                      	// private constructor  
                          private function __construct( ) {  
                              $this->myvar = 'Hello World';  
                          }  
                        
                      	// static singleton method  
                          public function GetInstance( )  
                          {  
                              if( !isset( self::$Instance ) )  
                              	self::$Instance = new Singleton();  
                              return self::$Instance;  
                          }  
                        
                          // Example: unset()  
                          // ! Throws Exception !  
                          public static function DeleteMe( )  
                          {  
                              // Fatal error: Attempt to unset static property Singleton::$Instance in [..]  
                              unset( self::$Instance );  
                          }  
                        
                          // Edit Output-String  
                          public function SetValue( $str )  
                          {  
                              $this->myvar = $str;  
                          }  
                        
                          // Echo String  
                          public function Debug()  
                          {  
                          	echo $this->myvar.'<br>';  
                          }  
                      	  
                      	// Example: Desctructor  
                      	public function __destruct()  
                          {  
                          	unset( $this->myvar );  
                          }  
                      }  
                        
                      // Get Instance  
                      $Singleton = Singleton::GetInstance();  
                        
                      // Output String  
                      echo $Singleton->Debug();  
                        
                      // Set individual Value  
                      $Singleton->SetValue('Good Bye my World');  
                        
                      // Output String  
                      echo $Singleton->Debug();  
                        
                      // Try to destroy Singleton-Static-Instance.. will Fail!  
                      // $Singleton->DeleteMe();  
                        
                      // Do it manually  
                      unset( $Singleton ); // Hier wird nur die Referenz geloescht, nicht die Static-Instanz  
                        
                      // Get "new" Instance - will still be the Same.  
                      $Singleton = Singleton::GetInstance();  
                        
                      // Output String  
                      echo $Singleton->Debug();  
                        
                        
                      ?>
                      
                      --
                      "If the future isn't bright, at least it is colorful"
                      1. Hello,

                        [...]

                        viele Mühe. Danke.

                        Ergo kann man bei PHP die Instanz einer Singleton-Klasse nicht wieder beseitigen.
                        Dann könnte man doch gleich eine Referenz auf die Klassendefinition benutzen und gar nicht erst eine Instanz bilden? Oder stehe ich da jetzt im Wald?

                        Liebe Grüße aus dem Cyberspace

                        Tom vom Berg

                        --
                        Nur selber lernen macht schlau
                        http://bergpost.annerschbarrich.de
                        1. echo $begrüßung;

                          Dann könnte man doch gleich eine Referenz auf die Klassendefinition benutzen und gar nicht erst eine Instanz bilden? Oder stehe ich da jetzt im Wald?

                          Es gibt Programmiersprachen, da sind auch Klassen Objekte, aber PHP gehört nicht dazu. Mit "Referenz auf die Klassendefinition" meinst du vielleicht Klassenname::... womit du bei statischen Eigenschaften und Methoden gelandet wärst. Es kann sinnvoll sein, eine Klasse mit nur statischem Zeug zu haben, je nach Anwendungsfall.

                          Ich glaube, ich schlug im ursprünglichen Thread so etwas vor. Eine Datenabstraktionsschicht stellt diverse statische Methoden bereit, die eine atomate Aufgabe erfüllen: sie holen (eventuell abhängig von übergebenen Parametern) eine Datenmenge. Je nach Anwendungsfall gibt es eine solche Methode. Wie die Daten besorgt werden ist Blackbox. Nach außen hin gibt es jedenfalls nur diese eine Methode für jeden (mehr oder weniger) speziellen Fall. Damit hast du ein zumindest nach außen hin instanzlos wirkendes Gebilde.

                          echo "$verabschiedung $name";

                    2. echo $begrüßung;

                      Wenn ich eine normale dynamische Klasse habe,

                      Du meinst ein Objekt (auch Instanz genannt).

                      kann ich die mittels unset($klassenvariable) wieder zerstören. Wie muss ich das denn bei einer Singleton-Klasse machen? Die bleibt von dem unset($singletonclass) unbeindruckt.

                      Wenn eine Klassenvariable nicht öffentlich ist, kann sie auch nur von einem zur Klasse gehörenden Code angesprochen werden. Und der kann sie auch per unset() eliminieren. Wenn du nur eine Referenz zur Verfügung hast, löschst du mit unset() nur diese.

                      Wenn du jedoch beispielsweise per Singleton eine Referenz auf die Klassenvariable rausgegeben hast, nun aber die Klassenvariable löschst, so löschst du nur die klasseninterne Referenz auf den Variablencontainer. Die "draußen" existierende Referenz verweist weiterhin auf den Container, der auch nicht automatisch verschwindet, also quasi unterm Gesäß weggezogen würde. Greifst du mit dem Klassencode wieder schreibend auf die Klassenvariable zu, wird ein neuer Variablencontainer unabhängig zum "außen" existierenden erstellt.

                      echo "$verabschiedung $name";

                  2. Hai Tom,

                    Damit meinte ich, dass die Klasse auf diese Weise nicht zweimal nacheinander, also erzeugen, zerstören, erzeugen ... benutzt werden kann, weil die Static-Variable auch nach dem Tod der Klasse erhalten bleibt. Die muss, soll die nochmalige Verwendung im selben Script erlaubt sein, dediziert aufgeräumt werden.

                    Wozu aufraeumen? Ich binde eine Klasse doch gerade dafuer ein, dass mir a) in meinem Scope die entsprechenden Static-Variablen/-Methoden zu Verfuegung stehen - eben ohne an eine Instanz gebunden zu sein(1) - und b) ich von verschiedenen Stellen/Klassen aus instanz-unabhaengige Variablen/Methoden teilen kann(2).
                    Moechte man erreichen, dass eine Variable beim Zerstoeren der Klasse mit verworfen wird - was ja in der Praxis der Normalfall ist - dann deklariert man sie als Member-Variable.

                    MfG,
                    Sympatisant

                    (1) "Declaring class members or methods as static makes them accessible without needing an instantiation of the class" more

                    (2) Simples Beispiel:

                    <?php  
                      
                    class Counter  
                    {  
                        private static $start_time;  
                    	private static $stop_time;  
                      
                        public static function Start()  
                        {  
                            self::$start_time = time();  
                        }  
                      
                        public static function Stop()  
                        {  
                            self::$stop_time = time();  
                        }  
                      
                        public static function GetSeconds()  
                        {  
                            return round(self::$stop_time - self::$start_time,2);  
                        }  
                      
                        private static function GetMicrotime()  
                    	{  
                    	   	list($msec, $sec) = explode(" ",microtime());  
                    		return ($msec + $sec);  
                    	}  
                    }  
                      
                    class MyImpl1  
                    {  
                    	public function __construct()  
                    	{  
                    		Counter::Start();  
                    	}  
                    }  
                      
                    class MyImpl2  
                    {  
                    	public function __construct()  
                    	{  
                    		Counter::Stop();  
                    	}  
                    }  
                      
                    class MyImpl3  
                    {  
                    	public function __construct()  
                    	{  
                    		echo 'Execution Time: '.Counter::GetSeconds();  
                    	}  
                    }  
                      
                    new MyImpl1; // Starts the Counter  
                    sleep(2); // Dummy  
                    new MyImpl2; // Ends the Counter  
                    new MyImpl3; // Displays Time  
                      
                    ?>
                    
                    --
                    "If the future isn't bright, at least it is colorful"
                    1. Hello,

                      Moechte man erreichen, dass eine Variable beim Zerstoeren der Klasse mit verworfen wird - was ja in der Praxis der Normalfall ist - dann deklariert man sie als Member-Variable.

                      Da habe ich mich wohl schief ausgedrückt.
                      Ich will nicht die Variable entfernen, sondern, wenn die Instanz der Singleton-Class beseitigt wurde (was ja legitim ist), diese lediglich zurücksetzen, damit später wieder eine neue Instanz gebildet werden kann.

                      Dadurch kam ich darauf, man müsste sie einfach NULL setzen und im getInstance() auch auf NULL prüfen. Aber leider verschwindet auch vom NULL-Setzen weder der Instanzvariable noch der static-Variable die Instanz nicht wieder.

                      Liebe Grüße aus dem Cyberspace

                      Tom vom Berg

                      --
                      Nur selber lernen macht schlau
                      http://bergpost.annerschbarrich.de
                      1. Hai,

                        Da habe ich mich wohl schief ausgedrückt. Ich will nicht die Variable entfernen, sondern, wenn die Instanz der Singleton-Class beseitigt wurde (was ja legitim ist), diese lediglich zurücksetzen, damit später wieder eine neue Instanz gebildet werden kann.

                        OK, jetzt haben wir uns anscheinend verstanden.
                        Siehe http://forum.de.selfhtml.org/my/?t=185544&m=1231559#m1231559

                        MfG,
                        Sympatisant

                        --
                        "If the future isn't bright, at least it is colorful"
                2. Moin!

                  Da static-Variablen zustandlos sind - dass heisst, sie sind nicht an eine Instanz gebunden -, existieren sie auch noch nach dem "Sterben" einer Klasse.

                  Wann stirbt eine Klasse? Am Skriptende. Denn die Klasse existiert aufgrund ihrer Deklaration mittels class{} - die kann man nicht vor Skriptablauf töten.

                  - Sven Rautenberg

                  1. Hello,

                    Da static-Variablen zustandlos sind - dass heisst, sie sind nicht an eine Instanz gebunden -, existieren sie auch noch nach dem "Sterben" einer Klasse.

                    Wann stirbt eine Klasse? Am Skriptende. Denn die Klasse existiert aufgrund ihrer Deklaration mittels class{} - die kann man nicht vor Skriptablauf töten.

                    Wie heißt dieser komische Ausdruck? http://de.wikipedia.org/wiki/Korinthenkacker

                    Dass hier die Beseitigung der einzigen Instanz der Singleton-Klasse gemeint war, ergibt sich aus dem Gesprächsfaden.

                    Aber wo wir gerade beim Thema sind: brauche ich denn überhaupt eine Instanz, wenn ich denn sowieso nur  eine haben kann und die ja scheinbar auch nicht vor dem Scriptende wieder loswerde?

                    Liebe Grüße aus dem Cyberspace

                    Tom vom Berg

                    --
                    Nur selber lernen macht schlau
                    http://bergpost.annerschbarrich.de
                    1. echo $begrüßung;

                      Wie heißt dieser komische Ausdruck? http://de.wikipedia.org/wiki/Korinthenkacker

                      Wer sauber programmieren will, sollte sich auch einer sauberen Begriffswahl befleißigen. Eine Klasse ist eine Klasse, ein Objekt oder eine Instanz ist was anderes. Spätestens wenn du bei Regen mit einem Bauplan in der Hand dastehst statt in einem Haus zu sitzen, wirst du merken, dass du besser gekommen wärst, wenn du beim Bestellprozess die richtigen Begriffe verwendet hättest.

                      Aber wo wir gerade beim Thema sind: brauche ich denn überhaupt eine Instanz, wenn ich denn sowieso nur  eine haben kann und die ja scheinbar auch nicht vor dem Scriptende wieder loswerde?

                      Wenn du das Funktionalität eines Objekts benötigst, wirst du um eine Instanz nicht drumrumkommen.

                      echo "$verabschiedung $name";

                3. echo $begrüßung;

                  Allerdings ist ein Singleton unter PHP nicht das gleiche wie in anderen Sprachen. Unter Java oder C# oder.. wird tatsaechlich fuer alle Anfragen eine _einzige Instanz_ genutzt - und zwar immer exakt die Selbe. Unter PHP hat zB jeder Benutzer fuer jeden Request seine eigene (neue) Instanz, da die Instanz nach jedem Request wieder verworfen wird.

                  Das stimmt nicht. Auch unter PHP gibt es mit einem ordentlich implementierten Singleton nur eine einzige Instanz.

                  » Geht es überhaupt ein zweites Mal, so wie er es gebaut hat? Werden Static Vars auch gelöscht, wenn die Klasse stirbt?)
                  Da static-Variablen zustandlos sind - dass heisst, sie sind nicht an eine Instanz gebunden -, existieren sie auch noch nach dem "Sterben" einer Klasse.

                  Eine Klasse ist ein abstraktes Gebilde, ein Bauplan. Sie kann nicht leben und demzufolge auch nicht sterben. Man kann Instanzen erzeugen, die leben und sterben können. Und es gibt die statischen Eigenschaften, die aber nur globale Variablen in einem Namensraum sind.

                  echo "$verabschiedung $name";

                  1. Hai deldfix,

                    Das stimmt nicht. Auch unter PHP gibt es mit einem ordentlich implementierten Singleton nur eine einzige Instanz.

                    Ja, aber - im Webumfeld - jeweils nur pro Request. Danach geht sie wieder verloren. Und genau das meinte ich. Implementiere ich unter Java eine Singleton-Instanz, so wird sie erst dann sterben, wenn ich den Application-Server neustarte. Bis dahin wird sie ausnahmslos von allen Prozessen geteilt und verwendet.

                    Eine Klasse ist ein abstraktes Gebilde, ein Bauplan. Sie kann nicht leben und demzufolge auch nicht sterben. Man kann Instanzen erzeugen, die leben und sterben können.

                    Stimmt, da habe ich mich ungluecklich ausgedrueckt.

                    MfG,
                    Sympatisant

                    --
                    "If the future isn't bright, at least it is colorful"
                    1. echo $begrüßung;

                      » Das stimmt nicht. Auch unter PHP gibt es mit einem ordentlich implementierten Singleton nur eine einzige Instanz.
                      Ja, aber - im Webumfeld - jeweils nur pro Request. Danach geht sie wieder verloren. Und genau das meinte ich. Implementiere ich unter Java eine Singleton-Instanz, so wird sie erst dann sterben, wenn ich den Application-Server neustarte. Bis dahin wird sie ausnahmslos von allen Prozessen geteilt und verwendet.

                      Ach, so meinst du das. Das ist aber, wenn man es genau nimmt, nicht abhängig von der Sprache sondern von der Laufzeitumgebung. Beispielsweise ist nicht C# die Ursache für den Unterschied sondern ASP.NET.

                      echo "$verabschiedung $name";

                      1. Hai dedlfix,

                        Ach, so meinst du das. Das ist aber, wenn man es genau nimmt, nicht abhängig von der Sprache sondern von der Laufzeitumgebung. Beispielsweise ist nicht C# die Ursache für den Unterschied sondern ASP.NET.

                        Das hast Du vollkommen richtig erkannt. Da, wo wir bei Java WebSphere, Sybase, WebLogic oder JBoss haben (bei C# .NET und den IIS), haben wir im Falle von PHP lediglich den Apache.

                        MfG,
                        Sympatisant

                        --
                        "If the future isn't bright, at least it is colorful"
              2. echo $begrüßung;

                Ein Script könnte aber auch durchaus etwas länger laufen und es wäre möglich, dass jemand auf die Idee kommt, mehrere Datenbankverbindungen nacheinander aufzubauen (wenn Chris die DB-Klasse als Singleton Pattern aufbaut, geht es ja nur nacheinander... oder? Geht es überhaupt ein zweites Mal, so wie er es gebaut hat?

                Üblicherweise wird das Ergebnis einer Datenbankanfrage von der MySQL-Client-API komplett abgeholt und gepuffert. Du kannst also sofort eine weitere Abfrage starten und dann erst das Resultset der ersten über dessen Ressourcenkennung befetchen. (Man kann natürlich auch ungepufferte Abfragen stellen, dann muss man die erst zu Ende fetchen, bevor man eine nächste stellen kann.)

                Werden Static Vars auch gelöscht, wenn die Klasse stirbt?

                Eine Klasse stirbt nicht wirklich, denn eigentlich ist sie nur Code. Ihre statischen Variablen sind im Prinzip wie globale Variable zu betrachten, was ihr Lebensende anbelangt.

                Jedenfalls halte ich gerade für diese Aufgabe den Destruktor für den richtigen Ort, da das Handle nicht in den Einzugsbereich von PHP, sondern den des DBMS gehört und daher ordentlich zurückgegeben werden muss. Das Gleiche gilt für Dateihandles, Speicherhandles der Image-Funktionen usw.

                PHP gibt nur Ressourcenkennungen nach außen. Mit Handles im eigentlichen Sinne kommt der PHP-Programmierer nicht in Berührung. Wenn eine Schließfunktion nicht explizit für eine Ressourcenkennung aufgerufen wird, dann schließt PHP die Ressource und die damit verbundenen internen Handles am Scriptende. Mach dir mal als PHP-Programmierer nicht zu viele Gedanken um die Handles.

                echo "$verabschiedung $name";

                1. Hello,

                  Werden Static Vars auch gelöscht, wenn die Klasse stirbt?

                  Auch hier meitne ich die Instanz der Klasse.
                  Die Static Var liegt aber im Definitionsbereich der Klasse.
                  Sie bleibt also bestehen, wenn man sie nicht im Destruktor zurücksetzt.

                  PHP gibt nur Ressourcenkennungen nach außen. Mit Handles im eigentlichen Sinne kommt der PHP-Programmierer nicht in Berührung. Wenn eine Schließfunktion nicht explizit für eine Ressourcenkennung aufgerufen wird, dann schließt PHP die Ressource und die damit verbundenen internen Handles am Scriptende. Mach dir mal als PHP-Programmierer nicht zu viele Gedanken um die Handles.

                  Die Ressourcenkennungen sind zu behandeln, wie Handles. Das Löschen einer Ressourcenkennung gibt das dahinterliegende Handle nicht frei, macht es aber unerreicbar!

                  Gerade, wenn man sich eigene Klassen abut, sollten die schon sauber designed werden. Dazu gehört auch das Zurückgeben von Handles, indem man die passende Funktion unter Verwendung der Ressourcenkennung benutzt.

                  Ich habe schon an die Hundert kaputter Scripte repariert, die das nicht beherzigt haben und daher ihre Server lahm gelegt haben.

                  Wer saubere OOP-Programme schreiben will, MUSS berücksichtigen, wie es "untenrum" aussieht.

                  Liebe Grüße aus dem Cyberspace

                  Tom vom Berg

                  --
                  Nur selber lernen macht schlau
                  http://bergpost.annerschbarrich.de
          2. Hai,

            Eben dies soll er ja auch gar nicht.
            Das Problem ist aber, dass hier ein Lost Handle erzeugt werden würde, wenn nicht spätestens der Destruktor die Verbindung zur DB kappt. Das DB-Handle zu löschen, hebt die Verbindung mMn nicht auf.

            Ich hatte noch im Hinterkopf, dass der Destruktor nicht immer automatisch aufgerufen wurde und man es teils explizit machen musste. Daher mein Kommentar. Jedoch existiert dieses Verhalten mitterweile wohl nicht mehr, da folgendes in der aktuelle Version (5.2.9) wie erwuenscht funktioniert:

              
            class Test  
            {  
                public function __construct()  
                {  
                	echo "Hello";  
                }  
              
                public function DoSth($var)  
                {  
                    echo $var;  
                }  
              
                public function __destruct()  
                {  
                	echo "World";  
                }  
              
            }  
              
            $Test = new Test;  
            $Test->DoSth(' my ');
            

            MfG,
            Sympatisant

            --
            "If the future isn't bright, at least it is colorful"
        2. echo $begrüßung;

          » » - Eigenschaften der Klasse sollten nicht public sein
          Es kommt darauf an. Man kann sie durchaus public setzen und dann mittels Overloading entsprechend intervenieren. Somit spart man sich die Getter- und Setter-Methoden fuer Properties, die keine weiteren Behandlungen benoetigen.

          Das geht nicht. PHPs Overloading springt erst dann an, wenn eine Eigenschaft nicht vorhanden ist.

          Wenn man zugunsten der Einfachheit auf das Erstellen von Getter und Setter verzichtet hat, nun aber doch eine andere Zugriffslogik braucht, kann man das wie folgt lösen. Man erstellt Getter und Setter und löscht die ehemalige public-Variable. Per Overloading ruft man im Falle des Zugriffs auf die ehemalige Variable nun Getter und Setter auf.

          » »» - Der Destruktor sollte für ein geeordnetes Lebensende der Klasse sorgen, also hier das
          » »»   Beenden der Datenbankverbindung.
          Mit der Verwendung von Destruktoren unter PHP muss man recht achtsam sein, denn "The destructor method will be called as soon as all references to a particular object are removed or when the object is explicitly destroyed or in any order in shutdown sequence.". Und ein Aufrufer wird nur in den seltesten Faellen mueszig genug sein und den Destruktor explizit aufrufen.

          Dann lag ich mit meiner letzten Anmerkung in jenem Beitrag etwas falsch. Da hier aber ein Singleton im Spiel ist, ist die Instanz (nach ihrer Erzeugung) immer vorhanden, da sie einer statischen Klasseneigenschaft zugewiesen ist. Und die wird erst am Scriptende aufgeräumt und somit kommt auch erst dann der Konstruktur zum Zuge.

          Vorher will man den auch gar nicht aufrufen, denn die anwendenden Codeteile wissen nicht, ob nach ihnen noch jemand die DB-Verbindung benötigt. Und die DB-Klasse selbst weiß auch nicht, ob noch jemand daherkommt.

          echo "$verabschiedung $name";

    2. echo $begrüßung;

      • Eigenschaften der Klasse sollten nicht public sein

      Das kann man so sehen, muss man aber nicht prinzipiell. Eine Zugriffsmethode ist immer zusätzlicher Code, der Laufzeit verbraucht. Wenn abzusehen ist, dass der Code der Zugriffsmethode nichts anderes machen wird als return $this->private_variable; kann man sich die Erhöhung der (Code-)Komplexität, ohne dass man dabei was gewinnt, sparen.

      • Der Konstruktor sollte die wichtigste Aufgabe der Klasse bei der Instantiierung übernehmen,
          also hier das Beschaffen der Zugangsdaten und den Erstaufbau der Datenbank-Verbindung.

      Nein, nicht prinzipiell. Die Datenbankverbindung kann auch lazy erstellt werden, also erst dann, wenn sie wirklich gebraucht wird. Im Falles des Singleton-Patterns muss man sich andere Gedanken um die Beschaffung der Zugangsdaten machen. Es ist nicht unbedingt die Aufgabe des anwendenden Codes, die Zugangsdaten zu kennen. Vielmehr sollte sich die DB-Klasse die Zugangsdaten selbst holen, beispielsweise aus einer Konfigurationsdatei.

      • Der Destruktor sollte für ein geeordnetes Lebensende der Klasse sorgen, also hier das
          Beenden der Datenbankverbindung.

      Der wird sowieso erst am Scriptende aufgerufen und da wird die DB-Verbindung automatisch geschlossen. (Gilt zumindest für PHP.)

      echo "$verabschiedung $name";

      1. Hello,

        • Der Destruktor sollte für ein geeordnetes Lebensende der Klasse sorgen, also hier das
             Beenden der Datenbankverbindung.

        Der wird sowieso erst am Scriptende aufgerufen und da wird die DB-Verbindung automatisch geschlossen. (Gilt zumindest für PHP.)

        Wer legt denn das fest?
        Ich kann doch meine Instanz mitten im Script löschen, wenn es mir in den Kram passt?

        Und damit ich dann eine Weile später wieder eine bilden lassen kann, muss ich die Static-Variable, die das Singleton kontrolliert, zurücksetzen.

        Allerdings funktioniert das bei der Singleton-Klassen-Instanz eben leider nicht in PHP, jedenfalls nicht so, wie ich es erwartet hätte und auch nicht so, wie es in den UCN des PHP-Handbuches beschrieben steht.

        Liebe Grüße aus dem Cyberspace

        Tom vom Berg

        --
        Nur selber lernen macht schlau
        http://bergpost.annerschbarrich.de
        1. echo $begrüßung;

          » Der [Destruktor] wird sowieso erst am Scriptende aufgerufen und da wird die DB-Verbindung automatisch geschlossen. (Gilt zumindest für PHP.)
          Wer legt denn das fest?
          Ich kann doch meine Instanz mitten im Script löschen, wenn es mir in den Kram passt?

          Ja, kannst du schon. Meine Aussage war pauschal nicht richtig. Die Singleton-Instanz jedoch stirbt erst zum Scriptende.

          Und damit ich dann eine Weile später wieder eine bilden lassen kann, muss ich die Static-Variable, die das Singleton kontrolliert, zurücksetzen.

          Sie vorher zu töten und anschließend eine neue aufleben zu lassen, wäre kein Singleton mehr. Die von der DB-Klsse verwaltete Verbindung steht in keinem direkten Zusammenhang zum Singleton-Pattern. Allerdings will man ja gerade dieses einsetzen, um ein ständiges Öffnen und Schließen der Verbindung zu unterbinden.

          echo "$verabschiedung $name";

          1. Hello,

            ... verwirrt haben mich die UCN in der Handbuchseite, die eine Zerstörung der Singleton-Instanz andeuten:

            http://www.php.net/manual/en/language.oop5.patterns.php

            /**
                 * Destroy the singleton
                 */
                public function destroySingleton()
                {
                    unset(self::$_instance[ get_class($this) ]);
                }

            oder an anderer Stelle:

            /**
                 *    Destroy the singleton object. Deleting the session variable in the
                 *    destructor does not make sense since the destructor is called every
                 *    time the script ends.
                 */
                 public static function _destroy()
                 {
                     $_SESSION[ self::$_singleton_class ] = null;
                 }

            oder von irgendwo anders:

            public function destroySingleton()
                {
                    settype(&$this, 'null');
                }

            Aber das letzte könnte noch von PHP 4 stammen, vermute ich.

            Liebe Grüße aus dem Cyberspace

            Tom vom Berg

            --
            Nur selber lernen macht schlau
            http://bergpost.annerschbarrich.de
            1. echo $begrüßung;

              ... verwirrt haben mich die UCN in der Handbuchseite, die eine Zerstörung der Singleton-Instanz andeuten:

              Da steht manchmal auch gehöriger Unfug drin. Die Singleton-Instanz darf nicht explizit zerstört werden. Wenn du doch das Bedürfnis dazu hast, ist das Singleton-Pattern nicht das was du verwenden willst. Oder anders: wenn du einen aufrufbaren Vernichtungsmechanismus erfolgreich einbaust, hast du keine Implementation des Singleton-Pattern mehr vorliegen.

              echo "$verabschiedung $name";

              1. Hello,

                ... verwirrt haben mich die UCN in der Handbuchseite, die eine Zerstörung der Singleton-Instanz andeuten:

                Da steht manchmal auch gehöriger Unfug drin. Die Singleton-Instanz darf nicht explizit zerstört werden. Wenn du doch das Bedürfnis dazu hast, ist das Singleton-Pattern nicht das was du verwenden willst. Oder anders: wenn du einen aufrufbaren Vernichtungsmechanismus erfolgreich einbaust, hast du keine Implementation des Singleton-Pattern mehr vorliegen.

                Ok, das ist angekommen :-)

                Liebe Grüße aus dem Cyberspace

                Tom vom Berg

                --
                Nur selber lernen macht schlau
                http://bergpost.annerschbarrich.de
  4. Hello,

    ich habe da bei meiner Suche nach "wie zerstört man die Instanz einer Singel-Pattern-Class?" gerade noch ein PDF im Web gefunden

    http://www.informit.com/content/images/013147149X/downloads/013147149X_book.pdf

    Das isht doch ganz gut aus :-)

    Liebe Grüße aus dem Cyberspace

    Tom vom Berg

    --
    Nur selber lernen macht schlau
    http://bergpost.annerschbarrich.de
    1. echo $begrüßung;

      ich habe da bei meiner Suche nach "wie zerstört man die Instanz einer Singel-Pattern-Class?" gerade noch ein PDF im Web gefunden
      http://www.informit.com/content/images/013147149X/downloads/013147149X_book.pdf

      Auf welcher der 720 Seiten steht das denn?

      Generell: wer die Instanz erstellt hat, der ist bei Bedarf auch für ihre Zerstörung zuständig. Also musst du dafür Code in der Klasse vorsehen. Allerdings ist das Unterfangen aussischtslos, wenn anderswo noch Referenzen existieren. Du kannst dann nur irgendwelchen Aufräumcode ausführen, aber die eigentliche Instanz bekommst du nicht tot. Das darf auch nicht passieren, denn sonst hingen die anderen Referenzen in der Luft.

      echo "$verabschiedung $name";

      1. Hello,

        ich habe da bei meiner Suche nach "wie zerstört man die Instanz einer Singleton-Pattern-Class?" gerade noch ein PDF im Web gefunden
        http://www.informit.com/content/images/013147149X/downloads/013147149X_book.pdf

        Auf welcher der 720 Seiten steht das denn?

        Ich hatte wohl nach "PHP Singleton destroy Instance" gesucht, und Google hat mir den Link geworfen.

        Da wollte ich ihn doch nicht unterschlagen. Ich habe die 720 Seiten noch nicht durch, aber mMn sieht es recht kompetent aus ;-))

        Liebe Grüße aus dem Cyberspace

        Tom vom Berg

        --
        Nur selber lernen macht schlau
        http://bergpost.annerschbarrich.de
        1. echo $begrüßung;

          » > http://www.informit.com/content/images/013147149X/downloads/013147149X_book.pdf
          Ich habe die 720 Seiten noch nicht durch, aber mMn sieht es recht kompetent aus ;-))

          Ja, das sieht man schon an den Namen der Autoren. Allerdings ist seit 2004 auch schon wieder gehörig Zeit ins Land gegangen und das eine oder andere Details ist sicher schon wieder nicht mehr aktuell.

          echo "$verabschiedung $name";

  5. Hello,

    ... und noch ein eBook für Dich:
    http://d.scribd.com/docs/j7iwykqplv9nmj7qf0f.pdf

    Die bauen da sogar eine DB-Klasse mit einem Singleton-Pattern :-)

    Liebe Grüße aus dem Cyberspace

    Tom vom Berg

    --
    Nur selber lernen macht schlau
    http://bergpost.annerschbarrich.de
  6. echo $begrüßung;

    Fortsetzung von Komplettes Projekt in OOP.
    Ich rufe hiermit den großen Dedlfix und Co. auf, mich weiterhin zu unterstützen ;).

    Es haben sich ja schon einige Antworten eingefunden. Teilweise gehen sie aber andere Wege als ich im Sinn hatte. Und das ist auch nicht verkehrt, denn die einzig wahre Lösung gibt es nicht. Wie auch immer, es folgen einige Anmerkungen aus meiner Sicht.

    public static $db_host;
    public static $db_user;
    public static $db_pw;
    public static $db_name;
    public static $db_connection;

    Braucht jemand diese Angaben außer den Mitgliedern deiner Klasse? Wohl kaum. Für die Zugangsdaten reichen private Variablen, wenn sie überhaupt benötigt werden. Also, die Variablen meine ich. Die Zugangsdaten brauchst du nur um die Verbindung aufzubauen. Die soll ja auch, während das Script läuft, nicht wieder geschlossen werden. Es reicht also, wenn die die Verbindung aufbauende Methode sich die Zugangsdaten besorgt. Eine Konfigurationsdatei ist dafür einer der möglichen guten Wege. Ein weiteres Rumhantieren mit diesen Daten außerhalb der Klasse entfällt dann.

    Und auch die Connection ist nichts, was öffentlich zugänglich sein sollte. Genau das willst du ja kapseln.

    Singleton

    public static function db_singleton()
        {
            if (!isset(self::$instance)) {
                $c = __CLASS__;
                self::$instance = new $c;

    Auf das $c kannst du verzichten.

    self::$instance = new db();

    ist zum einen ausreichend und zum anderen sehe ich keinen Anwendungsfall bei dem der Klassenname nicht bekannt ist. Der einzige Grund für deinen Weg ist meines Erachtens, dass du dir die Möglichkeit der Umbenennung der Klasse vorbehalten willst und für diesen Fall diese Stelle nicht mehr anpassen willst. Für alle anderen klassenintern Verweise auf den Klassennamen kannst du ja self:: verwenden ...

    Datenbankwerte setzen

    public function db_set_vars($host,$name,$pw,$dbname){
    $db_host=$host;
    $db_user=$user;
    $db_pw=$pw;
    $db_name=$dbname;

    ... und das musst du auch. So wie du es mit der self::$instance gemacht hast, musst du es auch mit den anderen Klassenvariablen machen.
    Allerdings darf das Setzen der Zugangsdaten - so du es doch von außen tun willst - nicht als Methode der Instanz implementiert sein. Denn in dem Fall müsste der erste Verwender die Zugangsdaten setzen und die anderen brauchen und dürfen das nicht mehr. Woher weiß denn aber der erste, dass er der erste ist? Er muss das nicht wissen, muss sich also auch nicht um die Zugangsdaten kümmern müssen.

    Wenn du dabei bleibst und die Daten explizit bereitstellst, dann mach das mit einer statischen Methode, die irgendwo am Scriptanfang mit anderen Initialisierungsaufgaben aufgerufen wird. Normalerweise müsste sich diese Methode auch noch gegen Zweitaufruf wehren. Wenn also beispielsweise der Host schon gesetzt ist, dann ein ignorierendes return; oder dem Aufrufer einen Fehler vor die Füße werfen.

    # Zur Datenbank verbinden
            public function db_connect()

    Der Verbindungsauf- und -abbau ist auch keine Angelegenheit der Verwender. Die stellen solche Anforderungen wie eine Query auszuführen. Wenn dazu eine Verbindung benötigt wird, muss das die Query-Methode bei Bedarf erledigen. Sie kann dazu eine private Connect-Methode aufrufen, welche ihrerseits nachschaut, ob die Verbindung schon besteht und wenn nicht, sie herstellt.

    if (mysqli_connect_errno()) {
        printf("Connect failed: %s\n", mysqli_connect_error());
         exit();
       } else {
        echo "alles korrekt";

    Aufgabe der DB-Klasse ist nicht, auf den Bildschirm zu malen. Wenn sie sich mitzuteilen gedenkt, dann über Rückgabewerte oder Fehlermeldungen oder Exceptions.

    $user="name";
    $pw="pw";
    $sql="INSERT INTO users(user,pw) VALUES('".$user."','".$pw."')";

    Wenn du die Query selbst zusammenbaust, musst du dich auch selbst um die kontextgerechte Behandlung kümmern. Mit diesen beiden Werten ist das zwar nicht nötig, aber wenn es nur ein Test sein sollte, hättest du die Werte auch direkt in die Query einbauen können.

    Fatal error: Call to a member function query() on a non-object in C:\xampp\htdocs\_next\allethemen\classes\class.db.php on line 52
    Line: 52 $db_connection->query($query);
    Was ist denn daran falsch? Warum ist es kein Objekt, ich habe es doch oben als Objekt instanziert:

    Kontrollausgaben! Mit einer solchen hättest du sehen können, dass $db_connection null ist. Und mit einem aus E_ALL stehenden error_reporting hätte auch noch ein Zugriff auf eine nicht vorhandene Variable angezeigt werden müssen.

    Es ist also kein Objekt sondern eine nicht vorhandene Variable. Es gehört zum Grundlagenwissen der OOP, einfache Variablen von Instanzvariablen von Klassenvariablen zu unterscheiden. Alle drei Typen werden unterschiedlich notiert.

    echo "$verabschiedung $name";

    1. Hello,

      # Datenbankwerte setzen  
      public function db\_set\_vars($host,$name,$pw,$dbname){  
        $db\_host=$host;  
        $db\_user=$user;  
        $db\_pw=$pw;  
        $db\_name=$dbname;  
      

      ... und das musst du auch. So wie du es mit der self::$instance gemacht hast, musst du es auch mit den anderen Klassenvariablen machen.
      Allerdings darf das Setzen der Zugangsdaten - so du es doch von außen tun willst - nicht als Methode der Instanz implementiert sein. Denn in dem Fall müsste der erste Verwender die Zugangsdaten setzen und die anderen brauchen und dürfen das nicht mehr. Woher weiß denn aber der erste, dass er der erste ist?

      Was meinst Du, wofür es die Methode getInstance() gibt und wofür ein Konstruktor vorhanden ist?
      Zweitere ist mMn der richtige Platz, um Anfangswerte zu setzen!

      Aufgabe der DB-Klasse ist nicht, auf den Bildschirm zu malen. Wenn sie sich mitzuteilen gedenkt, dann über Rückgabewerte oder Fehlermeldungen oder Exceptions.

      $user="name";
      $pw="pw";
      $sql="INSERT INTO users(user,pw) VALUES('".$user."','".$pw."')";

      ACK

      Wenn du die Query selbst zusammenbaust, musst du dich auch selbst um die kontextgerechte Behandlung kümmern. Mit diesen beiden Werten ist das zwar nicht nötig, aber wenn es nur ein Test sein sollte, hättest du die Werte auch direkt in die Query einbauen können.

      Die Werte sollten der Query typgerecht übergeben werden. Dazu muss man aber die Spaltentypen, ihre Ranges und Defaults vorher beschaffen. Alternativ sind wir dann bei prepared Statements, weil eine textuelle Schnittstelle (SQL) bei Verwendung einer komplexen API/Datenbankklasse kaum noch Existenzberechtigung hat.

      Liebe Grüße aus dem Cyberspace

      Tom vom Berg

      --
      Nur selber lernen macht schlau
      http://bergpost.annerschbarrich.de
      1. echo $begrüßung;

        » Allerdings darf das Setzen der Zugangsdaten - so du es doch von außen tun willst - nicht als Methode der Instanz implementiert sein. Denn in dem Fall müsste der erste Verwender die Zugangsdaten setzen und die anderen brauchen und dürfen das nicht mehr. Woher weiß denn aber der erste, dass er der erste ist?

        Was meinst Du, wofür es die Methode getInstance() gibt und wofür ein Konstruktor vorhanden ist?
        Zweitere ist mMn der richtige Platz, um Anfangswerte zu setzen!

        Das Szenario sieht vor, dass es eine einzige Datenbankverbindung im gesamten Script gibt. Deswegen werwenden wir ja hier auch das Singleton-Pattern.

        getInstance() ist für die Herausgabe der Instanz zuständig. Die Konfigurationsdaten hat es nicht entgegenzunehmen. getInstance() soll nämlich mehrfach aufgerufen werden können, je nach Bedarf und es soll dabei immer die selbe Datenbankverbindung verwendet werden. Die Verwender haben nicht die Aufgabe, sich um die Konfigurationsdaten zu kümmern.

        Der Konstruktor ist im Singleton-Pattern primär vorhanden, damit man ihn privatisieren kann. Initialisierungsaufgaben kann er auch übernehmen, wenn das notwendig ist. Hier könnte er sich beispielsweise um das Holen der Konfigurationsdaten kümmern. Das kann aber auch erst die Connect-Funktion machen, denn die benötigt die Daten nur ein einziges Mal. Wenn die Verbindung erst einmal steht sind sie nutzlos.

        Die Werte sollten der Query typgerecht übergeben werden. Dazu muss man aber die Spaltentypen, ihre Ranges und Defaults vorher beschaffen. Alternativ sind wir dann bei prepared Statements, weil eine textuelle Schnittstelle (SQL) bei Verwendung einer komplexen API/Datenbankklasse kaum noch Existenzberechtigung hat.

        Dass das automatisierte Bedienen von Prepared Statements unter mysqli mit einigem Aufwand verbunden ist, habe ich im ursprünglichen Faden schon dargelegt und Chris mittlerweile erfolgreich davon abgebracht. Der Aufwand des Quotierens und Maskierens ist dagegen ein Kinderspiel. P.S. unter mysqli lohnen sich effektiv nur, wenn man sie in der in den Handbuchbeispielen gezeigten Weise verwendet.

        Unter MySQL benötigt man eigentlich nur zwei Parametertypen: String und Ausdruck. Datums-und Zeit-Werte werden als String übergeben, mit Zahlen geht das ebenso problemlos. - Wenn man will, kann man jedoch die Parameter auf ihren Typ testen. Ist es ein Zahlentyp (is_int() oder is_float(), nicht aber is_numeric()), kann man ihn ohne Behandlung in die Query einbauen. Arrays, Objekte und Ressourcen sind abzulehnen. Boolean erfordert einen Typecast zu Integer. Auch Null ist testbar. Übrig bleiben Strings, die können mit der üblichen Behandlung in die Query eingefügt werden. Ob letztlich der Feldtyp passt ist aus sicherheitstechnischer Sicht egal. Die fachliche Püfung sehe ich als Aufgabe der Datenklasse und nicht der Datenbankklasse an. Die Datenbankklasse muss sich nicht prinzipiell gegen sämtliche Unfähigkeiten des anwendenden Programmierers schützen. Das ist schließlich Aufwand der auch bei fehlerfreier Verwendung betrieben werden muss. Mir reicht es für die allgemeine Anwendungszwecke, wenn sie sicherheitstechnisch keine Lücke aufweist.

        Ausdrücke erfordern ein anderes Herangehen. Wenn es möglich ist, sollten sie natürlich direkter Bestandteil des Querystrings werden und nur eventuelle Parameter dieser Ausdrücke noch eingefügt werden müssen. Lässt es sich nicht vermeiden und man will unbedingt übergeben können, hat man ein kleines Problem, denn sie sehen auch wie Strings aus, dürfen aber nicht als solche behandelt werden. Abhilfe kann man mit einer kleinen Wrapperklasse schaffen. Wenn Parameter instanceof Ausdrucksklasse ...

        echo "$verabschiedung $name";

  7. Okay, danke für die ganzen Beiträge, ich habe mir jeden durchgelesen.
    Da prallt soviel Fachwissen gegeneinander das ich nicht mehr durchblicke.

    Meine Klasse funktioniert jetzt:

      
    class db{  
      
    	protected static $_instance;  
    	protected static $_db_host;  
    	protected static $_db_user;  
    	protected static $_db_pw;  
    	protected static $_db_name;  
    	protected static $_db_connection;  
    	  
    	  
    	  
    	# Konstruktor - private - kann nicht aufgerufen werden  
    	private function __construct(){}  
    	  
    	# Singleton  
    	public static function db_singleton()  
        {  
            if (!isset(self::$_instance)) {  
                self::$_instance = new db();  
            }  
      
            return self::$_instance;  
        }  
    	  
    	# Datenbankwerte setzen  
    	public static function db_set_vars($host,$name,$pw,$dbname){  
    		self::$_db_host=$host;  
    		self::$_db_user=$name;  
    		self::$_db_pw=$pw;  
    		self::$_db_name=$dbname;  
    		  
    	}  
    	  
    	  
    	# Zur Datenbank verbinden  
    	public static function db_connect()  
        {  
           self::$_db_connection = new MySQLi(self::$_db_host, self::$_db_user, self::$_db_pw, self::$_db_name);  
    	   if (mysqli_connect_errno()) {  
       			printf("Connect failed: %s\n", mysqli_connect_error());  
        		exit();  
    	   } else {  
    	   		echo "alles korrekt";  
    	   }  
        }  
    	  
    	  
    	# Query ausführen  
    	public static function db_query($query){  
    		self::$_db_connection->query($query);  
    	}  
    	  
    	# Clone - unterbinden  
    	public function __clone()  
        {  
            trigger_error('Clone is not allowed.', E_USER_ERROR);  
        }  
    }  
      
    $db=db::db_singleton();  
    $db->db_set_vars('localhost','root','philz','allethemen');  
    $db->db_connect();  
      
    $sql="INSERT INTO users(user,pw) VALUES('name','pw')";  
    $db->db_query($sql);  
    
    

    So..
    Mir gefallen aber einige Dinge nicht und es tun sich noch einige Fragen auf:
    1.
    Man betrachtet:

    $db=db::db_singleton();  
    $db->db_set_vars('localhost','root','philz','allethemen');  
    $db->db_connect();
    

    Das ist mir zu umständlich, ich hätte viel lieber das wenn ich das Singleton erstelle, die Klasse die Zugangsdaten schon hat _und_ den Connect vornimmt.
    Aus

    $db=db::db_singleton();  
    $db->db_set_vars('localhost','root','philz','allethemen');  
    $db->db_connect();
    

    soll

    $db=db::db_singleton();

    werden und es soll das gleiche passieren.

    2. Das Singleton. Erstelle ich es einmal am Anfang von index.php oder macht das jede Klasse die es benötigt, was dann lazy? wäre?

    3. Wie könnte die Vorabübergabe der Daten stattfinden.
    Generell werden _alle_ Settings-Daten in einer settings.php stehen.
    Sprich bei einem Serverumzug, Domainwechsel usw müsste eh einfach nur alles in der "Settings.php" geändert werden.

    4. Dedlfix und Tom ihr errinnert dich denk ich. Ich habe noch eine Tools Klasse und eine Ext.Database Klasse mit Zusatzfunktionen.
    Die Tools Klasse wird static, ich werde sie in fast jeder zweiten Klasse brauchen.
     4.1 _Was_ kommt noch in die db-Klasse rein?
     4.2 wie würdet ihr mit den beiden anderen Klassen verfahren?

    5. Die Frage des Destruktors sehe ich in all den Beiträgen immernoch nicht geklärt.
    Destruktor Ja/Nein?, warum?, rufe ich ihn auf?, wann?, ruft er sich selber auf?

    6. Wie betreibe ich in dem Fall am besten die Fehlerbehandlung?
    Meine Ideen wären:
    1. Die Fehler in eine TXT zu schreiben
    2. Es gibt 2 Modis. a. Entwicklung, b. WWWW.
    Alle Fehler werden an eine extra Fehlerbehandlungsklasse weitergegeben, dort wird eine Variable aus der settings.php abgefragt über den aktuellen Status (a oder b).
    a. Alles befindet sich in Entwicklung und auf meinem lokalen Webserver, es werden alle Fehler angezeigt und dick unterstrichen angegeben.
    b. Es wird die Verbindung zur DB überprüft. Ist sie vorhanden, werden die Fehler dort eingetragen. Ist sie nicht vorhanden, wird versucht sie dort nochmal aufzubauen ohne die DB-Klasse. Geht das nicht, werden die Fehler in eine TXT geschrieben oder per E-Mail an mich geschickt.

    Das wars erstmal.

    Danke euch.

    Lg, Chris

    1. echo $begrüßung;

      protected static $_instance;
      protected static $_db_host;
      protected static $_db_user;
      protected static $_db_pw;
      protected static $_db_name;
      protected static $_db_connection;

      Bitte private. Das Singleton-Pattern lässt keine Vererbung zu, also braucht es kein protected.

      $db=db::db_singleton();

      $db->db_set_vars('localhost','root','philz','allethemen');
      $db->db_connect();

      
      >   
      > Das ist mir zu umständlich, ich hätte viel lieber das wenn ich das Singleton erstelle, die Klasse die Zugangsdaten schon hat \_und\_ den Connect vornimmt.  
        
      Das hab ich ja schon so vorgeschlagen. Die Methode connect() sollte private sein. Alle Methoden, die einen Connect voraussetzen, rufen connect() auf. connect() baut die Verbindung auf, wenn sie noch nicht steht und ansonsten macht sie nichts. Die Zugangsdaten kann sie sich entweder von Klassenvariablen holen, die ganz am Script-Anfang, also noch vor jeglicher Verwendung von db\_singleton(), gesetzt wurden, oder sie holt sie sich aus einer definierten (z.B. ini-File).  
        
      
      > 2. Das Singleton. Erstelle ich es einmal am Anfang von index.php oder macht das jede Klasse die es benötigt, was dann lazy? wäre?  
        
      Du hast das Singleton-Pattern anscheinend noch nicht verstanden. Aus der Sicht der Verwender betrachtet, holt sich jeder nur über die getInstance-Methode die Instanz ab. Er kann damit sofort arbeiten, ohne sich um weitere Initialisierungen oder dergleichen zu kümmern. Aus Klassensicht sorgt getInstance für einen verwendungsfähigen Zustand der Instanz.  
        
      Die geöffnete Verbindung gehört nicht unbedingt zum verwendungsfähigen Zustand. Die kann wie schon beschrieben im Hintergrund bei tatsächlichem Bedarf eröffnet werden (lazy connect).  
        
      
      > 3. Wie könnte die Vorabübergabe der Daten stattfinden.  
      > Generell werden \_alle\_ Settings-Daten in einer settings.php stehen.  
        
      Oder eine ini-Datei.  
        
      
      > 4. Dedlfix und Tom ihr errinnert dich denk ich. Ich habe noch eine Tools Klasse und eine Ext.Database Klasse mit Zusatzfunktionen.  
      >  4.1 \_Was\_ kommt noch in die db-Klasse rein?  
        
      Ich würde sie public nur mit den RUDI-Funktionen ausstatten, also Read (SELECT), Update, Delete und Insert. Wenn Bedarf in Sicht ist, kann sie immer noch erweitert werden.  
        
      
      >  4.2 wie würdet ihr mit den beiden anderen Klassen verfahren?  
        
      Dazu müsstest du konkreter werden. Bau die Klassen mal als Rumpf auf, so dass man ihre Funktionen erkennen kann.  
        
      
      > 5. Die Frage des Destruktors sehe ich in all den Beiträgen immernoch nicht geklärt.  
      > Destruktor Ja/Nein?, warum?, rufe ich ihn auf?, wann?, ruft er sich selber auf?  
        
      Wenn überhaupt, wird er beim Singleton-Pattern nur automatisch aufgerufen, wenn PHP die Instanz wegräumt. Du kannst gern einen erstellen, der das Schließen der Verbindung vornimmt.  
        
      
      > 6. Wie betreibe ich in dem Fall am besten die Fehlerbehandlung?  
        
      Eine Klasse sollte so wenig wie möglich Fremdarbeiten erledigen. Das Schreiben ins Dateisystem erfordert beispielsweise Kenntnisse, wohin geschrieben werden soll. Vollständig behandeln kann die DB-Klasse die Fehler sowieso nicht. Sie weiß ja nicht, was die Verwender für den Fall eines Fehlers konkret vorhaben. Es ist sinnlos, das Logfile mit Meldungen vollzuschreiben, wenn explizit das Auftreten eines Fehlers vorgesehen ist. Es ist kein Logfile-Fehler, wenn ein Benutzer sich mit einer bereits vorhandenen Kennung zu registrieren versucht. Ein Insert mit dieser Kennung scheitert in dem Fall wegen Unique-Index-Verletzung. Man sagt dem Benutzer, dass er einen anderen Namen wählen muss und mehr Aufmerksamkeit benötigt diese Fehlermeldung nicht.  
        
      Wenn Fehler beim RUDI auftreten, sollten diese durch Rückgabewert oder Exception weitergemeldet werden. Reagieren und gegebenenfalls Maßnahmen treffen obliegt dem Verwender. Er muss sowieso drauf gefasst sein, dass Fehler auftreten. Einfach weiter machen wird nicht möglich sein, denn dazu fehlen ja die Daten, die man eigentlich dazu benötigte. Also muss ein alternativer Weg gegangen werden und damit hast du eine Fallunterscheidung (oder ein try-catch bei Exceptions).  
        
      
      > Alle Fehler werden an eine extra Fehlerbehandlungsklasse weitergegeben, dort wird eine Variable aus der settings.php abgefragt über den aktuellen Status (a oder b).  
        
      Nicht Fehler"behandlungs"klasse sondern eher ein Logging-Mechanismus, der generell verwendet werden kann. Beispielsweise dann wenn ein DB-Klassen-Verwender einen Fehler als log-würdig ansieht.  
        
      
      > a. Alles befindet sich in Entwicklung und auf meinem lokalen Webserver, es werden alle Fehler angezeigt und dick unterstrichen angegeben.  
        
      Das kann die Log-Klasse gern machen.  
        
      
      > b. Es wird die Verbindung zur DB überprüft. Ist sie vorhanden, werden die Fehler dort eingetragen. Ist sie nicht vorhanden, wird versucht sie dort nochmal aufzubauen ohne die DB-Klasse. Geht das nicht, werden die Fehler in eine TXT geschrieben oder per E-Mail an mich geschickt.  
        
      Auch das wäre eine Möglichkeit, was die Log-Klasse machen könnte.  
        
        
      echo "$verabschiedung $name";
      
      1. Bitte private. Das Singleton-Pattern lässt keine Vererbung zu, also braucht es kein protected.

        Done.

        Das hab ich ja schon so vorgeschlagen. Die Methode connect() sollte private sein. Alle Methoden, die einen Connect voraussetzen, rufen connect() auf. connect() baut die Verbindung auf, wenn sie noch nicht steht und ansonsten macht sie nichts. Die Zugangsdaten kann sie sich entweder von Klassenvariablen holen, die ganz am Script-Anfang, also noch vor jeglicher Verwendung von db_singleton(), gesetzt wurden, oder sie holt sie sich aus einer definierten (z.B. ini-File).

        Also soll ich den Connect nicht automatisch mit dem Aufruf des Singleton machen? Weil ich mein, wenn ich das Singleton aufbaue, dann will ich auch die Verbindung haben. Logisch.
        Also soll die Zuweisung in der ini stattfinden.
        Sprich es steht dort z.b. drin:

        db->_db_host="localhost";

        ? Oder wie?
        Die Zugangsdatenvariablen sind ja static also müsste das doch so gehen.
        Die Werte kann ich ja aufgrund des "static" übergeben bevor das Singleton geholt wird.

        Du hast das Singleton-Pattern anscheinend noch nicht verstanden. Aus der Sicht der Verwender betrachtet, holt sich jeder nur über die getInstance-Methode die Instanz ab. Er kann damit sofort arbeiten, ohne sich um weitere Initialisierungen oder dergleichen zu kümmern. Aus Klassensicht sorgt getInstance für einen verwendungsfähigen Zustand der Instanz.

        Alles klar, gechecked.

        Die geöffnete Verbindung gehört nicht unbedingt zum verwendungsfähigen Zustand. Die kann wie schon beschrieben im Hintergrund bei tatsächlichem Bedarf eröffnet werden (lazy connect).

        Halt immer wenn ich brauche, Singleton holen.

        »» 3. Wie könnte die Vorabübergabe der Daten stattfinden.
        »» Generell werden _alle_ Settings-Daten in einer settings.php stehen.

        Oder eine ini-Datei.

        Macht das groß einen Unterschied? Ist das nicht latte ob das ne PHP oder ini-Datei ist?

        Ich würde sie public nur mit den RUDI-Funktionen ausstatten, also Read (SELECT), Update, Delete und Insert. Wenn Bedarf in Sicht ist, kann sie immer noch erweitert werden.

        Okay ich werde morgen hier mal eine Pseudo-Klasse reinschreiben.

        »»  4.2 wie würdet ihr mit den beiden anderen Klassen verfahren?

        Dazu müsstest du konkreter werden. Bau die Klassen mal als Rumpf auf, so dass man ihre Funktionen erkennen kann.

        Folgt.. schaff ich heute nicht mehr.

        »» 6. Wie betreibe ich in dem Fall am besten die Fehlerbehandlung?

        Eine Klasse sollte so wenig wie möglich Fremdarbeiten erledigen. Das Schreiben ins Dateisystem erfordert beispielsweise Kenntnisse, wohin geschrieben werden soll. Vollständig behandeln kann die DB-Klasse die Fehler sowieso nicht. Sie weiß ja nicht, was die Verwender für den Fall eines Fehlers konkret vorhaben. Es ist sinnlos, das Logfile mit Meldungen vollzuschreiben, wenn explizit das Auftreten eines Fehlers vorgesehen ist. Es ist kein Logfile-Fehler, wenn ein Benutzer sich mit einer bereits vorhandenen Kennung zu registrieren versucht. Ein Insert mit dieser Kennung scheitert in dem Fall wegen Unique-Index-Verletzung. Man sagt dem Benutzer, dass er einen anderen Namen wählen muss und mehr Aufmerksamkeit benötigt diese Fehlermeldung nicht.

        Ich meinte nur RUDI Fehler ;)

        Wenn Fehler beim RUDI auftreten, sollten diese durch Rückgabewert oder Exception weitergemeldet werden. Reagieren und gegebenenfalls Maßnahmen treffen obliegt dem Verwender. Er muss sowieso drauf gefasst sein, dass Fehler auftreten. Einfach weiter machen wird nicht möglich sein, denn dazu fehlen ja die Daten, die man eigentlich dazu benötigte. Also muss ein alternativer Weg gegangen werden und damit hast du eine Fallunterscheidung (oder ein try-catch bei Exceptions).

        Und weiter?

        Das kann die Log-Klasse gern machen.

        Okay also werden die RUDI Fehler an die LogKlasse weitergegeben...

        1. Hello,

          Bitte private. Das Singleton-Pattern lässt keine Vererbung zu, also braucht es kein protected.

          Das hab ich ja schon so vorgeschlagen. Die Methode connect() sollte private sein. Alle Methoden, die einen Connect voraussetzen, rufen connect() auf. connect() baut die Verbindung auf, wenn sie noch nicht steht und ansonsten macht sie nichts. Die Zugangsdaten kann sie sich entweder von Klassenvariablen holen, die ganz am Script-Anfang, also noch vor jeglicher Verwendung von db_singleton(), gesetzt wurden, oder sie holt sie sich aus einer definierten (z.B. ini-File).

          Also soll ich den Connect nicht automatisch mit dem Aufruf des Singleton machen? Weil ich mein, wenn ich das Singleton aufbaue, dann will ich auch die Verbindung haben. Logisch.

          MMn solltest Du das ruhig tun.

          Du benötigst also eine Methode init(), die den Anfangszustand herstellt und z.B. die Zugangsdaten und weitere Voreinstellungen aus einem _extra_ ini-File beschafft. Dafür hat PHP die Funktion parse_ini_file() http://www.php.net/manual/de/function.parse-ini-file.php

          Dann benötigst Du die Methode connect(), die mit den beschafften Daten die Verbindung aufbaut.

          Beide kannst Du im Konstruktor aufrufen, natürlich connect() nur, wenn init() geklappt hat.

          Also soll die Zuweisung in der ini stattfinden.
          Sprich es steht dort z.b. drin:

          db->_db_host="localhost";

          ? Oder wie?

          siehe Doku zu parse_ini_file

          Ich habe übrigens noch nie ausprobiert, ob man in einer Klasse ein Array auch als private anlegen kann, das auszuprobieren wäre doch eine gute Übung für Dich  :-))

          Die Zugangsdatenvariablen sind ja static also müsste das doch so gehen.

          Ich sehe nicht, warum die static sein müssen. MMn reicht da private aus. Es gibt ja sowieso nur eine Instanz von der Klasse. Und wenn Du Dir das später mal anders überlegen solltest, bräuchtest Du dann  nur den Konstruktor wieder public machen, oder z.B. im Singleton Arbeitsbereiche einrichten, wenn Du darüber die Anzahl nur beschränken willst. Static ist also für diese Daten definitv falsch!

          Die Werte kann ich ja aufgrund des "static" übergeben bevor das Singleton geholt wird.

          Wie willst Du das machen? Willst Du sie hard codieren? Dann stehen sie sichtbar in der Klasse.

          Liebe Grüße aus dem Cyberspace

          Tom vom Berg

          --
          Nur selber lernen macht schlau
          http://bergpost.annerschbarrich.de
          1. Hi.

            Ich verstehe nicht warum ich jetzt auf einmal mit dem Konstruktor arbeiten soll wenn dieser doch garnicht aufgerufen werden kann aufgrund des Singleton..

            lg, chris

            1. Hai,

              Ich verstehe nicht warum ich jetzt auf einmal mit dem Konstruktor arbeiten soll wenn dieser doch garnicht aufgerufen werden kann aufgrund des Singleton..

              Der Konstruktor wird pro Request genau einmal aufgerufen. Naemlich genau dann, wenn die GetSingleton-Methode das erste Mal aufgerufen wurde. Dort kannst du dann die Connection-Parameter aus der ini-Datei auslesen und die Verbindung aufbauen.

              @Tom:

              Ich habe übrigens noch nie ausprobiert, ob man in einer Klasse ein Array auch als private anlegen kann

              Es ist gaenzlich egal um was fuer einen Datentypen es sich handelt.

              MfG,
              Sympatisant

              --
              "If the future isn't bright, at least it is colorful"
              1. Hello,

                @Tom:

                Ich habe übrigens noch nie ausprobiert, ob man in einer Klasse ein Array auch als private anlegen kann
                Es ist gaenzlich egal um was fuer einen Datentypen es sich handelt.

                Das war eignetlich für Chris bestimmt :-))
                Und außerdem war es gelogen *duck*

                Liebe Grüße aus dem Cyberspace

                Tom vom Berg

                --
                Nur selber lernen macht schlau
                http://bergpost.annerschbarrich.de
        2. echo $begrüßung;

          Also soll ich den Connect nicht automatisch mit dem Aufruf des Singleton machen? Weil ich mein, wenn ich das Singleton aufbaue, dann will ich auch die Verbindung haben. Logisch.

          Jein. So logisch ist das am Ende nicht in jedem Fall. Wenn du für den Anfang den Verbindungsaufbau im Konstruktor (oder anders gesagt: beim erstmaligen Anfordern der Instanz) erledigst, ist das in Ordnung. Das ist dann etwas einfacher zu implentieren als ein Lazy Connect.

          Aber mal angenommen, es gäbe Methoden, die keine Verbindung brauchen und weiterhin angenommen, dass in einem Request nur solche Methoden verwendet werden, dann wäre der Verbindungsaufbau umsonst. Oder eine Codeteil fordert die Instanz an, macht aber erst noch was länger dauerndes bevor er zur Datenabfrage kommt, dann belegte die Verbindung schon eine ganze Weile umsonst die Ressourcen. In beiden Fällen wäre ein Lazy Connect eine feine Sache. Lassen wir es also der Einfachheit halber beim Connect im Konstruktor.

          Also soll die Zuweisung in der ini stattfinden.

          Soll nicht unbedingt, war nur ein Vorschlag.

          Sprich es steht dort z.b. drin:
          db->_db_host="localhost";
          ? Oder wie?

          So ähnlich. Beispiele für das ini-Format findest du im Handbuch bei der Funktion parse_ini_file().

          Macht das groß einen Unterschied? Ist das nicht latte ob das ne PHP oder ini-Datei ist?

          Eine ini-Datei ist einfacher zu warten, weil ihre Syntaxregeln nicht so komplex sind wie die von PHP. Du kannst auch in einer PHP-Datei Variablen setzen, wenn dir das besser gefällt.

          » Wenn Fehler beim RUDI auftreten, sollten diese durch Rückgabewert oder Exception weitergemeldet werden. Reagieren und gegebenenfalls Maßnahmen treffen obliegt dem Verwender. Er muss sowieso drauf gefasst sein, dass Fehler auftreten. Einfach weiter machen wird nicht möglich sein, denn dazu fehlen ja die Daten, die man eigentlich dazu benötigte. Also muss ein alternativer Weg gegangen werden und damit hast du eine Fallunterscheidung (oder ein try-catch bei Exceptions).

          Und weiter?

          Diese Antwort ist so pauschal nicht möglich sondern muss für jeden Anwendungsfall individuell gefunden werden. Du musst dir dazu überlegen, was im Fehlerfall für den Anwender das Beste ist und was du als Admininistrator zum Fehler brauchst. Diese Überlegungen solltest du dann in Code umsetzen.

          Ich hatte ja das Beispiel mit dem bereits vorhandenen Benutzernamen gebracht. In dem Fall benötigt der Anwender eine Information, dass er einen neuen Namen wählen muss und der Admin braucht nichts. Wenn generell die Verbindung ausgefallen ist, braucht der Anwender eine Tröstmeldung und beispielsweise Anweisungen, wie er trotzdem seine Bestellung loswerden kann. Der Admin braucht eine Sofortbenachrichtigung, damit er das System wieder in Gang bringt und keine weiteren Kunden verärgert werden. Fortsetzbar mit beliebigen Szenarien ...

          echo "$verabschiedung $name";

      2. Hey!

        Ich würde sie public nur mit den RUDI-Funktionen ausstatten, also Read (SELECT), Update, Delete und Insert. Wenn Bedarf in Sicht ist, kann sie immer noch erweitert werden.

        Hm ich überlege gerade wie sollche Funktionen aussehen sollen, meinst du ne Methode die die Satements dynamisch erzeugt? Siehe: hier sowas aus meinem "Komplettes Projekt in OOP"-v1 ?

        »»  4.2 wie würdet ihr mit den beiden anderen Klassen verfahren?

        Dazu müsstest du konkreter werden. Bau die Klassen mal als Rumpf auf, so dass man ihre Funktionen erkennen kann.

        class db.ext{  
          
        function __construct(){}  
          
        function getLastInsertId($result){}  
          
        function fetchObject($result){}  
          
        function countFoundOrAffectedRows($result){}  
          
        function freeSQLresult($result){}  
          
        function resultObject2array($object){}  
          
        function countEntries($table)(){}  
          
        function deleteTableEntries(){}  
          
        }
        

        Und in der Toolsklasse nützliche Funktionen wie:

          
        class tools{  
          
        function __construct(){}  
          
        function timestamp2Date(){}  
          
        function date2timestamp(){}  
          
        function compare_array_numbers($array_1,$array_2){}  
          
        }  
        
        

        So...

        1. echo $begrüßung;

          » Ich würde sie public nur mit den RUDI-Funktionen ausstatten, also Read (SELECT), Update, Delete und Insert. Wenn Bedarf in Sicht ist, kann sie immer noch erweitert werden.
          Hm ich überlege gerade wie sollche Funktionen aussehen sollen, meinst du ne Methode die die Satements dynamisch erzeugt?

          Ich muss mich korrigieren. Statements zusammenzubauen ist nicht unbedingt eine Aufgabe für die Verbindungsklasse. Die Verbindungsklasse bekäme bei mir nur eine generische Query-Methode, also eine, die Query-String mit Platzhaltern und Array mit den Werten entgegennimmt, beides zusammenbaut (oder Prepared Statements dafür verwendet, wenn diese nicht so umständlich zu bedienen wären wie bei mysqli), die Query ausführt und das Ergebnis (z.B. als fertig abgefragtes Array) zurückliefert. Gegebenenfalls weitere zum Verbindung gehörende Dinge, wie erzeugte ID beim Insert, Anzahl der betroffenen Datensätze, doch das gehört eigentlich als Meta-Information mit ins Ergebnis. Weitere Methoden für die Verbindungsklasse könnten solche sein, die Meta-Informationen zum System ermitteln. Versionsnummer des Servers, Struktur von Tabellen (was für Tom), Werte von Konfigurationsparametern abfragen oder setzen. Das ist aber alles nur mehr oder weniger Schnickschnack, den du fürs Erste weglassen kannst.

          » »  4.2 wie würdet ihr mit den beiden anderen Klassen verfahren?
          [code lang=php]class db.ext{
          function getLastInsertId($result){}

          Dazu braucht es direkt die Verbindung. Ein Kandidat für die db-Klasse.

          function fetchObject($result){}

          Eine intern benötigte Funktion bei der Erzeugung des Ergebnisses. Meine Idee der Query-Methode liefert bereits eine fertig abgefragte Ergebnismenge in Form eines Arrays mit je einem Array oder Objekt pro Datensatz. Wenn du das Fetchen den Verwendern überlässt, brauchst du keine eigene db-Klasse zu erstellen. Das gibt es fertig als mysqli-Extension. Um eine eigene Klasse zu rechtfertigen brauchst du irgendwelche Vorteile gegenüber dem Vorhandenen. Sich nicht um die Details des Fetch-Prozesses kümmern zu müssen, wäre ein Vorteil für die Verwender.

          function countFoundOrAffectedRows($result){}

          Auch dazu brauchst du die Verbindung, kannst das also nicht auslagern. Ansonsten ist das Meta-Information zum Ergebnis, sollte also zu diesem dazugeliefert werden.

          function freeSQLresult($result){}

          Gemäß meiner Vorstellung wird das Ergebnis ja von der Query-Methode komplett abgeholt, dort können dann auch die Result-Ressourcen aufgeräumt werden.

          function resultObject2array($object){}

          Ein Parameter der Query-Methode könnte ein Flag sein, das angibt, ob du ein Array mit Objekten oder ein Array mit Arrays als Ergebnis haben möchtest.

          function countEntries($table)(){}

          Kannste streichen, geht mit count($ergebnisarray);

          function deleteTableEntries(){}

          Ein Delete-Statement zusammenzubauen ist Teil der RUDI-Funktionalität.

          Statements zu erstellen ist teilweise nicht schwer, für das üblichen UDI-Aufgaben. Auch ein Select-Statement ist für einfache Anwendungsfälle automatisch und mit geringem Aufwand erstellbar. Doch SQL zeigt seine Stärken erst bei komplexeren Statements. Willst du diese automatisch zusammenbauen lassen, brauchst du bei geschachtelten AND-OR-verknüpften Bedingungen schonmal eine Strategie, wie man sowas als zu übergebenden Parameter einer PHP-Funktion gestaltet. Joins sind die nächste komplexe Stufe und Subselects, womöglich noch korreliert, machen die ganze Chose nicht einfacher. Und ein komplexes Statement immer wieder zusammenbauen zu lassen ist auch nicht gerade eine ressourcenschonende Angelegenheit.

          Ein Kompromiss ist, RUDI-Statements-Ersteller für einfache Aufgaben zu verwenden und komplexe Abfragen (alles was über SELECT * FROM ... ORDER BY ... LIMIT ... hinausgeht) direkt zu formulieren.

          Und in der Toolsklasse nützliche Funktionen wie:
          function timestamp2Date(){}
          function date2timestamp(){}
          function compare_array_numbers($array_1,$array_2){}

          Was auch immer die letzte Methode genau machen soll ... alle drei sind DBMS-unabhängige Funktionalität. Das ist in einer Allgemeine-Tools-Klasse gut aufgehoben. Wobei allerdings MySQL Funktionen für das Umrechnen von Timestamps mitbringt (FROM_UNIXTIME() und UNIX_TIMESTAMP()). Wenn du also mit PHP Unix-Timestamps verarbeiten willst, dann kann MySQL die gleich so übergeben und übernehmen, entsprechende Funktionsaufrufe in der Query vorausgesetzt.

          echo "$verabschiedung $name";

          1. Ich muss mich korrigieren. Statements zusammenzubauen ist nicht unbedingt eine Aufgabe für die Verbindungsklasse. Die Verbindungsklasse bekäme bei mir nur eine generische Query-Methode, also eine, die Query-String mit Platzhaltern und Array mit den Werten entgegennimmt, beides zusammenbaut (oder Prepared Statements dafür verwendet, wenn diese nicht so umständlich zu bedienen wären wie bei mysqli), die Query ausführt und das Ergebnis (z.B. als fertig abgefragtes Array) zurückliefert. Gegebenenfalls weitere zum Verbindung gehörende Dinge, wie erzeugte ID beim Insert, Anzahl der betroffenen Datensätze, doch das gehört eigentlich als Meta-Information mit ins Ergebnis. Weitere Methoden für die Verbindungsklasse könnten solche sein, die Meta-Informationen zum System ermitteln. Versionsnummer des Servers, Struktur von Tabellen (was für Tom), Werte von Konfigurationsparametern abfragen oder setzen. Das ist aber alles nur mehr oder weniger Schnickschnack, den du fürs Erste weglassen kannst.

            Sprich sowas hier... [1]

            »» function fetchObject($result){}

            Eine intern benötigte Funktion bei der Erzeugung des Ergebnisses. Meine Idee der Query-Methode liefert bereits eine fertig abgefragte Ergebnismenge in Form eines Arrays mit je einem Array oder Objekt pro Datensatz. Wenn du das Fetchen den Verwendern überlässt, brauchst du keine eigene db-Klasse zu erstellen. Das gibt es fertig als mysqli-Extension. Um eine eigene Klasse zu rechtfertigen brauchst du irgendwelche Vorteile gegenüber dem Vorhandenen. Sich nicht um die Details des Fetch-Prozesses kümmern zu müssen, wäre ein Vorteil für die Verwender.

            Hm aber die spalten heißen doch immer anders und sind unterschiedlich viel.. irgendwie blick ich nicht durch wie ich das realisieren soll..

            Wenn die Funktionen die Verbindung bruachen ist das doch egal, es ist doch Singleton!?

            »» function freeSQLresult($result){}

            Gemäß meiner Vorstellung wird das Ergebnis ja von der Query-Methode komplett abgeholt, dort können dann auch die Result-Ressourcen aufgeräumt werden.

            Das macht Sinn, danke.

            »» function resultObject2array($object){}

            Ein Parameter der Query-Methode könnte ein Flag sein, das angibt, ob du ein Array mit Objekten oder ein Array mit Arrays als Ergebnis haben möchtest.

            S.o. ich weiß noch nicht genau wie ich das umsetzen soll.

            »» function countEntries($table)(){}

            Kannste streichen, geht mit count($ergebnisarray);

            Die Funktion sollte eigendlich per "COUNT(spaltenname) AS anzahl" o.ä. fungieren.

            Statements zu erstellen ist teilweise nicht schwer, für das üblichen UDI-Aufgaben. Auch ein Select-Statement ist für einfache Anwendungsfälle automatisch und mit geringem Aufwand erstellbar.

            Siehe [1] ?

            Doch SQL zeigt seine Stärken erst bei komplexeren Statements. Willst du diese automatisch zusammenbauen lassen, brauchst du bei geschachtelten AND-OR-verknüpften Bedingungen schonmal eine Strategie, wie man sowas als zu übergebenden Parameter einer PHP-Funktion gestaltet. Joins sind die nächste komplexe Stufe und Subselects, womöglich noch korreliert, machen die ganze Chose nicht einfacher. Und ein komplexes Statement immer wieder zusammenbauen zu lassen ist auch nicht gerade eine ressourcenschonende Angelegenheit.
            Ein Kompromiss ist, RUDI-Statements-Ersteller für einfache Aufgaben zu verwenden und komplexe Abfragen (alles was über SELECT * FROM ... ORDER BY ... LIMIT ... hinausgeht) direkt zu formulieren.

            Das hatte ich auch so vor, JOINS usw lasse ich nicht zusammenbauen..

            »» Und in der Toolsklasse nützliche Funktionen wie:
            »» function timestamp2Date(){}
            »» function date2timestamp(){}
            »» function compare_array_numbers($array_1,$array_2){}

            Was auch immer die letzte Methode genau machen soll ...

            Zwei Arrays vergleichen ob Sie gleichgroß sind...(war für dynamisch erzeugte PS gedacht)...

            alle drei sind DBMS-unabhängige Funktionalität. Das ist in einer Allgemeine-Tools-Klasse gut aufgehoben. Wobei allerdings MySQL Funktionen für das Umrechnen von Timestamps mitbringt (FROM_UNIXTIME() und UNIX_TIMESTAMP()). Wenn du also mit PHP Unix-Timestamps verarbeiten willst, dann kann MySQL die gleich so übergeben und übernehmen, entsprechende Funktionsaufrufe in der Query vorausgesetzt.

            Gut das mit der Uhrzeit lässt sich auch direkt im Query erledigen.
            lg, chris

            1. echo $begrüßung;

              » »» function fetchObject($result){}
              Hm aber die spalten heißen doch immer anders und sind unterschiedlich viel.. irgendwie blick ich nicht durch wie ich das realisieren soll..

              Das ist ja kein Problem. Die üblichen assoziierenden und objektorientierten Fetch-Funktionen liefern alle Spalten, egal wieviele es sind. Dieses Array oder Objekt je Ergebnismelngenzeile hängst du an ein alle Zeilen enthaltendes Ergebnis-Array an. Derjenige, der die Datenmenge angefordert hat, weiß auch, was ihn erwartet. Ansonsten kann er immer noch durch die einzelnen Spalten "foreachen" (notfalls das Fetch-Objekt in ein Array casten).

              » »» function countEntries($table)(){}
              » Kannste streichen, geht mit count($ergebnisarray);
              Die Funktion sollte eigendlich per "COUNT(spaltenname) AS anzahl" o.ä. fungieren.

              OK. Bedenke aber auch, dass es SQL_CALC_FOUND_ROWS und FOUND_ROWS() gibt, wenn du von einer limitierten Abfrage die Anzahl der unlimitierten Datensätze brauchst.

              echo "$verabschiedung $name";

              1. Hallo.

                »» » »» function fetchObject($result){}
                »» Hm aber die spalten heißen doch immer anders und sind unterschiedlich viel.. irgendwie blick ich nicht durch wie ich das realisieren soll..

                Das ist ja kein Problem. Die üblichen assoziierenden und objektorientierten Fetch-Funktionen liefern alle Spalten, egal wieviele es sind. Dieses Array oder Objekt je Ergebnismelngenzeile hängst du an ein alle Zeilen enthaltendes Ergebnis-Array an. Derjenige, der die Datenmenge angefordert hat, weiß auch, was ihn erwartet. Ansonsten kann er immer noch durch die einzelnen Spalten "foreachen" (notfalls das Fetch-Objekt in ein Array casten).

                Ich lass mir ja ungern Code vor Füße legen aber in diesem Fall wäre ich dir dankbar wenn du diese "fetchResult()" Fkt. mal hier hin postest...

                Ich komm irgendwie nicht darauf klar Object 2 Array

                früher hab ichs immer so gemacht:

                $sql="SELECT name, email...";  
                $res=mysql_query($sql);  
                while($get=mysql_fetch_array($res)){  
                  echo $get['name']." : ".$get['email'];  
                }  
                  
                mysql_free_result($res); //[1]
                

                Zu [1]: In wiefern lohnt es sich eigendlich das zu machen? Lohnt es sich dafür eine Methode zu erstellen? Die dann mit mysqli_free_result das Ergebnis löscht?

                Ne weitere Frage:

                Wenn ich eine Klasse habe und meine Datenbank-Klasse(db) nutzen möchte, dann hole ich mir eine Instanz so:

                class beispiel{  
                  private static $dbcon;  
                  
                  public function __construct(){  
                   self::$dbcon=db::getInstance();  
                  }  
                }
                

                Damit arbeiten würde ich dann so:
                a)

                public workWith(){  
                  
                  self::$dbcon->db_query($sql);  
                  
                }
                

                Allerdings ginge doch auch direkt:
                b)

                public workWith(){  
                  db::db_query($sql);  
                }
                

                Da db_query eine statische Methode ist.
                Mir ist das erst später aufgefallen da ich atm zum üben eine Newsletterklasse schreibe. So versuche ich perfekt mit der db und der tools Klasse zusammen zuarbeiten.
                Mit der tools-Klasse mach ich das über tools::funktionsname();.. bei der db-Klasse hole ich mir erst eine Instanz und arbeite mit dieser, statt direkt db::funktionsname();.

                Lg, Chris

                1. echo $begrüßung;

                  Ich lass mir ja ungern Code vor Füße legen aber in diesem Fall wäre ich dir dankbar wenn du diese "fetchResult()" Fkt. mal hier hin postest...

                  Also, ich beschränke die Query erledigende Funktion mal auf das Nötigste. Das heißt, sie bekommt ein fertiges Statement ohne dass noch Parameter eingebaut werden können/müssen. Ebenfalls nicht mit berücksichtigt ist das Ermitteln und Zurückgeben von Result-Metadaten wie last_insert_id oder affected_rows.

                  /**  
                   * Query abarbeiten  
                   *  
                   * @param string $sql  ein SQL-Statement  
                   * @param mixed $asObject  false: Fetchen als Array  
                   *                         true: Fetchen als Objekt  
                   *                         string: Name der zu instantiierenden Klasse  
                   * @param array $objectParams  optionale Parameter @see mysqli_result::fetch_object()  
                   * @return array  Ergebnismenge als Array mit Arrays oder Objekten  
                   */  
                  function query($sql, $asObject = false, $objectParams = null) {  
                    $result = array();  
                    
                    $mysqli = $this->_getConnection(); // das ist eine private Methode, die mit ein mysqli-Objekt mit aktiver Verbindung gibt.  
                    
                    $mysqliResult = $mysqli->query($sql, MYSQLI_USE_RESULT);  
                    if (!$mysqliResult)  
                      throw new Exception(...);  
                    
                    if ($mysqliResult instanceof mysqli_result) {  
                      try {  
                    
                        if ($asObject) { // true oder string  
                          if (is_string($asObject)) {  
                            if (!class_exists($asObject))  
                              throw new Exception('class ' . $asObject . ' does not exist.');  
                          } else { // kein Klassenname übergeben, Standard-Klasse verwenden lassen  
                            $asObject = null;  
                            $objectParams = null;  
                          }  
                    
                          while ($row = $mysqliResult->fetch_object($asObject, $objectParams))  
                            $result[] = $row;  
                    
                        } else  
                          while ($row = $mysqliResult->fetch_assoc())  
                            $result[] = $row;  
                    
                      } finally {  
                        // wird unbedingt benötigt, wegen MYSQLI_USE_RESULT @see mysqli::query()  
                        $mysqliResult->free();  
                      }  
                    }  
                    
                    return $result;  
                  }
                  

                  Zu [1]: In wiefern lohnt es sich eigendlich das zu machen? Lohnt es sich dafür eine Methode zu erstellen? Die dann mit mysqli_free_result das Ergebnis löscht?

                  Es lohnt sich, wenn es sein muss (wie in meinem Beispiel). Beim Default-Verhalten MYSQLI_STORE_RESULT lohnt es sich, wenn die Ergebnismenge nicht mehr benötigt wird und das Script noch eine Weite weiterläuft und der belegte Speicher freigegeben werden soll.

                  Ne weitere Frage:

                  Wenn ich eine Klasse habe und meine Datenbank-Klasse(db) nutzen möchte, dann hole ich mir eine Instanz so:

                  class beispiel{

                  private static $dbcon;

                  public function __construct(){
                     self::$dbcon=db::getInstance();
                    }
                  }

                    
                  Ich würde die Instanz nicht auf Vorrat holen sondern jeweils in den jeweiligen Methoden, in denen sie benötigt wird und in einer lokalen Variable ablegen.  
                    
                  
                  > Allerdings ginge doch auch direkt:  
                  > b)  
                  > ~~~php
                  
                  public workWith(){  
                  
                  >   db::db_query($sql);  
                  > }
                  
                  

                  Da db_query eine statische Methode ist.

                  Für die statische Methode wird ja auch keine Instanz benötigt. du brauchst sie dann nicht abzufragen. Die Frage ist, ob überhaupt eine Instanz benötigt wird oder ob die public-Methoden alle atomar sind und damit statisch sein können. Dann brauchst du nämlich auch kein öffentliches Singleton, um die Instanz zu holen.

                  Mir ist das erst später aufgefallen da ich atm zum üben eine Newsletterklasse schreibe. So versuche ich perfekt mit der db und der tools Klasse zusammen zuarbeiten.

                  Manchmal stellt man erst später fest, dass das was man sich ausgedacht hat, wenn es ans Verwenden geht unbrauchbar ist. Deshalb gibt es auch das YAGNI-Prinzip (You ain't gonna need it): Funktinalität erst dann hinzufügen, wenn man sie braucht. Sonst programmiert man umsonst und/oder am eigentlichen Bedarf vorbei.

                  echo "$verabschiedung $name";

                  1. Hallo dedlfix.

                    Also, ich beschränke die Query erledigende Funktion mal auf das Nötigste.

                    Danke.

                    Das heißt, sie bekommt ein fertiges Statement ohne dass noch Parameter eingebaut werden können/müssen. Ebenfalls nicht mit berücksichtigt ist das Ermitteln und Zurückgeben von Result-Metadaten wie last_insert_id oder affected_rows.

                    Ich denke das werde ich im Nachhinein noch selber auf die Reihe bekommen.

                    $mysqli = $this->_getConnection(); // das ist eine private Methode, die mit ein mysqli-Objekt mit aktiver Verbindung gibt.

                    _getConnection(), was ist das? meine getInstance()?
                    Bzw. in meiner db-Klasse wird die Mysql-Verbindung ja in private static $_db_connection abgelegt und da die Methode query() ja in dieser Klasse liegt, einfach $mysqli = self::$_db_connection?

                    Meine db-Klasse baut ja beim instanzieren automatisch eine MySQLi-Verbindung auf, sie wird _immer_gebraucht bei jeder Methode in der Klasse.

                    »» Ne weitere Frage:
                    »»
                    »» Wenn ich eine Klasse habe und meine Datenbank-Klasse(db) nutzen möchte, dann hole ich mir eine Instanz so:
                    »»
                    »» ~~~php

                    class beispiel{

                    »»   private static $dbcon;
                    »»
                    »»   public function __construct(){
                    »»    self::$dbcon=db::getInstance();
                    »»   }
                    »» }

                    
                    >   
                    > Ich würde die Instanz nicht auf Vorrat holen sondern jeweils in den jeweiligen Methoden, in denen sie benötigt wird und in einer lokalen Variable ablegen.  
                      
                      
                    Okay habe ich geändert. Jede Methode die eine Verbindung braucht, holt sich per getInstance() eine Instanz und speichert sie lokal(innerhalb der Methode meinst du oder?) ab.  
                      
                    
                    > »» Allerdings ginge doch auch direkt:  
                    > »» b)  
                    > »» ~~~php
                    
                    public workWith(){  
                    
                    > »»   db::db_query($sql);  
                    > »» }
                    
                    

                    »»
                    »» Da db_query eine statische Methode ist.

                    Für die statische Methode wird ja auch keine Instanz benötigt. du brauchst sie dann nicht abzufragen. Die Frage ist, ob überhaupt eine Instanz benötigt wird oder ob die public-Methoden alle atomar sind und damit statisch sein können. Dann brauchst du nämlich auch kein öffentliches Singleton, um die Instanz zu holen.

                    Argh - jetzt bin ich wieder völlig überfordert und weiß nicht mal ob ich mich in einer YAGNI-Welt befinde, denn die ganze Zeit sitze ich daran eine db-Klasse auf Singleton-Pattern aufzubauen und nun sind alle Methoden static und ich kann jederzeit auf sie zugreifen auch ohne die Instanz.
                    Irgendwie bin ich stark verwirrt und weiß garnicht mehr wofür ich das Singleton da am besten nutze und warum ich nicht einfach alles static mache wie meine tools-Klasse. -______-

                    Ich poste mal meine Aktuelle db-Klasse um sie Deiner/Eurer Bewertung unterziehen zu lassen:

                    class db{  
                      
                    	# Instanz - Singleton Pattern  
                    	private static $_instance;  
                    	  
                    	# Verbindungsdaten  
                    	private static $_db_host;  
                    	private static $_db_user;  
                    	private static $_db_pw;  
                    	private static $_db_name;  
                    	private static $_db_connection;  
                    	  
                    	private static $_count_array;  
                    	private static $_rwu_sentence;  
                    	  
                    	public static $query;  
                    	public static $result;  
                    	  
                    	  
                    	  
                    	  
                    	# Konstruktor - private - kann nicht aufgerufen werden  
                    	private function __construct(){  
                    		self::db_connect();  
                    	}  
                    	  
                    	# Singleton Pattern  
                    	public static function getInstance()  
                        {  
                            if (!isset(self::$_instance)) {  
                    			self::$_instance = new db();  
                    		} else {  
                    			die("Es ist bereits eine Instanz vorhanden - schliessen Sie diese um eine weitere zu erstellen.<br/>  
                    Singleton-Pattern-Error.");  
                    		}  
                    		return self::$_instance;  
                        }  
                    	  
                    	# Datenbankwerte setzen  
                    	public static function db_set_vars($host,$name,$pw,$dbname){  
                    		self::$_db_host=$host;  
                    		self::$_db_user=$name;  
                    		self::$_db_pw=$pw;  
                    		self::$_db_name=$dbname;  
                    		  
                    	}  
                    	  
                    	  
                    	# Zur Datenbank verbinden  
                    	private static function db_connect()  
                        {  
                      
                           self::$_db_connection = new mysqli(self::$_db_host, self::$_db_user, self::$_db_pw, self::$_db_name);  
                    	   if (mysqli_connect_errno()) {  
                       			printf("Connect failed: %s\n", mysqli_connect_error());  
                        		exit();  
                    	   } else {  
                    	   		return true;  
                    	   }  
                        }  
                    	  
                    	######################################################################################################  
                    	################# db_make_rwu_sentence  
                    	######################################################################################################  
                    	  
                    	// Ein-/Auslesewerte aneinanderreihen  
                    	/*  
                    	3 Typen:  
                    	Typ 1: foo,bar  
                    	Typ 2: 'foo','bar'  
                    	Typ 3: foo='bar',foo='bar',  
                    	Typ 4: ?,?,? - MySQLi Platzhalter für prepared Statements  
                    	*/  
                    	public static function db_make_rwu_sentence($what_rwu,$what_insert,$rwu){  
                    	  
                    		$x=0; // Zähler auf NULL(0) setzen  
                    		  
                    		self::$_rwu_sentence=''; // Zurücksetzen des Ausdrucks  
                    		  
                    		foreach($what_rwu as $what){  
                    			  
                    				if($rwu==1||$rwu==2){  		// Typ 1 oder 2  
                    					  
                    					self::$_rwu_sentence .= ($rwu==1) ? $what : "'".$what."'";  
                    					  
                    				} elseif($rwu==3) { 		// Typ 3  
                    					  
                    					self::$_rwu_sentence .= $what."='".mysqli_real_escape_string($what_insert[$x])."'";  
                    				  
                    				} elseif($rwu==4) { 		// Typ 4  
                      
                    					self::$_rwu_sentence .= "?";  
                    				  
                    				}  
                    				  
                    				self::$_rwu_sentence .= ($x < self::$_count_array - 1) ? "," : "";  
                    				  
                    				++$x; // hochzählen  
                    		}  
                    		  
                    		return self::$_rwu_sentence;  
                    	}  
                    	  
                    	######################################################################################################  
                    	################# db_create_normal_query  
                    	######################################################################################################  
                    	// Erstellt einen Query  
                    	/*  
                    	$what_array -> Spaltennamen  
                    	$what_insert -> Was reingeschrieben wird  
                    	$from_table -> welche Tabelle angesprochen wird  
                    	$when -> BEDINGUNG! Wann macht der Querie etwas? Wo? -> $WHEN....  
                    	$whatkind -> Was für ein RUDI Query ist es? (SELECT(3), UPDATE(2), DELETE(4), INSERT(1))  
                    	  
                    	  
                    	*/  
                    	public static function db_create_normal_query($what_array,$what_insert, $from_table, $when, $whatkind){  
                      
                    		// RUDI-Queries  
                      
                    		# Wieviele Werte sind ein-/auszulesen  
                    		self::$_count_array=count($what_array);  
                    		  
                    		      if ($whatkind==1) { 	// SELECT ((R)ead)  
                    			  
                    				self::$query="SELECT ".self::db_make_rwu_sentence($what_array,'',1)." FROM ".$from_table." WHERE ".$when;  
                    					  
                    		} elseif ($whatkind==2) {	// UPDATE ((U)pdate)  
                    		  
                    				tools::check_array_numbers($what_array,$what_insert);  
                    				self::$query="UPDATE ".$from_table." SET ";  
                    				self::$query.=self::db_make_rwu_sentence($what_array,$what_insert,3);  
                    				self::$query.=" WHERE ".$when;  
                    		  
                    		} elseif ($whatkind==3) {	// DELETE ((D)elete)  
                    				  
                    				self::$query="DELETE FROM ".$from_table." WHERE ".$when;  
                    				  
                    		} elseif ($whatkind==4) {	// INSERT ((I)nsert)  
                    				  
                    				if(!tools::check_array_numbers($what_array,$what_insert)) self::db_errors("Die Arrays sind nicht gleichlang!");  
                    				  
                    				self::$query="INSERT INTO ".$from_table." (".self::db_make_rwu_sentence($what_array,'',1);  
                    				self::$query.=") VALUES (".self::db_make_rwu_sentence($what_insert,'',2).")";  
                    		  
                    		} else {					// Kein Typ -> Error  
                    		  
                    				self::db_errors("Es wurde kein Typ ausgewählt");  
                    				  
                    		}  
                    		  
                    		self::db_query(self::$query);  
                    	  
                    	}  
                    	  
                    /**  
                     * Query abarbeiten  
                     *  
                     * @param string $sql  ein SQL-Statement  
                     * @param mixed $asObject  false: Fetchen als Array  
                     *                         true: Fetchen als Objekt  
                     *                         string: Name der zu instantiierenden Klasse  
                     * @param array $objectParams  optionale Parameter @see mysqli_result::fetch_object()  
                     * @return array  Ergebnismenge als Array mit Arrays oder Objekten  
                     */  
                    	# Query ausführen  
                    	public static function db_query($sql, $asObject = false, $objectParams = null) {  
                    	  $result = array();  
                    	  
                    	  $mysqli = self::$_db_connection; // Ich hoffe das ist so richtig  
                    	  # $mysqli = $this->_getConnection(); // das ist eine private Methode, die mit ein mysqli-Objekt mit aktiver Verbindung gibt.  
                    	  
                    	  $mysqliResult = $mysqli->query($sql, MYSQLI_USE_RESULT);  
                    	  if (!$mysqliResult)  
                    		throw new Exception(...);  
                    	  
                    	  if ($mysqliResult instanceof mysqli_result) {  
                    		try {  
                    	  
                    		  if ($asObject) { // true oder string  
                    			if (is_string($asObject)) {  
                    			  if (!class_exists($asObject))  
                    				throw new Exception('class ' . $asObject . ' does not exist.');  
                    			} else { // kein Klassenname übergeben, Standard-Klasse verwenden lassen  
                    			  $asObject = null;  
                    			  $objectParams = null;  
                    			}  
                    	  
                    			while ($row = $mysqliResult->fetch_object($asObject, $objectParams))  
                    			  $result[] = $row;  
                    	  
                    		  } else  
                    			while ($row = $mysqliResult->fetch_assoc())  
                    			  $result[] = $row;  
                    	  
                    		} finally {  
                    		  // wird unbedingt benötigt, wegen MYSQLI_USE_RESULT @see mysqli::query()  
                    		  $mysqliResult->free();  
                    		}  
                    	  }  
                    	  
                    	  return $result;  
                    	}  
                    /*  
                    	  
                    	# Clone - unterbinden  
                    	public function __clone(){  
                               trigger_error('Clone is not allowed.', E_USER_ERROR);  
                            }  
                    	  
                    }
                    

                    Mir ist klar das dort noch eine Fehlerbehandlung passieren muss, ich werde dafür eine Log-Klasse schreiben die MySQL-Fehler loggt usw..
                    Weitere Fragen in meinem Kopf sind ausserdem immernoch:
                    1. Sollte der "Connect" im Konstruktor stattfinden oder nicht?
                    2. Wie könnte der Destruktor aussehen?

                    Lg, danke für deine Mühe,

                    Chris

                    1. echo $begrüßung;

                      »   $mysqli = $this->_getConnection(); // das ist eine private Methode, die mit ein mysqli-Objekt mit aktiver Verbindung gibt.
                      _getConnection(), was ist das? meine getInstance()?

                      Das ist meine Version eines lazy connect.

                      Bzw. in meiner db-Klasse wird die Mysql-Verbindung ja in private static $_db_connection abgelegt und da die Methode query() ja in dieser Klasse liegt, einfach $mysqli = self::$_db_connection?

                      Da du ja die Connection schon hast, kannst du dir obige Zeile sparen und in der nächsten das $mysqli durch self::$_db_connection ersetzen.

                      Argh - jetzt bin ich wieder völlig überfordert und weiß nicht mal ob ich mich in einer YAGNI-Welt befinde, denn die ganze Zeit sitze ich daran eine db-Klasse auf Singleton-Pattern aufzubauen und nun sind alle Methoden static und ich kann jederzeit auf sie zugreifen auch ohne die Instanz.

                      Auch gut, dann weg mit der öffentlichen Instanz. Wenn du nach außen hin nur noch statische Methoden übrig hast, dann kann das Singleton weg. Oder besser: bau es zu einem lazy connect um. Du hast ja jetzt nur noch öffentliche Methoden à la db::query(...) und keinen mehr, der die Verbindung aufbaut. Dann brauchst du doch eine private und statische _getConnection(), die quasi als internes Singleton die Connection erstellt oder die erstellte bereitstellt.

                      Ich poste mal meine Aktuelle db-Klasse um sie Deiner/Eurer Bewertung unterziehen zu lassen:

                      Du wirst sie ja vermutlich gleich noch mal umarbeiten ... :-) Deswegen kommentiere ich nicht alles.

                      Singleton Pattern

                      public static function getInstance()
                          {
                              if (!isset(self::$_instance)) {
                      self::$_instance = new db();
                      } else {
                      die("Es ist bereits eine Instanz vorhanden - schliessen Sie diese um eine weitere zu erstellen.<br/>
                      Singleton-Pattern-Error.");
                      }
                      return self::$_instance;
                          }

                      Unabhängig von den Umbauplänen: Die Meldung ist für ein Singleton nicht sehr sinnig. Der else-Zweig sollte ganz weg, denn wenn die Instanz schon da ist, soll sie einfach rausgegeben werden.

                      3 Typen:
                      Typ 1: foo,bar
                      Typ 2: 'foo','bar'
                      Typ 3: foo='bar',foo='bar',
                      Typ 4: ?,?,? - MySQLi Platzhalter für prepared Statements
                      if($rwu==1||$rwu==2){   // Typ 1 oder 2
                      } elseif($rwu==3) { // Typ 3
                      } elseif($rwu==4) { // Typ 4

                      Es gibt Klassenkonstanten. Nutze diese statt nichtssagender Zahlen und dein Quelltext wird ein Stück lesbarer.

                      $whatkind -> Was für ein RUDI Query ist es? (SELECT(3), UPDATE(2), DELETE(4), INSERT(1))

                      Auch dafür bieten sich Klassenkonstanten mit sprechenden Namen an. (Übrigens: Die Bezeichnung RUDI gefällt mir am besten, üblicher aber sprachlich unschön ist CRUD (Create statt Insert). Nur damit du es mal gehört hast.)

                      Weitere Fragen in meinem Kopf sind ausserdem immernoch:

                      1. Sollte der "Connect" im Konstruktor stattfinden oder nicht?

                      Mit dem Umstieg auf nur noch öffentliche statische Methoden brauchst du eigentlich nur noch ein mysqli-Objekt, das du dir in einer privaten statischen Klassenvariable merken kannst. Einen Konstruktor brauchst du nicht. Du kannst ihn private und leer lassen, damit keine Instanz erstellt werden kann, aber selbst wenn: solange es nur statisches Zeug gibt, nützt eine Instanz nichts, denn sie hat keine Methoden und keine Eigenschaften, die man aufrufen könnte.

                      1. Wie könnte der Destruktor aussehen?

                      Keine Instanz - kein Destruktor.

                      echo "$verabschiedung $name";

                      1. Hallo.

                        Da du ja die Connection schon hast, kannst du dir obige Zeile sparen und in der nächsten das $mysqli durch self::$_db_connection ersetzen.

                        Alles klar.

                        »» Argh - jetzt bin ich wieder völlig überfordert und weiß nicht mal ob ich mich in einer YAGNI-Welt befinde, denn die ganze Zeit sitze ich daran eine db-Klasse auf Singleton-Pattern aufzubauen und nun sind alle Methoden static und ich kann jederzeit auf sie zugreifen auch ohne die Instanz.

                        Auch gut, dann weg mit der öffentlichen Instanz. Wenn du nach außen hin nur noch statische Methoden übrig hast, dann kann das Singleton weg. Oder besser: bau es zu einem lazy connect um. Du hast ja jetzt nur noch öffentliche Methoden à la db::query(...) und keinen mehr, der die Verbindung aufbaut. Dann brauchst du doch eine private und statische _getConnection(), die quasi als internes Singleton die Connection erstellt oder die erstellte bereitstellt.

                        _WAAASSSS_ *mit einer Wimper zuck*... jetzt bin ich ja wieder an dem Punkt angelangt wo ich vor geschätzten 50 Beiträgen schon war.

                        Static vs. Singleton Pattern

                        Vorteile, Nachteile, was macht jetzt mehr Sinn und wie sollte ich die Klasse ausrichten. Ich könnte ja theoretisch auch die Methoden nicht static machen und dann rein Singleton benutzen bevor ich das alles zum 200. mal wieder neu umschreibe. Ich bin wieder völlig verwirrt, was denn nun das "beste" ist für eine Datenbankklasse.

                        Du wirst sie ja vermutlich gleich noch mal umarbeiten ... :-) Deswegen kommentiere ich nicht alles.

                        -.-"

                        Unabhängig von den Umbauplänen: Die Meldung ist für ein Singleton nicht sehr sinnig. Der else-Zweig sollte ganz weg, denn wenn die Instanz schon da ist, soll sie einfach rausgegeben werden.

                        Ja stimmt soweit habe ich nicht gedacht, hast Recht.

                        »» 3 Typen:
                        »» Typ 1: foo,bar
                        »» Typ 2: 'foo','bar'
                        »» Typ 3: foo='bar',foo='bar',
                        »» Typ 4: ?,?,? - MySQLi Platzhalter für prepared Statements
                        »» if($rwu==1||$rwu==2){   // Typ 1 oder 2
                        »» } elseif($rwu==3) { // Typ 3
                        »» } elseif($rwu==4) { // Typ 4

                        Es gibt Klassenkonstanten. Nutze diese statt nichtssagender Zahlen und dein Quelltext wird ein Stück lesbarer.

                        Wie soll das dann aussehen?

                        Auch dafür bieten sich Klassenkonstanten mit sprechenden Namen an. (Übrigens: Die Bezeichnung RUDI gefällt mir am besten, üblicher aber sprachlich unschön ist CRUD (Create statt Insert). Nur damit du es mal gehört hast.)

                        Danke =), ich find RUDI aber ebenfalls schöner..

                        »» Weitere Fragen in meinem Kopf sind ausserdem immernoch:
                        »» 1. Sollte der "Connect" im Konstruktor stattfinden oder nicht?

                        Mit dem Umstieg auf nur noch öffentliche statische Methoden brauchst du eigentlich nur noch ein mysqli-Objekt, das du dir in einer privaten statischen Klassenvariable merken kannst. Einen Konstruktor brauchst du nicht. Du kannst ihn private und leer lassen, damit keine Instanz erstellt werden kann, aber selbst wenn: solange es nur statisches Zeug gibt, nützt eine Instanz nichts, denn sie hat keine Methoden und keine Eigenschaften, die man aufrufen könnte.

                        Also habe ich dann die Methode _getConnection() die eine Verbindung zur Dátenbank macht, diese Verbindung speicher ich dann lokal in der Methode wo _getConnection() aufgerufen wird, richtig?

                        So das halt wirklich die Datenbank verbindung _nur_ bei einem Query kurzzeitig aufgebaut wird.
                        Wie baue ich Sie danach wieder ab?
                        mit $_Connection->close() ?

                        Lg,

                        Chris

                        1. echo $begrüßung;

                          _WAAASSSS_ *mit einer Wimper zuck*... jetzt bin ich ja wieder an dem Punkt angelangt wo ich vor geschätzten 50 Beiträgen schon war.

                          Ja, aber nun hast du 50 Beiträge lang zumindest Wissen/Erfahrung gesammelt. :-) Fehler und Irrwege sind ganz natürlich im Lernprozess. Man muss ja auch erfahren, warum man bestimmte Wege besser nicht geht.

                          Static vs. Singleton Pattern

                          Vorteile, Nachteile, was macht jetzt mehr Sinn und wie sollte ich die Klasse ausrichten. Ich könnte ja theoretisch auch die Methoden nicht static machen und dann rein Singleton benutzen bevor ich das alles zum 200. mal wieder neu umschreibe. Ich bin wieder völlig verwirrt, was denn nun das "beste" ist für eine Datenbankklasse.

                          Das "Beste" gibt es nicht. Aufwand und Nutzen ist immer gegeneinander abzuwägen. Nutzt es etwas, eine Instanz zu haben, wenn die Methoden alle unabhängig voneinander arbeiten? Ist es weniger aufwendig, diese Methoden sttisch aufzurufen? Wenn ich mich recht erinnere schrieb ich schon im ersten Faden, dass eine Klasse mit reinweg statischen öffentlichen Methoden eine Alternative ist.

                          » Es gibt Klassenkonstanten. Nutze diese statt nichtssagender Zahlen und dein Quelltext wird ein Stück lesbarer.
                          Wie soll das dann aussehen?

                          Syntaktisch so wie im Handbuch unter Class Constants beschrieben.

                          Wenn du Zahlen zur Unterscheidung von x Fällen nimmst, dann kannst du Konstanten mit einem aussagekräftigen Namen diese Zahlen zuweisen und statt den Zahlen im Code nimmst du die Konstanten.

                          class foo {  
                            const bar = 1;  
                            const qux = 2;  
                            
                            function baz($param) {  
                              switch ($param) {  
                                case self::bar: ...  
                                case self::qux: ...  
                              }  
                            }  
                          }  
                            
                          $foo = new foo();  
                          $foo->baz(foo::qux);
                          

                          Also habe ich dann die Methode _getConnection() die eine Verbindung zur Dátenbank macht, diese Verbindung speicher ich dann lokal in der Methode wo _getConnection() aufgerufen wird, richtig?

                          Ja.

                          So das halt wirklich die Datenbank verbindung _nur_ bei einem Query kurzzeitig aufgebaut wird.
                          Wie baue ich Sie danach wieder ab?
                          mit $_Connection->close() ?

                          Ich würde sie einfach stehen lassen. Ein Abbauen bedeutet ein erneutes Aufbauen-Müssen bei der nächsten Query im selben Script. Die Verbindung allein frisst kaum Brot. Sie belegt nur einen Platz der max connections. Wenn du eine hochbelastete Anwendung mit mehr als 100 gleichzeitig laufenden Scripts erstellst oder sie sich so entwickelt, wirst du noch ganz andere Optimierungen finden müssen.

                          echo "$verabschiedung $name";

                          1. Hallo.

                            Ja, aber nun hast du 50 Beiträge lang zumindest Wissen/Erfahrung gesammelt. :-) Fehler und Irrwege sind ganz natürlich im Lernprozess. Man muss ja auch erfahren, warum man bestimmte Wege besser nicht geht.

                            Ja da hast du Recht..

                            Das "Beste" gibt es nicht. Aufwand und Nutzen ist immer gegeneinander abzuwägen. Nutzt es etwas, eine Instanz zu haben, wenn die Methoden alle unabhängig voneinander arbeiten? Ist es weniger aufwendig, diese Methoden sttisch aufzurufen? Wenn ich mich recht erinnere schrieb ich schon im ersten Faden, dass eine Klasse mit reinweg statischen öffentlichen Methoden eine Alternative ist.

                            Ja richtig und als dann alle wie wild mit Singleton Pattern um sich warfen hatte ich mich dafür entschieden.

                            »» So das halt wirklich die Datenbank verbindung _nur_ bei einem Query kurzzeitig aufgebaut wird.
                            »» Wie baue ich Sie danach wieder ab?
                            »» mit $_Connection->close() ?

                            Ich würde sie einfach stehen lassen. Ein Abbauen bedeutet ein erneutes Aufbauen-Müssen bei der nächsten Query im selben Script. Die Verbindung allein frisst kaum Brot. Sie belegt nur einen Platz der max connections. Wenn du eine hochbelastete Anwendung mit mehr als 100 gleichzeitig laufenden Scripts erstellst oder sie sich so entwickelt, wirst du noch ganz andere Optimierungen finden müssen.

                            Aber ich speicher sie doch lokal für den _einen_ Query ab, beim nächsten Query holt er sich doch eh eine neue Verbindung aufgrund _getConnection().
                            Oder sollte ich einfach überprüfen - ist eine DB-Verbindung vorhanden? wenn nicht, erstelle eine und speicher sie Klassenglobal als private static $db_connection und beim nächsten mal nehme die alte abgespeicherte Verbindung?

                            Hier meine aktuelle Klasse:

                              
                            class db{  
                              
                            	# Instanz - Singleton Pattern  
                            	private static $_instance;  
                            	  
                            	# Verbindungsdaten  
                            	private static $_db_host;  
                            	private static $_db_user;  
                            	private static $_db_pw;  
                            	private static $_db_name;  
                            	  
                            	private static $_count_array;  
                            	private static $_rwu_sentence;  
                            	  
                            	public static $query;  
                            	public static $result;  
                            	  
                            	const select = 1;  
                            	const update = 2;  
                            	const delete = 3;  
                            	const insert = 4;  
                            	  
                            	  
                            	  
                            	  
                            	# Konstruktor - private - kann nicht aufgerufen werden  
                            	private function __construct(){}  
                            	  
                            	# Datenbankwerte setzen  
                            	public static function db_set_vars($host,$name,$pw,$dbname){  
                            		self::$_db_host=$host;  
                            		self::$_db_user=$name;  
                            		self::$_db_pw=$pw;  
                            		self::$_db_name=$dbname;	  
                            	}  
                            	  
                            	  
                            	# Zur Datenbank verbinden  
                            	private static function db_connect(){  
                                   $_db_connection = new mysqli(self::$_db_host, self::$_db_user, self::$_db_pw, self::$_db_name);  
                            	   if (mysqli_connect_errno()) {  
                               			printf("Connect failed: %s\n", mysqli_connect_error());  
                                		exit();  
                            	   } else {  
                            	   		return true;  
                            	   }  
                            	  
                            	   return $_db_connection;  
                                }  
                            	  
                            	######################################################################################################  
                            	################# db_make_rwu_sentence  
                            	######################################################################################################  
                            	  
                            	// Ein-/Auslesewerte aneinanderreihen  
                            	/*  
                            	3 Typen:  
                            	Typ 1: foo,bar  
                            	Typ 2: 'foo','bar'  
                            	Typ 3: foo='bar',foo='bar',  
                            	Typ 4: ?,?,? - MySQLi Platzhalter für prepared Statements  
                            	*/  
                            	private static function db_make_rwu_sentence($what_rwu,$what_insert,$rwu){  
                            	  
                            		$x=0; // Zähler auf NULL(0) setzen  
                            		  
                            		self::$_rwu_sentence=''; // Zurücksetzen des Ausdrucks  
                            		  
                            		foreach($what_rwu as $what){  
                            			  
                            				if($rwu==1||$rwu==2){  		// Typ 1 oder 2  
                            					  
                            					self::$_rwu_sentence .= ($rwu==1) ? $what : "'".$what."'";  
                            					  
                            				} elseif($rwu==3) { 		// Typ 3  
                            					  
                            					self::$_rwu_sentence .= $what."='".mysqli_real_escape_string($what_insert[$x])."'";  
                            				  
                            				} elseif($rwu==4) { 		// Typ 4  
                              
                            					self::$_rwu_sentence .= "?";  
                            				  
                            				}  
                            				  
                            				self::$_rwu_sentence .= ($x < self::$_count_array - 1) ? "," : "";  
                            				  
                            				++$x; // hochzählen  
                            		}  
                            		  
                            		return self::$_rwu_sentence;  
                            	}  
                            	  
                            	######################################################################################################  
                            	################# db_create_normal_query  
                            	######################################################################################################  
                            	// Erstellt einen Query  
                            	/*  
                            	$what_array -> Spaltennamen  
                            	$what_insert -> Was reingeschrieben wird  
                            	$from_table -> welche Tabelle angesprochen wird  
                            	$when -> BEDINGUNG! Wann macht der Querie etwas? Wo? -> $WHEN....  
                            	$whatkind -> Was für ein RUDI Query ist es? (SELECT(3), UPDATE(2), DELETE(4), INSERT(1))  
                            	  
                            	  
                            	*/  
                            	public static function db_create_normal_query($what_array,$what_insert, $from_table, $when, $whatkind){  
                              
                            		// RUDI-Queries  
                              
                            		# Wieviele Werte sind ein-/auszulesen  
                            		self::$_count_array=count($what_array);  
                            		  
                            		      if ($whatkind==self::select) { 	// SELECT ((R)ead)  
                            			  
                            				self::$query="SELECT ".self::db_make_rwu_sentence($what_array,'',1)." FROM ".$from_table." WHERE ".$when;  
                            					  
                            		} elseif ($whatkind==self::update) {	// UPDATE ((U)pdate)  
                            		  
                            				tools::check_array_numbers($what_array,$what_insert);  
                            				self::$query="UPDATE ".$from_table." SET ";  
                            				self::$query.=self::db_make_rwu_sentence($what_array,$what_insert,3);  
                            				self::$query.=" WHERE ".$when;  
                            		  
                            		} elseif ($whatkind==self::delete) {	// DELETE ((D)elete)  
                            				  
                            				self::$query="DELETE FROM ".$from_table." WHERE ".$when;  
                            				  
                            		} elseif ($whatkind==self::insert) {	// INSERT ((I)nsert)  
                            				  
                            				if(!tools::check_array_numbers($what_array,$what_insert)) self::db_errors("Die Arrays sind nicht gleichlang!");  
                            				  
                            				self::$query="INSERT INTO ".$from_table." (".self::db_make_rwu_sentence($what_array,'',1);  
                            				self::$query.=") VALUES (".self::db_make_rwu_sentence($what_insert,'',2).")";  
                            		  
                            		} else {					// Kein Typ -> Error  
                            		  
                            				self::db_errors("Es wurde kein Typ ausgewählt");  
                            				  
                            		}  
                            		  
                            		self::db_query(self::$query);  
                            	  
                            	}  
                            	  
                            	/**  
                            	 * Query abarbeiten  
                            	 *  
                            	 * @param string $sql  ein SQL-Statement  
                            	 * @param mixed $asObject  false: Fetchen als Array  
                            	 *                         true: Fetchen als Objekt  
                            	 *                         string: Name der zu instantiierenden Klasse  
                            	 * @param array $objectParams  optionale Parameter @see mysqli_result::fetch_object()  
                            	 * @return array  Ergebnismenge als Array mit Arrays oder Objekten  
                            	 */  
                            	# Query ausführen  
                            	public static function db_query($sql, $asObject = false, $objectParams = null) {  
                            	  $result = array();  
                            	  
                            	  $mysqli = self::db_connect();  
                            	  # $mysqli = $this->_getConnection(); // das ist eine private Methode, die mit ein mysqli-Objekt mit aktiver Verbindung gibt.  
                            	  
                            	  $mysqliResult = $mysqli->query($sql, MYSQLI_USE_RESULT);  
                            	  if (!$mysqliResult)  
                            		throw new Exception(...);  
                            	  
                            	  if ($mysqliResult instanceof mysqli_result) {  
                            		try {  
                            	  
                            		  if ($asObject) { // true oder string  
                            			if (is_string($asObject)) {  
                            			  if (!class_exists($asObject))  
                            				throw new Exception('class ' . $asObject . ' does not exist.');  
                            			} else { // kein Klassenname übergeben, Standard-Klasse verwenden lassen  
                            			  $asObject = null;  
                            			  $objectParams = null;  
                            			}  
                            	  
                            			while ($row = $mysqliResult->fetch_object($asObject, $objectParams))  
                            			  $result[] = $row;  
                            	  
                            		  } else  
                            			while ($row = $mysqliResult->fetch_assoc())  
                            			  $result[] = $row;  
                            	  
                            		} finally {  
                            		  // wird unbedingt benötigt, wegen MYSQLI_USE_RESULT @see mysqli::query()  
                            		  $mysqliResult->free();  
                            		}  
                            	  }  
                            	  
                            	  return $result;  
                            	}  
                            	  
                            	# Clone - unterbinden  
                            	public function __clone() {  
                                    trigger_error('Clone is not allowed.', E_USER_ERROR);  
                                }  
                            }  
                              
                            
                            

                            Bei deinem Skript kommen allerdings zwei Fehler aufgrund:

                            throw new Exception(...);

                            Was kommt statt "..." hin?
                            Und er erwartet "catch": Parse error: parse error, expecting `T_CATCH' in

                            Sprich hier : } finally {

                            Wäre nett wenn du die zwei Fehler und sonstige die du in der Funktion siehst noch beheben könntest :-[

                            Mit try, exceptions usw muss ich mich eh noch auseinandersetzen, werde ich in der zwischenzeit mal tun.

                            Danke dir,

                            lg, Chris

                            1. Hello,

                              Ja richtig und als dann alle wie wild mit Singleton Pattern um sich warfen hatte ich mich dafür entschieden.

                              Einspruch!

                              Ich habe von Anfang an in Frage gestellt, ob ein Singleton für diese Aufgabe überhaupt die richtige Wahl ist! Und ich habe meinen Einwand auch begründet.

                              Trotzdem habe ich auch 'was dabei gelernt und habe mich nun quer durchs Web gelesen (so ca. 0,000085% aller Beiträge zum Thema werde ich wohl schon durch haben). Ich konnte nirgends eine Begründung dafür finden, warum die Singleton-Instanz während der gesamten Programmrestlaufzeit erhalten bleiben muss. Wenn ein Programm Nebenläufigkeit zulässt, muss man sowieso Maßnahmen für den gegenseitigen Ausschluss (Mutex) ergreifen und wenn es keine zulässt, so wie üblicherweise die PHP-Scripte, dann kann die Instanz im Programmablauf auch ruhig wieder beseitigt werden, solange man sie nicht benötigt.

                              Es kommt dann nach der in diesem Thread verfochtenen Logik ja nur darauf an, dass es zur gleichen Zeit nur eine Instanz für die Datenbankverbindung gibt.

                              (was ich persönlich ja unsinnig finde ...)

                              Liebe Grüße aus dem Cyberspace

                              Tom vom Berg

                              --
                              Nur selber lernen macht schlau
                              http://bergpost.annerschbarrich.de
                              1. echo $begrüßung;

                                Es kommt dann nach der in diesem Thread verfochtenen Logik ja nur darauf an, dass es zur gleichen Zeit nur eine Instanz für die Datenbankverbindung gibt.
                                (was ich persönlich ja unsinnig finde ...)

                                Nun, dann hast du einen anderen Anwendungsfall als geschätzt 99% aller potentiellen Nutzer einer solchen DB-Klasse. Die benötigen nämlich nur eine einzige DB-Verbindung. Wenn du mehrere brauchst, dann brauchst du eine andere Lösung.

                                echo "$verabschiedung $name";

                            2. echo $begrüßung;

                              Aber ich speicher sie doch lokal für den _einen_ Query ab, beim nächsten Query holt er sich doch eh eine neue Verbindung aufgrund _getConnection().
                              Oder sollte ich einfach überprüfen - ist eine DB-Verbindung vorhanden? wenn nicht, erstelle eine und speicher sie Klassenglobal als private static $db_connection und beim nächsten mal nehme die alte abgespeicherte Verbindung?

                              Genau das ist meine Intention von der Arbeitsweise von _getConnection(). Ein Singleton für die Verbindung beziehungsweise das mysqli-Objekt mit geöffneter Verbindung. Zum Verbindungsöffnen gehört ja auch noch das Aushandeln einer Zeichenkodierung und die Abfrage nach aufgetretenen Fehlern. Diesen Code will man nicht ständig zu jedem Verwendungsfall hinkopieren.

                              Zur Datenbank verbinden

                              private static function db_connect(){
                                     $_db_connection = new mysqli(self::$_db_host, self::$_db_user, self::$_db_pw, self::$_db_name);
                                 if (mysqli_connect_errno()) {
                                  printf("Connect failed: %s\n", mysqli_connect_error());
                                   exit();
                                 } else {
                                  return true;
                                 }

                              return $_db_connection;
                                  }

                              Hier musst du nochmal nachbessern. Wenn ein if-Zweig mit exit, die oder return endet (und diese nicht umgangen werden können), dann brauchst du keinen else-Zweig. Die dortigen Anweisungen können im normalen Programmkontext stehen. Du siehst dann auch, dass deine beiden returns nicht richtig sind.

                              throw new Exception(...);
                              Was kommt statt "..." hin?

                              Ein passender Meldungstext.

                              Und er erwartet "catch": Parse error: parse error, expecting `T_CATCH' in
                              Sprich hier : } finally {

                              Ach Mist. Das kommt davon, wenn man aus der Kalten was schreibt. PHP kennt kein finally. Da muss ich umbauen.

                              public static function db_query($sql, $asObject = false, $objectParams = null) {  
                                $result = array();  
                                
                                if ($asObject) { // true oder string  
                                  if (is_string($asObject)) {  
                                    $className = $asObject;  
                                    if (!class_exists($className))  
                                      throw new Exception('class ' . $className . ' does not exist.');  
                                  } else { // kein Klassenname übergeben, Standard-Klasse verwenden lassen  
                                    $className = null;  
                                    $objectParams = null;  
                                  }  
                                }  
                                
                                $mysqli = self::db_connect();  
                                # $mysqli = $this->_getConnection(); // das ist eine private Methode, die mit ein mysqli-Objekt mit aktiver Verbindung gibt.  
                                
                                $mysqliResult = $mysqli->query($sql, MYSQLI_USE_RESULT);  
                                if (!$mysqliResult)  
                                  throw new Exception(...);  
                                
                                if ($mysqliResult instanceof mysqli_result) {  
                                  if ($asObject) {  
                                    while ($row = $mysqliResult->fetch_object($className, $objectParams))  
                                      $result[] = $row;  
                                
                                  } else {  
                                    while ($row = $mysqliResult->fetch_assoc())  
                                      $result[] = $row;  
                                  }  
                                
                                  // wird unbedingt benötigt, wegen MYSQLI_USE_RESULT @see mysqli::query()  
                                  $mysqliResult->free();  
                                }  
                                
                                return $result;  
                              }
                              

                              echo "$verabschiedung $name";

                              1. Hi.

                                »» Aber ich speicher sie doch lokal für den _einen_ Query ab, beim nächsten Query holt er sich doch eh eine neue Verbindung aufgrund _getConnection().
                                »» Oder sollte ich einfach überprüfen - ist eine DB-Verbindung vorhanden? wenn nicht, erstelle eine und speicher sie Klassenglobal als private static $db_connection und beim nächsten mal nehme die alte abgespeicherte Verbindung?

                                Genau das ist meine Intention von der Arbeitsweise von _getConnection(). Ein Singleton für die Verbindung beziehungsweise das mysqli-Objekt mit geöffneter Verbindung. Zum Verbindungsöffnen gehört ja auch noch das Aushandeln einer Zeichenkodierung und die Abfrage nach aufgetretenen Fehlern. Diesen Code will man nicht ständig zu jedem Verwendungsfall hinkopieren.

                                Also ich habe das jetzt mal so "ausformuliert":

                                  
                                private static $_db_connection;  
                                  
                                private static function _getConnection(){  
                                		  
                                		if(!self::$_db_connection instanceof mysqli){  
                                       		self::$_db_connection = new mysqli(self::$_db_host, self::$_db_user, self::$_db_pw, self::$_db_name);  
                                	   		if (mysqli_connect_errno()) {  
                                   				printf("Connect failed: %s\n", mysqli_connect_error());  
                                	   			exit();  
                                	   		}  
                                		}  
                                	  
                                	   return self::$_db_connection;  
                                    }  
                                
                                

                                Ach Mist. Das kommt davon, wenn man aus der Kalten was schreibt. PHP kennt kein finally. Da muss ich umbauen.

                                Danke.

                                Ich stoße jetzt vor ein neues Problem.
                                Und zwar lasse ich normale einfache RUDI-Statements zusammenbauen von db_create_normal_query(), diese baut den Query und führt ihn dann aus, sprich sie ruft am ende db_query() auf.

                                db_create_normal_query() gib mir also keinen Rückgabewert, das tut nur db_query. Ich habe meiner Ansicht nach nur die Alternative das ich 1. den Query baue und ihn zurückgebe und dann selber db_query aufbaue.

                                Gibt es irgendwie eine Möglichkeit, das ich das $result von db_query zurückbekomme, auch wenn ich db_create_normal_query() aufrufe.
                                Ich will mir halt praktisch eine Zeile sparen.
                                Statt:
                                [1]
                                $result=db_create_normal_query();

                                also:
                                [2]
                                $my_created_query=db_create_normal_query();
                                $result=db_query();

                                Fällt dir was ein wie ich [1] nutzen kann?

                                Wir würdest du das $result eigendlich "zu Papier" bringen?
                                Wenn ich eine Spalte "name" habe, dann greife ich darauf so:
                                echo $result[0]['name'];
                                zu. Das funktioniert, ich bekomme halt ein Doppelarray zurück.

                                Ich komme mal zur Fehlerbehandlung zurück.
                                Ich werde jetzt eine Log-Klasse schreiben, diese wird so arbeiten:

                                "Zuerst überprüfe die DB-Verbindung, wenn vorhanden, schreibe den Fehler in die Datenbank, wenn nicht, öffne die Log.txt und schreibe den Fehler dort rein."

                                Wenn ich diese Fehler im Adminpanel später aufrufen möchte:
                                "Lese die Fehler aus der Datenbenk und aus der Log.txt aus und zeige sie an."

                                Und noch einmal auf die Settings die man setzt.
                                Dafür will ich jetzt eine class.settings schreiben.
                                Allerdings weiß ich noch nicht wie ich das machen soll mit dem Daten holen aus einer TXT oder INI-Datei.
                                Ich werde es denk ich einfach so machen, das man die Daten per Hand in diese settings Klasse reinschreibt, zum Beispiel Seitenname, Domain, Firmenname, Datenbankverbindungsdaten.. usw..

                                lg,

                                chris

                                1. echo $begrüßung;

                                  Gibt es irgendwie eine Möglichkeit, das ich das $result von db_query zurückbekomme, auch wenn ich db_create_normal_query() aufrufe.

                                  Natürlich, db_query() gibt ein Ergebnis zurück. Nimm es in db_create_normal_query() in Empfang und gib es an dessen Aufrufer zurück.

                                  Wir würdest du das $result eigendlich "zu Papier" bringen?
                                  Wenn ich eine Spalte "name" habe, dann greife ich darauf so:
                                  echo $result[0]['name'];
                                  zu. Das funktioniert, ich bekomme halt ein Doppelarray zurück.

                                  Genau so. Und wenn man alles ausgeben will, dann mit foreach über das äußere Array laufen.

                                  Ich werde jetzt eine Log-Klasse schreiben, diese wird so arbeiten:
                                  "Zuerst überprüfe die DB-Verbindung, wenn vorhanden, schreibe den Fehler in die Datenbank, wenn nicht, öffne die Log.txt und schreibe den Fehler dort rein."

                                  Damit hast du dann zwei Stellen, die du auswerten musst. Wenn du keine DB-Funktionalität beim Auswerten der Meldungen benötigst, dann nimm nur eine Stelle, also die Textdatei.

                                  Allerdings weiß ich noch nicht wie ich das machen soll mit dem Daten holen aus einer TXT oder INI-Datei.

                                  Einfacher als mit parse_ini_file() eine ini-Datei auszuwerten, geht es kaum.

                                  echo "$verabschiedung $name";

                                  1. Ich danke dir Dedlfix, du hast mir sehr sehr viel geholfen.
                                    Falls ich mich irgendwie revanchieren kann, lass es mich wissen.

                                    Liebe Grüße mit bestem Dank,

                                    Chris