Сколько бесполезных манипуляций.
public static function getProductsList()
{
$query = "select p.id, ...";
return Db::getConnection()->query($query);
}
И mysqli и PDO для объекта результата давным давно предоставляют traversable. А плоский массив при необходимости многократно обходить результат получается элементарным fetchAll() без этой простыни.
<?php foreach ($productsList as $product): ?>
<tr>
<td><?=$product['id']; ?></td>
</tr>
<?php endforeach; ?>
Если бы вы действительно делали var_dump, то уже давно бы заметили, что алиас таблицы ни PDO ни mysqli в результат не предоставляют. Только имена самих полей или алиасы этих полей.
Ну, это если считать, что PDO::ATTR_DEFAULT_FETCH_MODE у вас установлен в PDO::FETCH_ASSOC или хотя бы в дурацкий дефолтный PDO::FETCH_BOTH.
В любом случае у вас выключено отображение ошибок. Переключите error_reporting в нормальный девелоперский E_ALL.