Verwirrender PHP Objekt Fehler

Fragen zu allen Themen rund ums Programmieren außerhalb von phpBB können hier gestellt werden - auch zu anderen Programmiersprachen oder Software wie Webservern und Editoren.
Antworten
Benutzeravatar
gn#36
Ehrenadmin
Beiträge: 9313
Registriert: 01.10.2006 16:20
Wohnort: Ganz in der Nähe...
Kontaktdaten:

Verwirrender PHP Objekt Fehler

Beitrag von gn#36 »

Ich rätsele gerade an einem ziemlich verwirrenden Fehler herum. Das ganze hat nicht direkt mit PHPbb zu tun, daher bitte keine Kommentare wie "Die Funktion gibt's nicht" oder so.

Situation:
ich habe ein sehr kurzes Testscript geschrieben, welches eine SQL Fehlermeldung provoziert (Einfach SQL Abfrage mit "Diese Abfrage produziert einen Fehler" :) ). Die Abfrage wird von einem Datenbankobjekt ausgeführt, welches im Fehlerfall die Fehlermeldungen sofort abfragt und in einem Array speichert. Dieses Datenbankobjekt besitzt außerdem eine Funktion, mit der ich diese Fehlermeldung formatiert zurückgeliefert bekomme, also Array -> String. Außerdem gibt es ja die PHP Fehlerbehandlung, welche ich mit einer eigenen überschreibe.
Der Effekt ist jetzt folgender:
  • PHP 5 verhält sich exakt so wie man es erwarten sollte (auch wenn es ein wenig gebraucht hat meinen "mental error" zu finden, denn ich hielt erst PHP 5 für falsch). Nachdem ich den Fehler verursacht habe wird dieser in einer Variablen gespeichert. Dann benutze ich trigger_error(). Im Zuge dieser Funktion passiert ein Datenbankaufruf, der Fehlerfrei vonstatten geht (Log ist keine Datei sondern eine Datenbanktabelle). Daher ist danach kein Fehler mehr da (letzte Aktion wird jeweils gespeichert) und ich bekomme, wenn ich die Fehlermeldung neu Abfrage kein Ergebnis mehr.
  • In PHP 4 dagegen bekomme ich eine Fehlermeldung in die erste Variable (sollte so auch sein) ich bekomme eine in die Datenbank (auch gut) aber ich bekomme danach immer noch die Fehlermeldung geliefert, obwohl ja die letzte Datenbankabfrage offenbar geklappt haben muss.
Während ich das hier schreibe kommt mir die Vermutung, dass an dieser Stelle die Objektbehandlung in PHP 4 und 5 ein wenig anders läuft? Denn ich speichere in meinem error Handler das Datenbankobjekt zwischen.
Wenn hierbei eine komplette Kopie angelegt würde, dann würde das logischerweise bedeuten, dass ich beim Datenbankupdate mit dem error_handler keine Änderung an den Variablen des globalen Datenbankobjekts vorgenommen habe, sondern nur an den Variablen des Lokalen Objekts. Da beim Kopieren des Objekts die Verbindung bereits hergestellt war und die Verbindungsdaten im Objekt lagen, dürfte sich bei der Interaktion mit der Datenbank kein Unterschied ergeben. Wenn es aber um lokale Daten im Objekt geht schon.
Wobei sich dann wiederum PHP 5 blödsinnig verhalten würde, denn wenn mein globales Datenbankobjekt nicht dasselbe ist wie das, welches ich im Error Handler benutze (da ich ja eine Kopie erzeuge), dann dürfte die Abfrage im Error Handler keine Fehlermeldungen löschen.
Ich erzeuge die Kopie (oder Referenz?) mit diesem Code:

Code: Alles auswählen

