pear/console_table
PEAR Console_Table is a PHP library for rendering clean, aligned text tables in terminal and console output. It supports headers, rows, column alignment, padding, borders, auto-sizing, and flexible formatting, making CLI reports and command-line data displays easy to build.
pear/console_table is a PEAR-era, single-purpose table renderer: you feed it headers and rows, it hands back a monospace string. It's archived, so treat it as legacy-in-waiting rather than a new dependency.
Install (Composer mirrors the PEAR channel, so no pear install needed):
composer require pear/console_table
If the class isn't autoloadable in your setup (PEAR packages have historically used include-path or classmap autoloading), fall back to require_once 'Console/Table.php'; — but check vendor/pear/console_table/composer.json first so you don't fight your own autoloader later.
Where to look first: the class file itself. The surface you'll actually touch is tiny — setHeaders(), addRow(), setAlign(), setWidth(), setPadding(), addFilter(), getTable(), plus Console_Table::fromArray() for a one-liner. Read those eight methods and you know the package.
First use case — a report in an Artisan command:
use Console_Table;
$table = new Console_Table();
$table->setHeaders(['ID', 'Customer', 'Total']);
$table->setAlign(2, CONSOLE_TABLE_ALIGN_RIGHT);
foreach ($orders as $order) {
$table->addRow([$order->id, $order->customer->name, number_format($order->total, 2)]);
}
$this->output->write($table->getTable());
Be honest with yourself about why you're here: Laravel already ships $this->table() (Symfony Console's Table) via InteractsWithIO. Reach for Console_Table when you're maintaining an existing codebase that already uses it, or when you specifically want its column-filter callback model. For greenfield code, Symfony's Table is the better default.
Wrap it, don't sprinkle it. Because this package is archived, isolate it behind a small contract so a future swap is a one-file change:
interface TableRenderer
{
public function render(array $headers, iterable $rows): string;
}
final class ConsoleTableRenderer implements TableRenderer { /* Console_Table here */ }
Bind it in a service provider; inject into commands and services. When you eventually migrate to Symfony\Component\Console\Helper\Table, nothing above the interface changes.
Use fromArray() for static output — help text, config dumps, diagnostics:
echo Console_Table::fromArray(
['Key', 'Value'],
[['driver', config('database.default')], ['env', app()->environment()]]
);
Column filters are the genuinely nice feature. Instead of formatting in your loop, register a callback per column:
$table->addFilter('trim', 1);
$table->addFilter('number_format', 2, 2); // column 2, two decimals
$table->addFilter('strtoupper', 0);
This keeps row assembly dumb (just raw data) and puts presentation in one place — handy when several commands produce similar tables.
Integrate with Artisan output carefully. Prefer $this->output->write($table->getTable()) over $this->line(...), since getTable() already terminates each row with \n; line() adds another and you get a trailing blank line.
Color: Console_Table_Color emits raw ANSI escapes. Only use it when $this->output->isDecorated() is true, otherwise you'll dump escape codes into CI logs and log files. In practice, most Laravel devs skip it and let Symfony's <info>/<comment> tags do the work — but don't mix the two in the same cell, because tag characters count toward column width.
Testing: Artisan::call('report:orders'); $output = Artisan::output(); then $this->assertStringContainsString('Customer', $output). Assert on substrings, not whole-table snapshots — alignment whitespace makes snapshots brittle across PHP versions.
strlen(). Bytes, not characters. Any accented name, CJK label, or emoji will misalign every column to its right. Pre-pad/normalize such values yourself, or restrict this package to ASCII-only output.<info> tag inside a row shifts the border. Color the whole line after getTable() if you must, or avoid inline markup entirely.CONSOLE_TABLE_ALIGN_RIGHT, CONSOLE_TABLE_FILTER_*, etc. are plain define()s — referencing one before the class file loads is a fatal error, not a warning. Always instantiate (or fromArray) before touching them.addRow() vs. addCol() ordering matters. addCol() appends a column to already-added rows; call it before you start adding data or you'll get a table where early rows have fewer cells than later ones.getTable(). Don't echo it inside a heredoc or you'll get inconsistent blank lines depending on your output driver.setAlign($col, ...)); if you need one cell bold you're post-processing the string, which is usually the signal to switch to Symfony's Table.Console_Table to override rendering is the only realistic hook, and it ties you to protected internals that will never be documented or fixed. Prefer the wrapper/adapter approach above.$table->getTable() with var_export() to see literal whitespace, not a pretty-printed terminal version — that's how you catch off-by-one column widths.Table (already a dependency) covers headers, alignment, column max-width, row separators, and styling, and it handles multibyte width correctly. Keep the TableRenderer abstraction and swap the implementation behind it.How can I help you explore Laravel packages today?