Abusive use of long database query?
You are on the right track about trying to reduce trips to the database. I think the rule of thumb would be: whatever gives the best overall performance ;-)

A single query will almost always outperform N queries. Sometimes you may have the choice between two single queries: one that's extremely complex but loads exactly the data you need, and another that's simple but loads more data than you need and you have to filter the result yourself in code. When the database is heavily loaded, the simple query can be faster.

That said, your final $query is not optimal. This would be better:

SELECT col1, col2 FROM shelf
LEFT JOIN (
    SELECT tray.shelf_id, SUM(egg.weight) AS total_weight FROM tray
    LEFT JOIN egg USING (tray_id)
    GROUP BY shelf_id
) AS weight USING (shelf_id)
WHERE shop_id = ?


Of course col1 and col2 are not real columns, I just wanted to emphasize that you should always write the column names explicitly. It's faster to load only what you really need. It also protects you from changes in the column order.

Also notice that I removed one sub-query, which should also make it faster.