Du bist nicht angemeldet.

Johannes S.

Fortgeschrittener

  • »Johannes S.« ist der Autor dieses Themas

Beiträge: 444

Registrierungsdatum: 24.06.2011

Wohnort: Lychen

Danksagungen: 71

  • Private Nachricht senden

1

19.06.2014, 23:09

Merkwürdiger Fehler

EDIT: Mir ist noch was aufgefallen, was ich vorher leider immer übersehen habe, wobei ich der Meinung bin, dass das bei meinen "damaligen" Tests hätte auffallen müssen: Die Werte in den Feldern sind im gesamten Array gleich. Es wird also für jedes Element ein Eintrag in $data['news'] angelegt, aber anscheint ist das überall das selbe Element. Damit ist das Problem womöglich darauf zurückzuführen, dass der Fehler einfach darin liegt, dass Jedes Element in data['news'] eine Referenz auf das selbe Array ist und somit nur der letzte Wert in allen Felden drin steht, was in meinem Fall null für messages ist und zufälligerweise auch bei den anderen Timelines, an denen ich das getestet habe, null gewesen sein könnte.

(Das heißt, man kann den nachfolgenden Text auch als Veraltet betrachten.)


Hi, ich hatte vor ein paar Wochen ein Problem mit PHP und am Ende ein Workaround geschrieben, ohne die Ursache für den Fehler zu verstehen. Ich dachte heute mal, ich teile meine Erkenntnisse mit euch. Ich habe den Fehler heute zur Sicherheit nochmal (im entsprechenden Projekt) reproduziert und ein paar Tests gemacht.

Hier zunächst der problematische Code. Da ich den Fehler bis heute nicht verstanden habe, kann ich nicht garantieren, dass der Fehler bei euch genau so auftritt. Vielleicht habe ich einfach eine schlechte PHP-Version PHP 5.5.9 (cli) (built: Feb 12 2014 21:03:16) oder PHP mag die Stelle im Arbeitsspeicher nicht, an die der Code kopiert wird.^^

Problematischer Code

PHP-Quelltext

1
2
3
4
5
6
7
8
9
10
$data['news'] = array();
foreach ($messageObjects as $messageObj) {
    $news = array();
    $data['news'][] =& $news;

    $news['id'] = $messageObj->getProperty('id');
    $news['message'] = $messageObj->getProperty('message');
    $news['picture'] = $messageObj->getProperty('picture');
    $news['link'] = $messageObj->getProperty('link');
}


$messageObjects ist ein Array mit Objekten der Klasse GraphObject der Facebook-PHP-SDK v4.
https://github.com/facebook/facebook-php-sdk-v4/blob/master/src/Facebook/GraphObject.php

Wie man vielleicht erkennen kann ist mein Ziel recht einfach. Ich möchte in $data['news'] ein Array mit den Nachrichten von Facebook haben, wobei eine Nachricht durch ein assoziatives Array mit den Schlüsseln id, message, picture und link dargestellt wird. Inzwischen sind noch einige mehr dazu gekommen, aber um das Beispiel nicht zu sehr zu strecken hier nur die 4 Elemente, die ich damals hatte.

Hier jetzt mein Workaround, bevor ich zu dem eigendlichen Fehler komme. Dieser funktioniert ohne, dass ich auch nur eine Leerzeile an einer anderen Stelle im Code hinzugefügt habe (also das war wirklich die einzige Änderung).

Workaround

PHP-Quelltext

1
2
3
4
5
6
7
8
9
10
11
$data['news'] = array();
foreach ($messageObjects as $messageObj) {
    $news = array();

    $news['id'] = $messageObj->getProperty('id');
    $news['message'] = $messageObj->getProperty('message');
    $news['picture'] = $messageObj->getProperty('picture');
    $news['link'] = $messageObj->getProperty('link');

    $data['news'][] = $news;
}


Kommen wir zum Fehler und meinen Beobachtungen: Die Arrays in $data['news'] enthielten wie erwartet die 4 Felder, nur war das Feld message immer null, Alle anderen Felder funktionierten ohne Probleme: Die id enthielt die des Posts, picture enthielt den Link zum Vorschaubild, wenn eins vorhanden war, und link enthielt den geposteten Link, wenn einer gepostet wurde. Es hat wirklich lange gedauert, bis ich herausgefunden hatte, dass der Wert von message nicht ordentlich über die Referenz übergeben wurde. Meine erste Vermutung war, dass getProperty(...) eben null zurück gibt. Später schob ich den Fehler auf die Ausgabe. Später habe ich durch den folgenden Test die übergebe durch die Referenz als einzigen möglichen Fehlerpunkt entlaft (Die den Testcode habe ich gerade geschrieben und nicht nochmal getestet [syntax-Fehler möglich], er soll nur zeigen an welchen Stellen ich welche Ausgaben hinzugefügt habe):

Test

PHP-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$data['news'] = array();
foreach ($messageObjects as $messageObj) {
    print_r($messageObj->getProperty('message'));

    $news = array();
    $data['news'][] =& $news;

    $news['id'] = $messageObj->getProperty('id');
    $news['message'] = $messageObj->getProperty('message');
    $news['picture'] = $messageObj->getProperty('picture');
    $news['link'] = $messageObj->getProperty('link');

    print_r($news);
}
print_r($data['news'][0]);

