Jörg: PHP Fatal error: Uncaught Error: Call to a member function query() on null in

Hallo,

ein Code, der auf meinem php 8.1 Testsystem keinen Fehler auswirft, macht das auf meinem php 8.1 Produktivsystem.

try {
$db = new PDO("mysql:host =$server;dbname=$name;charset=utf8;port=3306",$user,$passwd);
   $db->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
} catch (PDOException $e) {
    echo 'Verbindung fehlgeschlagen: ' . $e->getMessage();
}

$query_ma = "SELECT ID,User FROM myuser";
$result_ma = $db->query($query_ma);

ergibt auf dem Produktivsystem:

PHP Fatal error:  Uncaught Error: Call to a member function query() on null in ...

Weiß grad gar nicht, was php zu meckern hat?
Wersagts mir?

Jörg

  1. Hallo Jörg,

    dann ist $db auf null.

    Steht da "Verbindung fehlgeschlagen"? Oder eine andere Fehlermeldung? Hast Du display_errors mal eingeschaltet und error_reporting aufgedreht?

    Ich kann mir nur vorstellen, dass der new PDO schiefgeht, deswegen $db nicht initialisiert ist und null enthält.

    Du hast zwar einen try/catch drin, aber der catch-Block lässt den Code munter weiterlaufen. Das ist nicht der Sinn des Errorhandlings. Code, der wegen eines Errows keinen Sinn mehr ergibt, darf nicht ausgeführt werden.

    Vielleicht fliegt ja auch eine andere Exception. Du könntest einen zweiten Catch-Block für Throwable $t anhängen, falls Du "Verbindung fehlgeschlagen" nicht siehst.

    try {
       $db = new PDO(...);
    } 
    catch (PDOException $ex) {
        ...
    }
    catch (Throwable $unknownError) {
       echo "General Failure übernimmt das Kommando\n";
       echo $unknownError;
    }
    

    Rolf

    --
    sumpsi - posui - obstruxi
  2. Wenn der Fehler in der Zeile ...

    $result_ma = $db->query($query_ma);
    

    bekrittelt wird, dann hat $db = new PDO( ... ) wohl keinen Fehler (genauer PDOException) geschmissen - aber NULL geliefert.

    Prüfe, warum das so ist.

    1. Hallo Raketenwilli,

      dann hat $db = new PDO( ... ) wohl keinen Fehler geschmissen - aber NULL geliefert.

      Geht das? Das ist ein new Operator, und den kannst Du nur dadurch vom Liefern eines Objekts abhalten, indem Du ihm eine Exception an den Kopf wirfst.

      Rolf

      --
      sumpsi - posui - obstruxi
      1. Hallo Rolf, Hallo Willi,

        ja, Ihr hattet recht, die Verbindung zur db war auf dem Produktivsystem nicht vorhanden.

        Und warum beim Verbindungsaufbau kein Fehler geworfen wurde, ist auch klar. Mein Code, den ich gepostet hatte, war gut, aber der auf dem Server war leider etwas anders.

        try {
        $db = new PDO("mysql:host =$server;dbname=$name;charset=utf8;port=3306",$user,$passwd);
           $db->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
        } catch (PDOException $e) {
            echo 'Verbindung fehlgeschlagen: ' . $e->getMessage();
        }
        
        $query_ma = "SELECT ID,User FROM myuser";
        $result_ma = $dbo->query($query_ma);
        

        Das klärt es auf 😉

        Danke für Eure Hilfe,

        Jörg

  3. Hallo nochmal,

    nachdem vorhin ja recht schnell klar war, wo der Fehler lag, finde ich ihn nun schon wieder nicht.

    In meiner Konfigurationsdatei connecte ich meine DB.

    Dann sollte doch die Verbindung in einem Script, das diese Konfigurationsdatei includet, noch erhalten bleiben, hm?

    Frage: Wie kann ich abfragen, ob die Verbindung noch besteht? Meine Idee ist, ich will erruieren, wo sie verloren geht.

    Jörg

    1. In meiner Konfigurationsdatei connecte ich meine DB.

      Dann sollte doch die Verbindung in einem Script, das diese Konfigurationsdatei includet, noch erhalten bleiben, hm?

      Aber ja. Bis Du die Variable oder Verbindung wegschmeisst. Es sei denn, Du findest diese nur nicht.

      1. Was steht im error.log?
      2. Wird die Konfigurationsdatei wirklich geladen? - Versuche require oder require_once statt include.
      3. Erfolgt der connect innerhalb einer Funktion, einer Methode oder dergleichen? - Gib das DB/PDO-Object mit return zurück oder schreib es in den globalen Raum (e.g. $GLOBALS['db']).
      4. Wenn Du innerhalb von anderen Funktionen oder Methoden nicht auf Dein Datenbankobjekt zugreifen kannst, dann übergib es der Funktion oder lese es aus dem globalen Raum (e.g. $GLOBALS['db']).
      1. Hallo Willi,

        1. Was steht im error.log?

        Da stand wirklich nur das drin, was ich hier in der Threadüberschrift gewählt hatte. Aber seltsamerweise habe ich die beiden Stellen (in 2 verschiedenen Scripten) dann mal mit einem weiteren iclude_once() bestückt, woraufhin der Fehler verschwand. Dann habe ich das (IMHO überflüssige) include_once() wieder gelöscht und php hatte ein Einsehen... die Fehlermeldung blieb aus. Seltsam...

        1. Wird die Konfigurationsdatei wirklich geladen? - Versuche require oder require_once statt include.

        Na sollte schon.
        Weil ich nutze die Anwendung schon seit jahren, nur eben auf php7.

        1. Erfolgt der connect innerhalb einer Funktion, einer Methode oder dergleichen? -

        Nein, darauf hatte ich geachtet, ob die Variablen innerhalb ihres Gültigkeitsraumes waren.

        Gib das DB/PDO-Object mit return zurück oder schreib es in den globalen Raum (e.g. $GLOBALS['db']).

        Wie macht man das genau?
        Weil, genau das hätte ich gebraucht. Jetzt läuft es zwar prima, aber fürs nächste mal wärs gut, wenn ich wüßte, wie man das genau notieren muss.

        1. Wenn Du innerhalb von anderen Funktionen oder Methoden nicht auf Dein Datenbankobjekt zugreifen kannst, dann übergib es der Funktion oder lese es aus dem globalen Raum (e.g. $GLOBALS['db']).

        Ja, das hätte ich aber gefunden. Wie schon gesagt, Gültigkeitsraum von Variablen ist mir schon ein begriff.

        Danke für die Hilfe, Jörg

        1. Gib das DB/PDO-Object mit return zurück oder schreib es in den globalen Raum (e.g. $GLOBALS['db']).

          Wie macht man das genau?

          1_Beispiel->sagt() > 1000_Worte->sagt():

          <?php
          $GLOBALS['ZumGruß'] = 'Hallo Welt!';
          
          function GlobalZumGruß() {
              echo $GLOBALS['ZumGruß'] . PHP_EOL;
          }
          
          GlobalZumGruß();
          
          $ZumGruß = 'Grüß Gott!';
          
          function GlobalGrüßGott() {
              echo $GLOBALS['ZumGruß'] . PHP_EOL;
          }
          
          GlobalGrüßGott();
          GlobalZumGruß();
          
          

          ausführen …

          Hallo Welt!
          Grüß Gott!
          Grüß Gott!
          

          Also ... ganz einfach: $GLOBALS['ZumGruß'] und $ZumGruß im globalen Namensraum sind sozusagen das selbe.

          Hinweis:

          Eigentlich ist die Verwendung von $GLOBALS ein „Hirnfurz“, weil das die Klarheit beseitigt, was in den Variablen steht.

          Alternative? Konstanten:

          define (
              'FH',
              fopen( __FILE__, 'r' )
          ); 
          
          
          $i=0;
          while( $row = fgets( FH ) ) {
          	echo ( $i++ ) . "\t" . htmlspecialchars( $row );
          }
          

          Benutze also die Konstante wie gezeigt. Die sind in PHP immer global.

          1. Hallo Raketenwilli,

            statt $_GLOBALS kann man auch das global Statement verwenden. Die Frage ist natürlich, ob diese $db Variable überhaupt global war.

            Edit: Die Variable heißt natürlich $GLOBALS 😕

            Einen define für eine DB Connection kann man aber nicht verwenden. Weil das eben keine Konstante ist, sondern ein Objekt. Oder was sollte dein Beispiel besagen? Ich sehe da Code, der seinen eigenen Sourcecode ausgibt...

            Rolf

            --
            sumpsi - posui - obstruxi
            1. Hi Rolf,

              statt $_GLOBALS kann man auch das global Statement verwenden. Die Frage ist natürlich, ob diese $db Variable überhaupt global war.

              So mache ich es übrigens bisher.

              Jörg

            2. Einen define für eine DB Connection kann man aber nicht verwenden. Weil das eben keine Konstante ist, sondern ein Objekt.

              Ok. Ich zeige es.

              <?php
              define(
              	'sqlite3',
              	new SQLite3( '/home/fastix/armbian.sqlite3' )
              );
              
              $query  = 'SELECT name, description from pakete LIMIT 4';
              $result = sqlite3->query( $query );
              
              while ( $row = $result->fetchArray( SQLITE3_ASSOC ) ) {
                 print_r( $row );
              };
              

              ... Dann sollte man das testen.

              Array
              (
                  [name] => accountsservice
                  [description] => query and manipulate user account information
              )
              Array
              (
                  [name] => acct
                  [description] => GNU Accounting utilities for process and login accounting
              )
              Array
              (
                  [name] => acl
                  [description] => access control list - utilities
              )
              Array
              (
                  [name] => acpid
                  [description] => Advanced Configuration and Power Interface event daemon
              )
              

              Oder was sollte dein Beispiel besagen? Ich sehe da Code, der seinen eigenen Sourcecode ausgibt...

              und jetzt die ersten vier Zeilen aus der Liste der Pakte von Armbian.

              Erst wenn ich an das Skript

              sqlite3->close();
              $result = sqlite3->query( $query );
              

              anhänge (also die Verbindung schließe und die Abfrage nochmals versuche), dann kommt

              PHP Fatal error:  Uncaught Error: The SQLite3 object has not been correctly initialised or is already closed in /home/fastix/tmp/2.php:14
              

              Also in der Zeile $result = sqlite3->query( $query ); ich hätte auch erwartet, dass PHP sich dort über die geschlossene Verbindung beschwert.

              sqlite->open( $file  );
              

              funktioniert auch.

              1. Hallo Raketenwilli,

                ich hatte es nie ausprobiert. Ich weiß nur, was im Handbuch steht:

                value
                Der Wert der Konstante. In PHP 5 muss value ein scalarer Wert (int, float, string, bool, oder null) sein. In PHP 7 werden auch Array-Werte akzeptiert.
                Warnung
                Obgleich es möglich ist, Konstanten vom Typ Ressource zu definieren, wird dies nicht empfohlen, da es ein unvorhersagbares Verhalten des Programms zur Folge haben kann.

                new PDO(...) oder new SQLite3 liefert ein Objekt. Das ist kein Skalar und kein Array, es kommt vermutlich einer Ressource näher. Und deswegen bin ich davon ausgegangen, dass man das lassen sollte. Die Warnung steht bestimmt nicht zum Spaß im Handbuch. Leider erklärt sie nicht, was genau das Problem sein kann.

                Rolf

                --
                sumpsi - posui - obstruxi
                1. Die Warnung steht bestimmt nicht zum Spaß im Handbuch.

                  Oder jemand war zu faul. Oder es funktioniert nicht wie vom Autor ursprünglich geplant…

                  Leider erklärt sie nicht, was genau das Problem sein kann.

                  Naja. Erklär mal einem Leser, warum bei einem als Konstante instanzierten Objekt Eigenschaften sehr wohl mit einem Setter (und durch andere Objekt-Methoden) geändert werden können, nicht aber direkt.

                  Und naja. Wenn sich ein Objekt mal so und mal so verhält, dann ist das verwirrend. Das ist wohl mit „nicht vorhersehbar“ gemeint. Ansonsten ist es Eigenschaft eines Programmes, dass es sich (abgesehen von der Generierung von Zufallswerten) stets gleich verhält. Man könnte das also dokumentieren.

              2. <?php
                class Foo {
                	
                	var $foo = 0;
                	var $bar = 0;
                	function __construct( $foo, $bar ) {
                		$this->foo = $foo;
                		$this->bar = $bar;
                	}
                	function setFoo( $v ) {
                		$this->foo = $v;
                	}
                	function setBar( $v ) {
                		$this->bar = $v;
                	}	
                	
                }
                
                define (
                	'Objekt',
                	new Foo(1,1)
                );
                
                echo 'Objekt->foo : ' . Objekt->foo . PHP_EOL;
                echo 'Objekt->bar : ' . Objekt->bar . PHP_EOL;
                
                ### Das geht nicht:
                #Objekt->bar=2;
                #Objekt->bar=2;
                #echo 'Objekt->foo : ' . Objekt->foo . PHP_EOL;
                #echo 'Objekt->bar : ' . Objekt->bar . PHP_EOL;
                
                
                ### Mit den Settern geht es aber:
                Objekt->setFoo(2);
                Objekt->setBar(2);
                
                echo 'Objekt->foo : ' . Objekt->foo . PHP_EOL;
                echo 'Objekt->bar : ' . Objekt->bar . PHP_EOL;
                
                Objekt->foo : 1
                Objekt->bar : 1
                Objekt->foo : 2
                Objekt->bar : 2
                

                Fazit: Sogar Eigenschaften eines Objektes sind auch dann veränderlich, wenn das Objekt als Konstante abgelegt wurde. Aber nur mittels einer Objekt-Methode wie den gezeigten Settern.

            3. statt $_GLOBALS kann man auch das global Statement verwenden.

              Ja. Auch der Mist geht. Das die Variable $GLOBALS heißt ist auch so ein „Hirnfurz“: Superglobale Variablen sind $_SERVER, $_GET, $_POST, $_FILES, $_COOKIE, $_SESSION, $_REQUEST, $_ENV und dann („Peng!“) $GLOBALS!

              Wenn ich ganz ehrlich bin, dann bin ich „nicht besonders hell begeistert“, wenn man in Programmiersprachen ein- und das selbe auf gefühlte 16.389 Weisen machen kann. Diese ganzen Aliase und Alternativen (mit teilweise kruden Schreibweisen) muss man zwar nicht selbst benutzen, aber wahrscheinlich lesen.

              • Und bei manchen dann auch noch um die im Detail liegenden Abweichungen wissen…

              Und für die zugehörigen Parser, Linter, Interpreter oder Kompiler gilt das letztendlich auch. Mir kann keiner erzählen, dass eine solche Alternativenwulst die Ausführung von Skripten schneller macht und auch nur irgendwas vereinfacht. Ich denke, da werden einfach Designfehler der Programmiersprache („Hirnfürze“) konserviert.

              Zur Berechnung im Titel:

              „Nur“ 100 Items, welche die Kompilierungs- oder Ausführungszeit eines Programmes jeweils um „unbeachtliche“ 0,5% erhöhen, machen es im schlimmsten Fall so langsam, dass es die 1,646-fache Zeit braucht…

          2. Erstmal 1000 Dank, Willi! 👍

            1_Beispiel->sagt() > 1000_Worte->sagt():

            Wem sagst Du das?

            meineRede = 1_Beispiel->sagt() > 1000_Worte->sagt(); 😅

            Hinweis:

            Eigentlich ist die Verwendung von $GLOBALS ein „Hirnfurz“, weil das die Klarheit beseitigt, was in den Variablen steht.

            Stimmt, aer war trotzdem ein gutes Beispiel, weil nochmal klar gemacht hat, worauf Du hinaus wolltest.

            Alternative? Konstanten:

            define (
                'FH',
                fopen( __FILE__, 'r' )
            ); 
            
            
            $i=0;
            while( $row = fgets( FH ) ) {
            	echo ( $i++ ) . "\t" . htmlspecialchars( $row );
            }
            

            Benutze also die Konstante wie gezeigt. Die sind in PHP immer global.

            Sehr gute Idee. Werde ich machen, bzw. mache ich heute auch schon, nämlich arbeite ich in Datenbanken eigentlich immer mit Tabellenpräfixen... und genau da nutze ich immer Konstanten.

            Und, ich muss es zugeben, bei nder Umstellunmg von php7 auf php8 nutze ich grad auch Konstanten, weil ich sehr, sehr oft in Funktionsaufrufen die Anführungszeichen bei Stringparametern weggelasen habe. Und da hab ich jetzt (erstmal) eine Handvoll Strings als Konstanten declariert, damit mir nihct bei jedem 2. Schritt meine Anwendung mit FatalError abschmiert.

            Jörg

  4. Hi,

    try {
    $db = new PDO("mysql:host =$server;dbname=$name;charset=utf8;port=3306",$user,$passwd);
       $db->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
    } catch (PDOException $e) {
        echo 'Verbindung fehlgeschlagen: ' . $e->getMessage();
    }
    
    $query_ma = "SELECT ID,User FROM myuser";
    $result_ma = $db->query($query_ma);
    

    ist nicht wirklich sinnvoll - wenn die Verbindung fehlschlägt, wird eine Meldung ausgegeben, aber danach munter weiter auf die Verbindung zugegriffen.

    PHP Fatal error:  Uncaught Error: Call to a member function query() on null in ...
    

    Weiß grad gar nicht, was php zu meckern hat?
    Wersagts mir?

    PHP hat's Dir doch gesagt: das Objekt, auf dem Du query aufrufst (also $db), ist null.

    cu,
    Andreas a/k/a MudGuard