Laatste regel afsluiten!
En hoe kan ik dat toepassen die $output?
Code (php)
$i is in het begin altijd minder dan num_rows.
Je kunt ook 1 van de gegeven oplossingen toepassen.
Gewijzigd op 03/01/2023 13:11:00 door Adoptive Solution
Wat is er mis met implode(), Kees?
Kees Mulder op 03/01/2023 12:32:26:
Ik heb nu deze code gemaakt maar en die werkt bij 2 of meer regels. Behalve als ik 1 regel heb dan zet hij er ook een , achter! Hoe los ik dat op?
Het makkelijkste is door de $i++ (regel 15) vóór het if-statement te plaatsen (regel 11, bijvoorbeeld). Dat lijkt me semantisch ook correcter.
Mijns inziens is implode() hiervoor de juiste benadering, zoals reeds genoemd door Adoptive Solution en Ariën.
Ozzie PHP op 06/01/2023 13:14:17:
Mijns inziens is implode() hiervoor de juiste benadering, zoals reeds genoemd door Adoptive Solution en Ariën.
Ik heb altijd geleerd dat er niet zoiets als "de juiste benadering" bestaat. Er zijn altijd redenen waarom een andere benadering wellicht beter is. Het nadeel van implode() is dat je de resultset in een array moet hebben; je moet dus eerst de gehele resultset verwerken voor je output kunt genereren. Is geen optie als je bijvoorbeeld tussenresultaten wilt laten zien.
Als je het mij persoonlijk zou vragen, zou ik zeggen dat het de juiste benadering zou zijn om geen PHP te gebruiken, maar Perl; dat werkt veel efficiënter:
Code (php)
1
2
3
2
3
my $sql = 'SELECT * FROM vruchten';
my @results = $conn->selectrow_array($sql, { Slice => {} });
say @results ? join ',', map { $_->{fruit} } @results : 'geen resultaat';
my @results = $conn->selectrow_array($sql, { Slice => {} });
say @results ? join ',', map { $_->{fruit} } @results : 'geen resultaat';
Maar ja, aangezien dit een PHP-forum is, kun je dus ook bij deze code niet spreken van 'de juiste benadering'. :-)
Je gaat nu een complete telling bijhouden enkel om aan het eind een puntje te kunnen zetten. Stop de resultaten in een array, implode met een komma en voilà. En of je het nu in de while echoot, of direct eronder maakt natuurlijk niet uit.
En inderdaad is dit een php-forum, dus discussies over andere talen lijken me in dit verband niet relevant ;-)
Ozzie PHP op 06/01/2023 17:20:35:
Je gaat nu een complete telling bijhouden enkel om aan het eind een puntje te kunnen zetten.
Dat argument werkt twee kanten op: je gaat nu een complete array opbouwen, alleen om hem daarna te kunnen imploden. ;-) Resource-technisch is dat tellertje misschien zelfs een stuk goedkoper.
En wat betreft de "juiste benadering in de context": je kent alleen de context van die 15 regels code die hier zijn gepost, maar niet van het grotere geheel. Ik neem aan dat er nog meer code is dan dit, want anders zou je dat hele aan elkaar plakken net zo goed in SQL kunnen doen:
Code (php)
1
2
3
4
5
6
2
3
4
5
6
<?php
$sql = "SELECT GROUP_CONCAT(fruit SEPARATOR ', ') FROM vruchten";
$result = $conn->query($sql);
$row = $result->fetch_array();
echo $row[0];
?>
$sql = "SELECT GROUP_CONCAT(fruit SEPARATOR ', ') FROM vruchten";
$result = $conn->query($sql);
$row = $result->fetch_array();
echo $row[0];
?>
Afhankelijk van de rest van de code zou de oplossing met implode() inderdaad de beste kunnen zijn, maar wellicht spelen er andere afwegingen waardoor de oplossing met het tellertje beter is. Alleen de programmeur/topicstarter heeft het overzicht om te bepalen wat het beste/handigste is; wij kunnen hooguit wat oplossingsrichtingen en tips aanreiken.
De komma's zijn in principe opmaak en kunnen zelfs gewoon met CSS. Maar zoiets is denk ik vaak lastig, zo niet onmogelijk met een ORM. En dan is het voor velen verleidelijk om het wiel opnieuw uit te vinden. Zelfs met relatief inefficiënte code als implode().
Wie het per se in PHP wil doen kan het beter simpel en snel doen:
Code (php)
Voor wie het niet meteen ziet: de komma wordt als onderdeel gezien van het opvolgende getal, door de komma te printen voordat het getal wordt geprint. Bij het eerste getal is geen voorafgaande komma nodig dus kan die worden overgeslagen. Hiervoor is geen teller nodig, een boolean is genoeg.
Voor de lol met CSS:
Code (php)
1
2
3
4
5
2
3
4
5
<style>
span:not(:last-child)::after{content:", ";}
span:last-child::after{content:".";}
</style>
<p><span>1</span><span>2</span><span>3</span></p>
span:not(:last-child)::after{content:", ";}
span:last-child::after{content:".";}
</style>
<p><span>1</span><span>2</span><span>3</span></p>
Toch ben ik nog steeds van mening dat een implode efficiënter en zo niet duidelijker is qua code. In oplossingen met een teller of een if-else controle moet er bij iedere loop een teller meelopen of een controle plaatsvinden. Bij de constructie met implode is dit niet het geval.
Het enige nadeel dat je zou kunnen opwerpen tegen het gebruik van een array, is het geheugenverbruik. Maar voor enkel wat tekst lijkt me dat geen enkel beletsel en PHP gaat daar efficiënt mee om.
Maar goed ... ieder z'n eigen voorkeur uiteraard.
Als je het goed doet presenteer je ook niet heel veel fruit tegelijk op het scherm, anders raakt de gebruiker de kluts kwijt. Het aantal spans maakt dan niet zoveel uit voor een browser (gelijk het weinige geheugen voor slechts een paar items van implode), en je kunt content dan wel met CSS animeren. Het hangt af van de behoefte van de vragensteller.
Als je het over optimaliseren hebt kan mijn voorbeeldcode verder verbeterd. Het is in dit geval onzinnig om een if statement te plaatsen in een lus, omdat het altijd zo is dat er voor het eerste item geen komma komt. De code is in theorie nog sneller te maken:
Code (php)
Maar het hangt ook af van efficiëntie. Als efficiëntie niet betekent dat je programma zo snel mogelijk moet draaien, maar dat je zo snel mogelijk code kan typen die eenvoudig te begrijpen en te onderhouden is, dan kan je beter voor implode() gaan.
De vragensteller loopt hierbij wel het risico dat het programma meer resources kost wanneer de inhoud van de tabel toeneemt, omdat eerst alle gegevens in de tabel moeten worden verdubbeld van de database naar het werkgeheugen van PHP, voordat implode() het kan samenvoegen. Een string aggregatiefunctie van de database als GROUP_CONCAT() biedt uitkomst, en belast de database server met de gegevensverwerking via een soort "In-database processing".
Het hangt er inderdaad maar net van af waar je de code voor gebruikt.
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<!DOCTYPE html>
<html lang="nl-be">
<head>
<meta charset="utf-8">
<title>Test</title>
<style>
.bye > span:first-child::before {
content: "";
}
.bye > span::before {
content: ", ";
}
.bye > span:last-child::before {
content: " en ";
}
.bye > span:last-child::after {
content: ".";
}
</style>
</head>
<body>
<div class="bye">
<span>appel</span>
<span>peer</span>
<span>kers</span>
<span>druif</span>
<span>appel</span>
<span>peer</span>
<span>kers</span>
<span>druif</span>
</div>
</body>
</html>
<html lang="nl-be">
<head>
<meta charset="utf-8">
<title>Test</title>
<style>
.bye > span:first-child::before {
content: "";
}
.bye > span::before {
content: ", ";
}
.bye > span:last-child::before {
content: " en ";
}
.bye > span:last-child::after {
content: ".";
}
</style>
</head>
<body>
<div class="bye">
<span>appel</span>
<span>peer</span>
<span>kers</span>
<span>druif</span>
<span>appel</span>
<span>peer</span>
<span>kers</span>
<span>druif</span>
</div>
</body>
</html>
Gewijzigd op 08/01/2023 09:26:09 door Jan R
Dit lijkt meer op een lijstje en vanuit semantisch oogpunt lijkt een <ul> met de gewenste opmaak hier meer op z'n plaats dan een nietszeggende div met spans.
Code (php)
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
<ul class="comma-list">
<li>appel</li>
<li>peer</li>
<li>kers</li>
<li>druif</li>
<li>appel</li>
<li>peer</li>
<li>kers</li>
<li>druif</li>
</ul>
<li>appel</li>
<li>peer</li>
<li>kers</li>
<li>druif</li>
<li>appel</li>
<li>peer</li>
<li>kers</li>
<li>druif</li>
</ul>
Dezelfde css als in jouw voorbeeld kun je dan toepassen op een lijst met de class .comma-list. Op die manier klopt het semantisch ook.
De enige aanvulling die ik nog heb is om de CSS class niet direct aan .comma-list > li te binden.
Door dat consequent te doen krijg je geen opmaak mee van andere li tags, en is de CSS eenvoudiger te onderhouden.
Wat bedoel je precies ... voorbeeldje?
Vanwege het Cascading-karakter van CSS. Als je li als selector gebruikt, geldt dat meteen voor alle li's, en kan opmaak in elkaar over lopen door inheritance zonder dat je dat in de gaten hebt of wilt.
En vanwege de semantiek. Een li is semantisch wel een list item, maar je kunt dan beter een naam voor een class verzinnen die semantisch aangeeft waar het voor is, in plaats van wat het technisch is. Bijvoorbeeld .fruit {} in plaats van li {} .