php - How to prevent a trailing comma while printing comma-delimited data in a loop?

I'm writing a php code which is supposed to echo some DB data as a group of arrays separated by commas.

The code looks like this:

include('inc_db.php');  
$query = "SELECT * FROM product WHERE p_shop_id=1";
$result = $conn->query($query);
if ($result->num_rows > 0) {
    while($row = $result->fetch_array()) {
        if($result->num_rows == 1)
            echo "[" .$row['p_description'] ."," .$row['p_category'] ."," .$row['p_cost'] ."," .$row['p_stock'] ."]";
        else
            echo "[" .$row['p_description'] ."," .$row['p_category'] ."," .$row['p_cost'] ."," .$row['p_stock'] ."], ";
    }
}
$conn->close();

*the include line is the connection to the DB.

On this line:

if($result->num_rows == 1)

I'm trying to detect whether the loop got to the last row of the result, so the echo line would end without a comma (as happens on the 'else' phrase).

I guess I did the 'if' statement wrong, because when I'm running the program I'm getting the array with a comma at the end of every row including the last one.

the result is:

[Eggs, Food, 20, 20], [Coca Cola, Drinks, 5, 30],

The expected result is:

 [Eggs, Food, 20, 20], [Coca Cola, Drinks, 5, 30]

(without a comma at the end)

So what is the proper way to detect that the while loop got to the last row?

Answer

Solution:

You don't need to count the rows. You don't need to know if you are processing the final row either.

I don't really understand why you need this format, but you can use implode() and wrap in square braces to concisely store row data. Then when the loop is finished, you can just implode again with commas -- this ensures that there will be no mess to mop up.

This snippet converts the array of arrays to an array of brace-wrapped, comma-delimited strings, then after the loop, the array is converted to a comma-delimited string. (Demo)

$result = $conn->query("SELECT p_description, p_category, p_cost, p_stock FROM product WHERE p_shop_id = 1");
$rows = [];
foreach ($result as $row) {
    $rows[] = '[' . implode(', ', $row) . ']';
}
echo implode(', ', $rows);

Or you can prepend 0 or 1 comma before each braced string: (Conditional Demo) (Functional Demo)

foreach ($result as $i => $row) {
    echo ($i ? ', ' : '') . '[' . implode(', ', $row) . ']';
    //echo str_repeat(', ', (bool)$i) . '[' . implode(', ', $row) . ']';
}

Or if you prefer functional iterators, you can omit the temporary variable $rows and just use array_map(): (Demo)

echo implode(', ', array_map(function($row) {
    return '[' . implode(', ', $row) . ']'; 
}, $result));

Or you could use array_reduce() and check if the there is any data written to the $carry variable as you iterate the rows. The notion is to only prepend a comma if you are not dealing with the first iteration. (Demo)

echo array_reduce($result, function($carry, $row) {
    $carry .= (!$carry ? '' : ', ') . '[' . implode(', ', $row) . ']'; 
    return $carry;
});

Answer

Solution:

You can declare a variable which you'll increment in your loop and use it to check against $result->num_rows to see if it's the last record.

if ($result->num_rows > 0) {
    $index = 0;
    while($row = $result->fetch_array()) {
            if($result->num_rows == ($index+1)) //Check if it's the last record
                echo "[" .$row['p_description'] ."," .$row['p_category'] ."," .$row['p_cost'] ."," .$row['p_stock'] ."]";
            else
                echo "[" .$row['p_description'] ."," .$row['p_category'] ."," .$row['p_cost'] ."," .$row['p_stock'] ."], ";

          $index++;
            
        }
}

Source