PHP syntax error unexpected double-quoted string
Ferdinand
- php
Okaaay, ich bin raus
Ein eigentlich super simples PHP Skript
$conn = mysqli_connect("","root","","dbname");
$sql = "SELECT user, score, timestamp FROM myTable";
$result = mysqli_query($conn, $sql);
if (mysqli_num_rows($result) > 0) {
while($row = mysqli_fetch_assoc($result)) {
echo "user: " . $row["user"] . " - score: " . $row["score"] . " " . $row["timestamp"] . "<br>";
}
} else {
echo "0 results";
}
mysqli_close($conn);
erzeugt
Parse error: syntax error, unexpected double-quoted string "user: "
bezogen auf die die Zeile echo "user: " . $row["user"] . " - score: " . $row["score"] . " " . $row["timestamp"] . "<br>";
ARG Hilfe?
Danke, Ferdinand
Nein. Hab das getestet. Der Fehler liegt definitiv außerhalb des gezeigten Codes.
→ Oft ein vergessenes Quota weiter oben. Ein Editor mit Syntaxbeleuchtung hilft Dir.
Hallo Raketenwilli,
hast Du kein Bett? Oder trainierst Du für die Silvesternacht?
Ich sehe aber auch im Umfeld der Zeile nichts inkriminierendes. Ein verschlabbertes " oder ; VOR dieser Stelle hätte sich bei diesem Code schon früher bemerkbar machen sollen. Find ich…
Ferdinand,
ist dieser Code alles, was in der PHP Datei drinsteht (außer einem einleitenden <?php
natürlich)?
Meine Hypothese 1: du guckst auf die falsche Stelle. Gibt's diese Zeile anderswo nochmal? Copy&Paste? Ein Parse Error wird normalerweise von Dateiname und Zeilennummer begleitet.
Eine SEHR UNWAHRSCHEINLICHE Hypothese ist ein Zeichen im Code, das wie ein normales ASCII Zeichen aussieht, aber keins ist. Sowas kann passieren, wenn man Code aus dem wilden weiten Web kopiert und der Autor "schicke Typographie" im Code haben wollte oder geschützte Leerzeichen eingesetzt hat. Aber das hätte sich beim Kopieren hier ins Forum übertragen müssen, deshalb: Sehr unwahrscheinlich.
Wenn die Stelle stimmt (bei vorhandenen Kopien lässt sich das zur Not durch Abändern von "user: " in "userin: " oder ähnlichem beweisen), aber viel Code vorneweg steht, kannst Du den gezeigten Code in eine andere PHP Datei kopieren und separat ausführen. Kommt dann kein Parse Error, fügst Du immer mehr (sinnvolle) Codestücke aus dem Original dazu, ausgehend von der kaputten Stelle aus nach oben. Da ein Parse Error vor der Ausführung entdeckt wird, könnte es nützlich sein, direkt hinter dem ersten <?php ein exit;
zu notieren, damit PHP bei fehlendem Parse Error nichts ausführt, was ggf. Schaden anrichtet.
Rolf
hast Du kein Bett?
Doch. Aber ich bin aus dem selben gefallen, weil jemand Auto gefahren ist, der das nicht hätte tun sollen. War ziemlich laut. Mit dem Auto macht der das nicht mehr.
Ein Editor mit Syntaxbeleuchtung hilft Dir.
Steht man völlig auf dem Schlauch, hilft auch das Entfernen der bemängelten Zeilen und, nach und nach, ihrer Umgebung, so oft bzw. weit, bis auch die Fehlermeldungen verschwinden.
Das ist dann eine Art indirekter Eingrenzung mit dem Holzhammer – so lange kaputtkloppen, bis es heil ist.
Hi,
Ein eigentlich super simples PHP Skript erzeugt
Parse error: syntax error, unexpected double-quoted string "user: "
bezogen auf die die Zeileecho "user: " . $row["user"] . " - score: " . $row["score"] . " " . $row["timestamp"] . "<br>";
Hast Du das Skript hier reinkopiert, oder (inkl. automatischer Korrektur) hier eingetippt?
Der Code sieht ok aus, auch der Highlighter macht keine verrückten Sachen damit, daher mein Verdacht, daß der hier gezeigte Code nicht identisch mit dem ist, der das Problem verursacht.
cu,
Andreas a/k/a MudGuard
Moin Ferdinand,
das
echo "user: " . $row["user"] . " - score: " . $row["score"] . " " . $row["timestamp"] . "<br>";
geht auch einfacher und mutmaßlich performanter, da die Einzelteile direkt in die Ausgabe geschrieben und nicht erst konkateniert werden müssen:
echo "user: ", $row["user"], " - score: ", $row["score"],
" ", $row["timestamp"], "<br>";
Soweit ich das sehe, passen da die Quotes. Was fehlt: die kontextgerechte Behandlung der SQL-Rückgabe für HTML – verwende htmlspecialchars
.
Viele Grüße
Robert
@@Robert B.
geht auch einfacher und mutmaßlich performanter, da die Einzelteile direkt in die Ausgabe geschrieben und nicht erst konkateniert werden müssen:
echo "user: ", $row["user"], " - score: ", $row["score"], " ", $row["timestamp"], "<br>";
Anstatt Konkatenation bietet sich ein Templatestring an:
printf(
"user: %1\$s – score: %2\$s %3\$s<br>",
$row["user"], $row["score"], $row["timestamp"]
);
Oder doch nicht, siehe unten.
Was fehlt: die kontextgerechte Behandlung der SQL-Rückgabe für HTML – verwende
htmlspecialchars
.
Yep:
printf(
"user: %1\$s – score: %2\$s %3\$s<br>",
htmlspecialchars($row["user"]),
htmlspecialchars($row["score"]),
htmlspecialchars($row["timestamp"])
);
Was noch fehlt: sinnvolles Markup anstatt <br>
. Das sollte wohl eine Liste <ul>
/<ol>
mit Listitems <li>
sein.
Und überhaupt würde eine vernünftige Syntax das ganze Rumgemache mit Konkatenation erübrigen.
🖖 Живіть довго і процвітайте
@@Gunnar Bittersmann
Was noch fehlt: sinnvolles Markup anstatt
<br>
. Das sollte wohl eine Liste<ul>
/<ol>
mit Listitems<li>
sein.Und überhaupt würde eine vernünftige Syntax das ganze Rumgemache mit Konkatenation erübrigen.
Sieht dann so aus – Markup und feststehender Text wird direkt notiert, per echo
werden nur die veränderlichen Daten ausgegeben. (Hier in der Kurzschreibweise <?=
)
<?php
$conn = mysqli_connect("", "root", "" ,"dbname");
$sql = "SELECT user, score, timestamp FROM myTable";
$result = mysqli_query($conn, $sql);
?>
<?php if (mysqli_num_rows($result) > 0): ?>
<ul>
<?php while($row = mysqli_fetch_assoc($result)): ?>
<li>
user: <?= htmlspecialchars($row["user"]) ?>
- score: <?= htmlspecialchars($row["score"]) ?>
<?= htmlspecialchars($row["timestamp"]) ?>
</li>
<?php endwhile; ?>
</ul>
<?php else: ?>
<p>0 results</p>
<?php endif; ?>
<?php
mysqli_close($conn);
?>
🖖 Живіть довго і процвітайте
Alles klar soweit. Nur:
Wenn man „teure“ Funktionen wie htmlspecialchars() auf einen „score“ (Integer bzw. Dezimalwert) oder Timestamp anwenden muss, die gerade aus eine Datenbank kommen, dann hat der Währunghüter(¹) was falsch gemacht.
¹) Person oder Organisation, die fest gelegt hat, was die Datenbank beinhaltet oder ausgibt.
n'Abend,
Wenn man „teure“ Funktionen wie htmlspecialchars() auf einen „score“ (Integer bzw. Dezimalwert) oder Timestamp anwenden muss, die gerade aus eine Datenbank kommen, dann hat der Währunghüter was falsch gemacht.
ja, mag sein. Aber auch pure Gewphnheit könnte einen dazu verleiten, htmlspecialchars() generell beim Ausgeben von HTML anzuwenden. Vielleicht kommen ja bei anderer Gelegenheit auch wieder alphanumerische Inhalte aus der DB, die auch mal '<' oder '&' enthalten könnten.
Es tut ja nicht weh und kostet nichts - außer Performance im ppm-Bereich.
Einen schönen Tag noch
Martin
@@Gunnar Bittersmann
Sieht dann so aus …
Weiteres Optimierungspotential: ersetze alle "
durch '
. Die Strings müssen ja nicht nach darin vorkommenden Variablen geparst werden.
🖖 Живіть довго і процвітайте
Weiteres Optimierungspotential: ersetze alle
"
durch'
.
Hallo Gunnar,
wenn überhaupt, ist das Nanooptimierung. Und eigentlich sollte der Bedarf, Variablen in einem Literal zu ersetzen, vom PHP Parser festgestellt werden und nicht zur Laufzeit. Findet er kein $, sollte die Ausführungszeit gleich sein.
Deshalb wundert es mich, dass Jörg da was feststellen konnte. Es sei denn, Lerdorf&Co haben mal wieder gepatzt. Verwunderlich wäre es nicht.
Rolf
Lerdorf&Co haben mal wieder gepatzt.
Gemecker 😀
Wenn gepatzt, dann bei echo $foo, $bar, $baz;
. Das scheint zu etwas echo $foo; echo $bar; echo $baz
zu werden, denn es muss ja einen Grund geben, warum das so viel langsamer als das Verbinden der Strings ist.
Wohl weil man das echo
so „notlos“ wie unbedingt nicht als Funktion notiert haben wollte.
Wir (hier im Forum) hatten genau das Thema schon mal (als PHP 7.2 neu war) und das Ergebnis hatte uns damals alle überrascht:
Zum selbst Testen:
<?php
# 1.php
$row["user"]="fritz";
$row["score"]=34;
$row["timestamp"]='2022-12-30';
for ($i=1;$i<100000;$i++) {
echo "user: ", $row["user"], " - score: ", $row["score"], " ", $row["timestamp"], "<br>";
}
<?php
#2.php
$row["user"]="fritz";
$row["score"]=34;
$row["timestamp"]='2022-12-30';
for ($i=1;$i<100000;$i++) {
echo "user: ". $row["user"]. " - score: ". $row["score"]. " ". $row["timestamp"]. "<br>";
}
Im Terminal ausgeführt (und die Ausgaben nach /dev/null umgeleitet) ist die Variante mit Konkatenierung stabil um den Faktor 3 schneller:
time 1.php > /dev/null
real 0m1,026s
user 0m0,523s
sys 0m0,472s
time 2.php > /dev/null
real 0m0,347s
user 0m0,126s
sys 0m0,186s
„Unverwässert“ durch z.b. ohne Zeiten für das Starten des Interpreters (user-time), wird sogar weniger als 1/4 der Zeit gebraucht. (Getestet auf Raspi4 mit PHP 8.2.0RC7 (cli) (built: Nov 26 2022 14:19:44) (NTS) )
Testsieger: Volles Konkatenieren des Outputs:
<?php
# 3.php
$row["user"]="fritz";
$row["score"]=34;
$row["timestamp"]='2022-12-30';
$out='';
for ($i=1;$i<100000;$i++) {
$out.="user: ". $row["user"]. " - score: ". $row["score"]. " ". $row["timestamp"]. "<br>";
}
echo $out;
time 3.php > /dev/null
real 0m0,197s
user 0m0,086s
sys 0m0,074s
Letzte Mikrooptimierung: Ersparen des Nachsehens, ob in den Strings etwas ersetzt werden muss ("
→ '
):
<?php
# 4.php
$row["user"]="fritz";
$row["score"]=34;
$row["timestamp"]='2022-12-30';
$out='';
for ($i=1;$i<100000;$i++) {
$out.='user: '. $row['user']. ' - score: '. $row['score']. ' '. $row['timestamp']. '<br>';
}
echo $out;
time 4.php > /dev/null
real 0m0,192s
user 0m0,109s
sys 0m0,055s
<?php
# 5.php
$row["user"]="fritz";
$row["score"]=34;
$row["timestamp"]='2022-12-30';
for ($i=1;$i<100000;$i++):
?>
'user: '<?=$row['user'];?>' - score: '<?=$row['score'];?>' '<?=$row['timestamp'];?>'<br>';
<?php
endfor;
time 5.php > /dev/null
real 0m0,127s
user 0m0,044s
sys 0m0,056s
Das machte „Wusch!“. Zum Vergleich noch mal die Zahlen des langsamsten Versuchs: echo der kommagetrennten Liste:
time 1.php > /dev/null
real 0m1,026s
user 0m0,523s
sys 0m0,472s
Das braucht 10 Mal so lange…
Guten Rutsch!
Das braucht 10 Mal so lange…
Ich habe Mist gemessen. Asche auf mein Haupt.
Ich hab versehentlich die Vorlage für das Skript getestet. Was ich also wirklich gemessen habe hat gar nichts ausgegeben.
<?php
# 5.php
$row["user"]="fritz";
$row["score"]=34;
$row["timestamp"]='2022-12-30';
for ($i=1;$i<100000;$i++):
?>
'user: '<?=$row['user'];?>' - score: '<?=$row['score'];?>' '<?=$row['timestamp'];?>'<br>';
<?php
endfor;
real 0m1,032s
user 0m0,533s
sys 0m0,468s
Und liegt damit sogar im Bereich des schlechtesten Ergebnisses:
time 1.php > /dev/null
real 0m1,026s
user 0m0,523s
sys 0m0,472s
So nebenher, bevor jemand fragt: Ein explizites implode()
mit einem als Konstante definierten Trenner lag zwischen Konkatenieren (das ist schneller) und der Übergabe als Liste (ist langsamer)
<?php
# 6.php
define ('DELIM', '');
$row["user"]="fritz";
$row["score"]=34;
$row["timestamp"]='2022-12-30';
$arr=[ 'user: ', $row['user'], ' - score: ', $row['score'], ' ', $row['timestamp'], '' ];
for ($i=1;$i<100000;$i++) {
echo implode( DELIM , $arr );
}
→
time php 6.php > /dev/null
real 0m0,298s
user 0m0,153s
sys 0m0,108s
@@Robert B.
geht auch einfacher und mutmaßlich performanter, da die Einzelteile direkt in die Ausgabe geschrieben und nicht erst konkateniert werden müssen:
echo "user: ", $row["user"], " - score: ", $row["score"], " ", $row["timestamp"], "<br>";
Beim Schreiben dieses Postings fiel es mir wie Schuppen aus den Haaren: Es geht noch einfacher! Innerhalb von "
werden Variablen ja aufgelelöst:
echo "user: $row[user] - score: $row[score] $row[timestamp]<br>";
(Über das <br>
hatte ich mich ja schon geäußert. at auch.)
Die bevorzugte sollte aber diese Variante sein (mit '
). Niemals Markup per echo
ausgeben, sondern nur die Daten.
🖖 Живіть довго і процвітайте
echo "user: $row[user] - score: $row[score] $row[timestamp]<br>";
Hm. Ja. Beide Varianten sind etwa gleich schnell und liegen (mit) vorn, aber hinter der 4. Variante (Konkatenieren aller Ausgaben)
<?php
# 7.php
$row["user"]="fritz";
$row["score"]=34;
$row["timestamp"]='2022-12-30';
for ($i=1;$i<100000;$i++) {
echo "user: ${row['user']} - score: ${row['score']} ${row['timestamp']}<br>";
#echo "user: $row[user] - score: $row[score] $row[timestamp]<br>";
}
→
time php 7.php > /dev/null
real 0m0,278s
user 0m0,109s
sys 0m0,141s
Niemals Markup per echo ausgeben, sondern nur die Daten.
Sag niemals „niemals“. 8.php = mix( '4.php', '7.php' )
<?php
# 8.php
$row["user"]="fritz";
$row["score"]=34;
$row["timestamp"]='2022-12-30';
$out='';
for ($i=1;$i<100000;$i++) {
$out.="user: ${row['user']} - score: ${row['score']} ${row['timestamp']}<br>";
}
echo $out;
→
time php 8.php > /dev/null
real 0m0,181s
user 0m0,081s
sys 0m0,073s
... das geht bis jetzt am schnellsten und erzeugt ergo am wenigsten Kohlendioxyd. Es kann also eine Frage der Präferenz bzw. Zielsetzung sein.
SELECT
CONCAT (
"user: ",
`user`,
" - score: ",
`score`,
" ",
`timestamp`
) AS `row`
FROM `myTable`;
(Syntax für mysql/mariadb)
Das geht freilich nur, wenn die Daten nicht auch noch anderweitig verarbeitet werden sollen und kann nachteilig sein, weil im Ergebnis mehr Daten über das langsame Netzwerk zurückgeliefert werden, ist sogar definitiv nachteilig, weil ein Teil des Outputs sogar im SQL notiert werden muss, was den Code schlechter pfleg- oder wiederverwendbar macht. Also nur testen und ggf. dann machen, wenn es wirklich schneller ist und aus $Gründen auf die Performance ankommt.
Hallo Raketenwilli,
je nach dem, wie oft du das abfragst, kann sich sogar eine materialisierte, berechnete Spalte dafür lohnen und 2-3µg CO₂ pro Query einsparen
Rolf
Willkommen im neuen Jahr!
je nach dem, wie oft du das abfragst, kann sich sogar eine materialisierte, berechnete Spalte dafür lohnen und 2-3µg CO₂ pro Query einsparen
Nun ja ... ich selbst bin ja eher ein Freund des „Hardcore-Cachings“. Da scheinbar (siehe SQL-Abfrage ohne WHERE-Klausel) die gesamte Datentabelle ausgeliefert wird, bietet es sich ohnehin an, das auszuliefernde HTML sogar schon gepackt bereit zu halten. Man lösche einfach die gespeicherte Cache-Datei sobald in der Datentabelle Änderungen gemacht wurden und erzeuge diese Datei also beim nächsten Abruf neu - wenn und nur falls kein Cache vorhanden ist.