function set_db_object($db_object,$db_tabelle = '')
		{
			if($db_object)
			{
				$this->db = $db_object;
				if($db_tabelle)
				{
					$this->db_table = $db_tabelle;
				}
				elseif(!$this->db_tabelle)
				{
					$this->db_tabelle = 'error_logfile';
				}
				$this->log_type = 'db';
			}
			else
			{
				$this->log_type = 'file';
			}
		}
Meine Vermutung wäre: PHP 5 legt nur eine Referenz an und benutzt weiterhin das übergebene (in diesem Fall globale) Objekt.
PHP 4 Interpretiert das "wörtlich" und kopiert das Objekt vollständig, so dass 2 unabhängige Objekte entstehen.
Hier noch als Beispiel mein T[codeestcode:

Code: Alles auswählen

include(ROOTPATH . 'basis/config.php');
$db->sql('Diese Abfrage produziert einen Fehler');
$fehler = $db->error();
trigger_error(strip_tags($db->error()),E_USER_WARNING);
$fehler2 = $db->error();
$fehler3 = print_r($db->error,true);
echo "<br>\n<span style='color:green'>FEHLER:</span> $fehler <br> \n <span style='color:green'>FEHLER2:</span> $fehler2";
echo "<br>\n<span style='color:green'>FEHLER3: </span>$fehler3 ";
Config.php übernimmt in diesem Fall die Initialisierung usw.
Ausgabe von PHP4 ist diese:
FEHLER: SQL Error NR: 1064
Errortext: You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near 'Diese Abfrage produziert einen Fehler' at line 1
Fehlerhaftes Query: Diese Abfrage produziert einen Fehler
FEHLER2: SQL Error NR: 1064
Errortext: You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near 'Diese Abfrage produziert einen Fehler' at line 1
Fehlerhaftes Query: Diese Abfrage produziert einen Fehler
FEHLER3: Array ( [TEXT] => You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near 'Diese Abfrage produziert einen Fehler' at line 1 [NR] => 1064 [QUERY] => Diese Abfrage produziert einen Fehler )
Die Ausgabe von PHP 5 diese:
FEHLER: SQL Error NR: 1064
Errortext: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'Diese Abfrage produziert einen Fehler' at line 1
FEHLER2:
FEHLER3: Array ( )
Hat jemand vielleicht noch eine andere Idee, oder kann das bestätigen? Das wird vermutlich nicht an der Tatsache liegen, dass es sich um ein Objekt mit Datenbankinteraktionen handelt, ich vermute es geht auch mit jedem beliebigen anderen Objekt als beispiel.
Begegnungen mit dem Chaos sind fast unvermeidlich, Aber nicht katastrophal, solange man den Durchblick behält.
Übertreiben sollte man's im Forum aber nicht mit dem Chaos, denn da sollen ja andere durchblicken und nicht nur man selbst.
PhilippK
Vorstand
Vorstand
Beiträge: 14662
Registriert: 13.08.2002 14:10
Wohnort: Stuttgart
Kontaktdaten:

Beitrag von PhilippK »

Mir wird hier noch nicht so ganz klar, was du genau erreichen willst - und wie du dazu vorgegangen bist.
Für was musst du überhaupt den PHP-Errorhandler überschreiben. Eine Fehlerhafte MySQL-Abfrage erzeugt ja keinen PHP-Fehler :-?

Ansonsten ist das Objektmodell von PHP 5 deutlich anders als das von PHP 4 - vor allem wenn es um Details geht. Da kann ein unterschiedliches Verhalten durchaus möglich sein.

Gruß, Philipp
Kein Support per PN!
Der Sozialstaat ist [...] eine zivilisatorische Errungenschaft, auf die wir stolz sein können. Aber der Sozialstaat heutiger Prägung hat sich übernommen. Das ist bitter, aber wahr. (Horst Köhler)
Meine Mods
Benutzeravatar
gn#36
Ehrenadmin
Beiträge: 9313
Registriert: 01.10.2006 16:20
Wohnort: Ganz in der Nähe...
Kontaktdaten:

Beitrag von gn#36 »

Im Prinzip habe ich die meisten Fragen beim Verfassen des Textes - da mir dann neue Ideen kamen woran das ganze liegen könnte - selbst klären können. Irritiert hatte mich ursprünglich, dass PHP 5 sich nicht so verhielt wie ich erwartet hatte, PHP 4 dagegen schon.
Den Error_Handler habe ich überschrieben, um mir selbst die Fehlermeldungen der noch ziemlich neuen Seite einfacher und besser Formatiert zugänglich zu machen, auch wenn ich selbst nicht derjenige bin, der den Fehler auslöst. Dabei ging es mir um alle Arten von Fehlern, also PHP eigene und auch Datenbankzugriffsfehler. Es ist klar, dass mysql keine Fehlermeldung ausgibt, wenn ein Fehler bei einem Aufruf auftritt, aber da ich ein Datenbankobjekt als Wrapper verwende ist das ja kein Problem. Ich kann nach jeder Abfrage den Erfolg der Aktion abfragen und dann - wenn nötig - selbst einen Error triggern (das ginge natürlich auch ohne das überschreiben des error_handlers, aber zum einen wollte ich das mal ausprobieren und zum anderen sind die Fehlermeldungen deutlich besser dargestellt).

Das ursprüngliche Problem war, dass auf dem Server eine Fehlermeldung angezeigt wurde durch eine fehlerhafte SQL Abfrage (soweit nichts ungewöhnliches bei einer neuen Seite), mein Testsystem zuhause brach an dieser Stelle zwar ebenfalls aus dem gleichen Grund ab, gab aber - bei identischen Dateien - keine Fehlermeldung aus.
Noch mehr irritierte mich aber dann, dass sowohl auf dem Server, als auch auf meinem Testsystem ein Eintrag zu diesem Fehler im error_log zu finden war wo genau der Text eingetragen war, welcher bei der Fehlermeldung im Testsystem fehlte.
Ich habe dann den Fehler auf eine Zeile Programmcode eingrenzen können, das war die Zeile

Code: Alles auswählen

trigger_error(strip_tags($db->error()),E_USER_ERROR);
Ohne diese Zeile im Skript lief alles in beiden Systemen erwartungsgemäß.
Da trigger_error und strip_tags beides PHP eigene Funktionen waren habe ich einen Fehler hierin natürlich erst einmal ausgeschlossen und mir weiter die Funktion error() im Datenbankobjekt angesehen, welche ja auch selbstgeschrieben war.

Code: Alles auswählen

function error($wrong_query = false)
 		{
 			if($this->error)
 			{
 				return '<b>SQL Error NR: </b> '.$this->error['NR']."\n".' <br><b>Errortext: </b> '.$this->error['TEXT'] .($wrong_query? "\n".'<br><b>Fehlerhaftes Query: </b>'.$this->error['QUERY']:'');
 			}
 			else
 			{
 				return '';
 			}
 		}
Wie man sieht sehr übersichtlich, denn der SQL Fehler wird - falls er auftritt - ja bereits bei der Abfrage selbst abgefragt und gespeichert, so dass das hier nicht mehr erforderlich ist.
An dieser Stelle kam ich nun nicht mehr weiter, denn in dieser Funktion war eindeutig kein Fehler zu erkennen, auch mehrfacher Aufruf hintereinander ändert den Rückgabewert nicht, und nichts anderes hatte ich in meinem Skript gemacht, nach der Triggerung des Errors sollte dieser lediglich durch Benutzung der selben Funktion über

Code: Alles auswählen

echo $db->error(); 
auch an den Benutzer ausgegeben werden, genau das funktionierte aber in Kombination mit oben geposteter Zeile nicht.

Nach einiger Rätselei und zwecklosem Rumprobieren entschloss ich mich einen Beitrag hier ins Forum zu setzen. Während ich den Text schrieb fiel mir wieder ein, dass ich die Fehlerbehandlung überschrieben hatte und habe ausprobiert was passiert wenn ich das nicht tue. Nachdem dann alles funktionierte wusste ich, dass hier irgendwo der Fehler liegen musste und habe mir die Eintragungsfunktion genauer angesehen. Der Error Handler trägt den Fehler in die Datenbank in einer speziellen Tabelle ein. Da hierfür die gleiche Verbindung verwendet wird wie für die restlichen Daten der Seite sieht der Error Handler die Möglichkeit vor, per Funktion ein Datenbankobjekt anzugeben, mit dem die Eintragung vorgenommen werden soll, im Notfall weicht er auf dateibasiertes Logging aus. Die Funktion zur Übergabe ist in meinem ersten Post zu finden. Da aber die Daten in die gleiche Datenbank eingetragen werden, dies aber fehlerfrei vonstatten ging kam mir die Idee, dass dann wohl logischerweise auch keine Fehlermeldung mehr da sein dürfte, da das Datenbankobjekt immer nur die letzte Fehlermeldung speichert.
Jetzt war ich auf dem Standpunkt angekommen, dass das was bei mir Lokal passierte vollkommen logisch war, da ja nach der Abfrage eine neue stattfindet, die die alte Fehlermeldung löscht, somit ist diese dann nicht mehr da wenn ich versuche sie abzufragen.
Die Frage war jetzt aber: Warum ist das in PHP 4 anders?
Daraufhin habe ich mir die Funktion ste_db_object() aus meinem ersten Posting noch mal angesehen und da besonders diese Zeile:

Code: Alles auswählen

$this->db = $db_object;
Hier erzeuge ich effektiv eine lokale Kopie des als Parameter der Funktion übergebenen Objekts. Das würde aber wiederum bedeuten dass sämtliche Attribute des Objekts ebenfalls kopiert würden und somit doppelt existieren. Für die Datenbankverbindung ergibt sich hieraus kein Nachteil, den mysql Funktionen ist es ja egal in welchen Variablen die Verbindungsdaten liegen. Da die Fehlermeldung aber in einem dieser Attribute gespeichert wird macht das sehr wohl einen Unterschied. Wenn nämlich eine lokale Kopie erzeugt wird, dann bedeutet dass, dass wenn ich mit meiner SQL Abfrage die Fehlermeldung lösche (es ist ja bei der Eintragung in die error_log Tabelle kein Fehler aufgetreten) dies nur in dem lokalen Objekt welches in dem error_handler gespeichert ist geschieht. Da $db->error() die Fehlermeldung nicht nochmals überprüft, sondern nur die schon gespeicherten Daten zurückliefert, wird in diesem Fall beim lokalen Objekt nichts mehr zu finden sein (Fehlermeldung ist ja von der neuen Abfrage überschrieben), im globalen Objekt aber sehr wohl, denn dieses hat ja die Abfrage nicht ausgeführt und hat die Fehlermeldung noch gespeichert.
Jetzt war ich also wieder an dem Punkt angelangt, wo PHP 4 sich vollkommen logisch verhielt und PHP 5 nicht, denn PHP 5 unterschied offenbar nicht zwischen dem lokalen und dem globalen Objekt.

Genau hier setzt im Prinzip meine Frage an:
Übergibt PHP 5 Objekte generell als Referenz? Ich würde bei dem Aufruf den ich in der Funktion set_db_object verwendet habe vermuten, dass eine lokale Kopie des Objektes angelegt wird. Wenn dem so ist: Wie kann ich verhindern, dass ein Objekt als Referenz übergeben wird?
Begegnungen mit dem Chaos sind fast unvermeidlich, Aber nicht katastrophal, solange man den Durchblick behält.
Übertreiben sollte man's im Forum aber nicht mit dem Chaos, denn da sollen ja andere durchblicken und nicht nur man selbst.
Antworten

Zurück zu „Coding & Technik“