PHPackages                             phpdot/console - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [CLI &amp; Console](/categories/cli)
4. /
5. phpdot/console

ActiveLibrary[CLI &amp; Console](/categories/cli)

phpdot/console
==============

Attribute-driven console command discovery on Symfony Console.

v0.1.1(1mo ago)052MITPHPPHP &gt;=8.5

Since Jul 18Pushed 1mo agoCompare

[ Source](https://github.com/phpdot/console)[ Packagist](https://packagist.org/packages/phpdot/console)[ RSS](/packages/phpdot-console/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (47)Versions (10)Used By (2)

phpdot/console
==============

[](#phpdotconsole)

CLI application framework wrapping symfony/console — DI integration, attribute-driven command discovery, and output helpers. Standalone.

Table of Contents
-----------------

[](#table-of-contents)

- [Requirements](#requirements)
- [Installation](#installation)
- [Usage](#usage)
- [Discovery](#discovery)
- [Architecture](#architecture)
- [Testing](#testing)
- [License](#license)

Requirements
------------

[](#requirements)

RequirementConstraintPHP`>= 8.5``symfony/console``^8.0``psr/container``^2.0``phpdot/attribute``^0.1``phpdot/container` is a dev-only suggestion — it exposes `#[Config('console')]` to a phpdot framework boot. Standalone consumers do not need it; the attribute is inert until reflected.

Installation
------------

[](#installation)

```
composer require phpdot/console
```

Usage
-----

[](#usage)

### Standalone

[](#standalone)

```
use PHPdot\Console\Application;
use PHPdot\Console\ConsoleConfig;

$app = new Application(new ConsoleConfig(name: 'MyApp', version: '1.0.0'));
$app->add(new GreetCommand());
$app->run();
```

### With discovery

[](#with-discovery)

```
use PHPdot\Console\Application;
use PHPdot\Console\ConsoleConfig;

$app = new Application(
    new ConsoleConfig(
        name: 'MyApp',
        version: '1.0.0',
        cachePath: __DIR__ . '/var/cache/commands.php',
    ),
);

$app->discover([__DIR__ . '/src/Command']);
$app->run();
```

`cachePath` makes `Application` build its own `CommandCache` automatically. Pass an explicit `CommandCache` instance via the third constructor argument when you need a custom one.

### With DI container

[](#with-di-container)

```
use PHPdot\Console\Application;
use PHPdot\Console\ConsoleConfig;

$container = /* any PSR-11 container */;

$app = new Application(
    config: new ConsoleConfig(
        name: 'MyApp',
        version: '1.0.0',
        cachePath: __DIR__ . '/var/cache/commands.php',
    ),
    container: $container,
);

$app->discover([__DIR__ . '/src/Command']);
$app->run();
```

### Auto-binding via phpdot/config

[](#auto-binding-via-phpdotconfig)

`ConsoleConfig` carries `#[Config('console')]`, so `phpdot/config` hydrates it from `config/console.php`:

```
// config/console.php
return [
    'name'      => 'MyApp',
    'version'   => '1.0.0',
    'cachePath' => __DIR__ . '/../var/cache/commands.php',
];
```

A future console provider will resolve the DTO from `Configuration::dto()` and inject it into `Application` automatically. Until then, construct the DTO yourself.

### Modifying discovered commands

[](#modifying-discovered-commands)

Apps frequently want to alias, rename, or relabel commands shipped by other packages — for shortcuts, brand consistency, or collision resolution. Three methods on `Application`:

```
$app->discover([__DIR__ . '/vendor/phpdot']);

// Add an alternate name. Both `container:list` and `c:l` work.
$app->alias('container:list', 'c:l');

// Replace the canonical name. The old name no longer resolves.
$app->rename('legacy:run', 'run');

// Change description / help text without touching the name.
$app->override('container:list', description: 'Show every entry in the live container');
```

Rules:

- `alias()` is additive — never breaks the original name. Throws if the new name is already taken by a different command.
- `rename()` replaces the name. Throws if the new name is already taken.
- `override()` mutates non-name metadata only (description, help). Use `rename()` for the name.
- All three are chainable.

### Defining commands

[](#defining-commands)

```
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use PHPdot\Console\Command;

#[AsCommand(name: 'users:import', description: 'Import users from CSV')]
final class ImportUsersCommand extends Command
{
    public function __construct(
        private readonly UserRepository $users,
    ) {
        parent::__construct();
    }

    protected function configure(): void
    {
        $this->addArgument('file', InputArgument::REQUIRED, 'CSV file path');
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $file = $input->getArgument('file');
        $rows = $this->parser->parse($file);

        $this->info($output, "Importing from {$file}...");

        $this->withProgress($output, $rows, function (array $row) {
            $this->users->create($row);
        });

        $this->success($output, 'Import complete.');
        return self::SUCCESS;
    }
}
```

### Output helpers

[](#output-helpers)

```
$this->info($output, 'Processing...');
$this->error($output, 'Something failed');
$this->success($output, 'Done');
$this->warning($output, 'Careful');
$this->comment($output, 'Note');
```

### Table

[](#table)

```
$this->table($output, [
    ['name' => 'Alice', 'email' => 'alice@example.com'],
    ['name' => 'Bob', 'email' => 'bob@example.com'],
]);
// Headers auto-detected from first row keys
```

### Progress

[](#progress)

```
$this->withProgress($output, $items, function (mixed $item) {
    // process each item
});
```

### Interactive input

[](#interactive-input)

```
$name = $this->ask($input, $output, 'What is your name?');
$confirmed = $this->confirm($input, $output, 'Continue?', true);
$color = $this->choice($input, $output, 'Pick a color', ['red', 'blue', 'green']);
$password = $this->secret($input, $output, 'Enter password');
```

### Programmatic execution

[](#programmatic-execution)

```
$exitCode = $app->call('cache:clear');
$exitCode = $app->call('migrate', ['--force' => true]);
```

Discovery
---------

[](#discovery)

`CommandDiscovery` scans directories for classes with `#[AsCommand]` that extend `Symfony\Component\Console\Command\Command`. Class discovery is delegated to [`phpdot/attribute`](https://github.com/phpdot/attribute), which handles tokenization, namespace resolution, and attribute reading.

Skips: interfaces, traits, enums, abstract classes, classes without `#[AsCommand]`, and classes that don't extend Symfony's `Command`.

### Cache format

[](#cache-format)

```
// var/cache/commands.php
return [
    'cache:clear' => 'App\\Command\\CacheClearCommand',
    'users:import' => 'App\\Command\\ImportUsersCommand',
];
```

Architecture
------------

[](#architecture)

 ```
graph TD
    APP[Application] -->|wraps| SA[Symfony Application]
    APP -->|discover| CD[CommandDiscovery]
    APP -->|read/write| CC[CommandCache]
    APP -->|wires| CCL[ContainerCommandLoader]

    CD -->|phpdot/attribute Scanner| FILES[".php files + #[AsCommand]"]
    CD -->|produces| MAP["Command Mapname → class"]
    CC -->|caches| MAP

    CCL -->|implements| CLI[CommandLoaderInterface]
    CCL -->|resolves via| PSR[PSR-11 Container]
    CCL -->|uses| MAP

    SA -->|runs| CMD[Command instances]
    CMD -->|extends| BASE[PHPdot Command]
    BASE -->|extends| SC[Symfony Command]

    style APP fill:#2d3748,color:#fff
    style BASE fill:#2d3748,color:#fff
    style CCL fill:#4a5568,color:#fff
    style CD fill:#4a5568,color:#fff
    style CC fill:#4a5568,color:#fff
    style SA fill:#718096,color:#fff
    style PSR fill:#718096,color:#fff
    style SC fill:#718096,color:#fff
    style MAP fill:#718096,color:#fff
    style FILES fill:#718096,color:#fff
    style CLI fill:#718096,color:#fff
    style CMD fill:#718096,color:#fff
```

      Loading Testing
-------

[](#testing)

The package is standalone-testable:

```
composer install
composer test        # PHPUnit
composer analyse     # PHPStan, level max + strict rules
composer cs-check    # PHP-CS-Fixer
composer check       # All three
```

License
-------

[](#license)

MIT.

**This repository is a read-only mirror**, generated by CI from [phpdot/monorepo](https://github.com/phpdot/monorepo). [Pull requests](https://github.com/phpdot/monorepo/pulls)and [issues](https://github.com/phpdot/monorepo/issues) belong in the monorepo.

###  Health Score

41

—

FairBetter than 87% of packages

Maintenance94

Actively maintained with recent releases

Popularity5

Limited adoption so far

Community13

Small or concentrated contributor base

Maturity47

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 81.8% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~13 days

Recently: every ~5 days

Total

9

Last Release

33d ago

Major Versions

v1.0.0 → v2.0.02026-04-27

PHP version history (3 changes)v1.0.0PHP &gt;=8.3

v2.2.1PHP &gt;=8.4

v0.1.0PHP &gt;=8.5

### Community

Maintainers

![](https://www.gravatar.com/avatar/62e82421bda4b5d6ba9a47ba6d88caca060dcd0d1a2862f351f3a97657385db0?d=identicon)[phpdot](/maintainers/phpdot)

---

Top Contributors

[![phpdot](https://avatars.githubusercontent.com/u/252500?v=4)](https://github.com/phpdot "phpdot (9 commits)")[![o3AM](https://avatars.githubusercontent.com/u/252500?v=4)](https://github.com/o3AM "o3AM (2 commits)")

---

Tags

cliconsolecommandattributesymfony-console

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/phpdot-console/health.svg)

```
[![Health](https://phpackages.com/badges/phpdot-console/health.svg)](https://phpackages.com/packages/phpdot-console)
```

###  Alternatives

[laravel/framework

The Laravel Framework.

34.9k556.2M21.5k](/packages/laravel-framework)[buggregator/trap

A simple and powerful tool for debugging PHP applications.

2742.3M74](/packages/buggregator-trap)[kimai/kimai

Kimai - Time Tracking

4.8k9.4k1](/packages/kimai-kimai)[drupal/core-recommended

Locked core dependencies; require this project INSTEAD OF drupal/core.

6943.5M449](/packages/drupal-core-recommended)[helhum/typo3-console

A reliable and powerful command line interface for TYPO3 CMS

2949.6M274](/packages/helhum-typo3-console)[laminas/laminas-cli

Command-line interface for Laminas projects

564.3M77](/packages/laminas-laminas-cli)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