Wie gesagt waren die ersten beiden Test-Ausgaben (mehrfache, da in der Schleife) wie erwartet (mit den entsprechenden Nachrichten), aber in der dritten hatte message zwar existiert, war aber null.

Weiter habe ich heute durch andere Tests noch folgendes heraus gefunden:
  • Der Fehler tritt unabhängig von Feldnamen auf, wenn ich $news['message'] in $news['xyz'] ändere, ist eben xyz gleich null.
  • Eine weitere Sache, die das alles noch sonderbarer macht: Wenn ich den Text, welcher message zugewiesen werden soll, direkt in den Code schreibe und nicht durch getProperty hole, tritt der Fehler nicht auf.
  • Außerdem kann ich die Reihenfolge der Zuweisungen ändern, ohne dass sich dadurch etwas ändert.
  • Ich kann auch mehrere Felder (mit unterschiedlichen Namen) angeben, denen ich getProperty('message') zuweise, und alle sind am Ende null.
  • Wenn ich dem Feld den Wert mehrfach zuweise, ändert das auch nichts am Ergebnis.


Somit scheint der Fehler durch die Kombination der Nutzung einer Referenz und dem Aufruf von getProperty(...) mit dem Parameter 'message' verursacht zu werden. Falls es noch andere Ideen gibt, bin ich interessiert.
Signatur ?

Dieser Beitrag wurde bereits 8 mal editiert, zuletzt von »Johannes S.« (20.06.2014, 15:14)


psycho

Fortgeschrittener

Beiträge: 413

Registrierungsdatum: 26.06.2011

Danksagungen: 80

  • Private Nachricht senden

2

20.06.2014, 12:12

Hm sehr merkwürdig, ich versuche das ganze mal zu reproduzieren und dann zu berichten.

Auf dem ersten Blick kann ich keinen Fehler erkennen.

Aber mal eine andere Frage... Warum speicherst du nicht einfach gleich das ganze Objekt in dem Array?

Oder ist das messageObj so groß?

Ich mein guck dir von Laravel die Models an... Das sind auch Objekte mit vielen Eigenschaften, trotzdem habe ich noch nie jemanden gesehen, der nur einen Teil der Eigenschaften an den View weiter gibt.

Was passiert wenn du die Reihenfolge änderst? Ist es immer nur das message Feld ? Sonst guck dir doch mal den Code von getProperty an...
Ist aber ein sehr komischer Fehler.

Wenn ich mal komische Fehler hatte, lag es aber meistens an irgendwelchen Abhängigkeiten oder Zeilen die zum debuggen waren und vergessen wurden zu entfernen. Das sind dann meistens ganz ärgerliche Fehler wo man dann ewig sucht.
Computer sind dazu da, uns die Arbeit zu
erleichtern, die wir ohne sie gar nicht hätten.

Johannes S.

Fortgeschrittener

  • »Johannes S.« ist der Autor dieses Themas

Beiträge: 444

Registrierungsdatum: 24.06.2011

Wohnort: Lychen

Danksagungen: 71

  • Private Nachricht senden

3

20.06.2014, 15:12

Die oberste (fett getruckte) Absatz sollte eigendlich sagen, dass ich mich anscheint vertan habe. Ich wollte den Beitrag aber auch nicht einfach löschen, daher habe ich das nur groß drüber geschrieben. Es ist meiner Meinung nach zwar immer noch ein Fehler seitens PHP, allerdings nicht so undurchsichtig. Vermutlich optimiert PHP die Schleife insofern, dass die Variable $news bei jedem durchgang die selbe ist. Normalerweise währe das kein Problem, wenn ich sie nicht immer nur als Referenz zuweisen würde, wodurch Änderungen in Späteren Schleifendurchläufen auch die vorherigen Objekte beeinträchtigen. Ob diese (neue) Einschätzung stimmt, weiß ich nicht. Ist nur eine Vermutung, die ich auch noch nicht genauer untersucht habe.
Signatur ?

liro

Fortgeschrittener

Beiträge: 180

Danksagungen: 36

  • Private Nachricht senden

4

22.06.2014, 09:03


[...]
Oder ist das messageObj so groß?
[...]

Selbst dann macht das Umkopieren keinen Sinn, denn das messageObj liegt bereits vollständig im Speicher. Wenn mans noch mal umkopiert wird der Speicherverbrauch nur höher.

psycho

Fortgeschrittener

Beiträge: 413

Registrierungsdatum: 26.06.2011

Danksagungen: 80

  • Private Nachricht senden

5

22.06.2014, 12:10

Nicht zwangsläufig... Wenn er beispielweise das Array später noch mal iteriert ist ein kleines wohl besser als ein großes, welches mit unnützen Informationen gefüllt ist.

Fragt sich nur ob der Aufwand sich lohnt im Endeffekt.
Computer sind dazu da, uns die Arbeit zu
erleichtern, die wir ohne sie gar nicht hätten.

Ähnliche Themen

Verwendete Tags

Fehler, PHP, webentwicklung