Skip to content

Arguments and Options

Understanding how to handle command arguments and options is crucial for building flexible CLI applications with Yalla.

Arguments

Arguments are positional parameters passed to your command. They are processed in the order they are defined.

Defining Arguments

php
public function __construct()
{
    $this->name = 'process';
    $this->description = 'Process a file';

    // Required argument
    $this->addArgument('input', 'Input file path', true);

    // Optional argument with default value
    $this->addArgument('output', 'Output file path', false);
}

Accessing Arguments

php
public function execute(array $input, Output $output): int
{
    // Get required argument
    $inputFile = $this->getArgument($input, 'input');

    // Get optional argument with default value
    $outputFile = $this->getArgument($input, 'output', 'output.txt');

    // Process the files...
    return 0;
}

Usage Examples

bash
# With required argument only
./cli process input.txt

# With both arguments
./cli process input.txt output.json

Options

Options are named parameters that can be passed in any order using flags.

Defining Options

php
public function __construct()
{
    $this->name = 'deploy';
    $this->description = 'Deploy application';

    // Boolean option (flag)
    $this->addOption('force', 'f', 'Force deployment', false);

    // Option with value
    $this->addOption('env', 'e', 'Target environment', 'production');

    // Option without shortcut
    $this->addOption('dry-run', null, 'Simulate deployment', false);
}

Option Types

Boolean Options (Flags)

php
// Definition
$this->addOption('verbose', 'v', 'Enable verbose output', false);

// Usage
./cli deploy --verbose
./cli deploy -v

// In code
$verbose = $this->getOption($input, 'verbose', false);
if ($verbose) {
    $output->info('Verbose mode enabled');
}

Value Options

php
// Definition
$this->addOption('timeout', 't', 'Timeout in seconds', 30);

// Usage
./cli deploy --timeout=60
./cli deploy --timeout 60
./cli deploy -t 60

// In code
$timeout = $this->getOption($input, 'timeout', 30);

Multiple Short Options

bash
# These are equivalent
./cli deploy -f -v -d
./cli deploy -fvd

Long vs Short Options

php
// Define both long and short versions
$this->addOption('help', 'h', 'Show help', false);
$this->addOption('version', 'V', 'Show version', false);
$this->addOption('quiet', 'q', 'Suppress output', false);

Usage:

bash
# Long format
./cli deploy --help --version --quiet

# Short format
./cli deploy -h -V -q

# Mixed
./cli deploy --help -Vq

Advanced Patterns

Variadic Arguments

For commands that accept multiple values:

php
public function execute(array $input, Output $output): int
{
    // All arguments after the first are treated as files
    $command = $this->getArgument($input, 0);
    $files = array_slice($input['arguments'], 1);

    foreach ($files as $file) {
        $output->info("Processing: $file");
    }

    return 0;
}

Usage:

bash
./cli process file1.txt file2.txt file3.txt

Option Arrays

For options that can be specified multiple times:

php
public function execute(array $input, Output $output): int
{
    // Parse multiple --tag options
    $tags = [];
    foreach ($input['options'] as $key => $value) {
        if (str_starts_with($key, 'tag')) {
            $tags[] = $value;
        }
    }

    return 0;
}

Usage:

bash
./cli deploy --tag=v1.0 --tag=production --tag=stable

Validation

Required Arguments

php
public function execute(array $input, Output $output): int
{
    $file = $this->getArgument($input, 'file');

    if (empty($file)) {
        $output->error('Error: File argument is required');
        return 1;
    }

    if (!file_exists($file)) {
        $output->error("Error: File '$file' does not exist");
        return 1;
    }

    // Continue processing...
    return 0;
}

Option Validation

php
public function execute(array $input, Output $output): int
{
    $format = $this->getOption($input, 'format', 'json');
    $validFormats = ['json', 'xml', 'csv', 'yaml'];

    if (!in_array($format, $validFormats)) {
        $output->error("Invalid format: $format");
        $output->info("Valid formats: " . implode(', ', $validFormats));
        return 1;
    }

    $timeout = $this->getOption($input, 'timeout', 30);
    if (!is_numeric($timeout) || $timeout < 0) {
        $output->error('Timeout must be a positive number');
        return 1;
    }

    // Continue processing...
    return 0;
}

Input Structure

The input array passed to execute() has this structure:

php
[
    'command' => 'deploy',
    'arguments' => [
        'production',
        'v1.2.3'
    ],
    'options' => [
        'force' => true,
        'f' => true,  // Shortcut also included
        'env' => 'staging',
        'e' => 'staging'  // Shortcut also included
    ]
]

Best Practices

1. Clear Naming

Use descriptive names for arguments and options:

php
// Good
$this->addArgument('source-file', 'Path to source file', true);
$this->addOption('output-format', 'o', 'Output format (json|xml|csv)', 'json');

// Poor
$this->addArgument('src', 'Source', true);
$this->addOption('fmt', 'f', 'Format', 'json');

2. Provide Defaults

Always provide sensible defaults for optional parameters:

php
$this->addArgument('port', 'Server port', false);

// In execute()
$port = $this->getArgument($input, 'port', 8080);  // Default to 8080
php
// Database options
$this->addOption('db-host', null, 'Database host', 'localhost');
$this->addOption('db-port', null, 'Database port', 3306);
$this->addOption('db-name', null, 'Database name', null);
$this->addOption('db-user', null, 'Database user', 'root');

4. Use Shortcuts Wisely

Reserve single letters for commonly used options:

php
$this->addOption('verbose', 'v', 'Verbose output', false);
$this->addOption('quiet', 'q', 'Quiet mode', false);
$this->addOption('force', 'f', 'Force operation', false);
$this->addOption('help', 'h', 'Show help', false);

5. Document Everything

Always provide clear descriptions:

php
$this->addArgument(
    'config-file',
    'Path to configuration file (JSON or YAML format)',
    true
);

$this->addOption(
    'dry-run',
    null,
    'Run in simulation mode without making actual changes',
    false
);

Complex Example

Here's a complete example showing various argument and option patterns:

php
<?php

use Yalla\Commands\Command;
use Yalla\Output\Output;

class BackupCommand extends Command
{
    public function __construct()
    {
        $this->name = 'backup';
        $this->description = 'Backup database and files';

        // Arguments
        $this->addArgument('source', 'Source directory or database', true);
        $this->addArgument('destination', 'Backup destination', false);

        // Options
        $this->addOption('type', 't', 'Backup type (full|incremental|differential)', 'full');
        $this->addOption('compress', 'c', 'Compression level (0-9)', 5);
        $this->addOption('encrypt', 'e', 'Encrypt backup', false);
        $this->addOption('exclude', 'x', 'Patterns to exclude', null);
        $this->addOption('dry-run', null, 'Simulate backup', false);
        $this->addOption('verbose', 'v', 'Verbose output', false);
        $this->addOption('quiet', 'q', 'Suppress output', false);
    }

    public function execute(array $input, Output $output): int
    {
        // Get arguments
        $source = $this->getArgument($input, 'source');
        $destination = $this->getArgument($input, 'destination', './backups/' . date('Y-m-d'));

        // Get options
        $type = $this->getOption($input, 'type', 'full');
        $compress = (int) $this->getOption($input, 'compress', 5);
        $encrypt = $this->getOption($input, 'encrypt', false);
        $exclude = $this->getOption($input, 'exclude');
        $dryRun = $this->getOption($input, 'dry-run', false);
        $verbose = $this->getOption($input, 'verbose', false);
        $quiet = $this->getOption($input, 'quiet', false);

        // Validate
        if (!in_array($type, ['full', 'incremental', 'differential'])) {
            $output->error("Invalid backup type: $type");
            return 1;
        }

        if ($compress < 0 || $compress > 9) {
            $output->error('Compression level must be between 0 and 9');
            return 1;
        }

        // Execute backup
        if (!$quiet) {
            $output->info("Starting $type backup...");
            $output->writeln("Source: $source");
            $output->writeln("Destination: $destination");
        }

        if ($verbose) {
            $output->section('Configuration');
            $output->writeln("Type: $type");
            $output->writeln("Compression: $compress");
            $output->writeln("Encryption: " . ($encrypt ? 'Yes' : 'No'));
            $output->writeln("Exclude: " . ($exclude ?: 'None'));
        }

        if ($dryRun) {
            $output->warning('DRY RUN - No actual changes will be made');
        }

        // Perform backup...
        if (!$quiet) {
            $output->success('Backup completed successfully!');
        }

        return 0;
    }
}

Usage examples:

bash
# Simple backup
./cli backup /var/www

# Full featured
./cli backup /var/www /backups/web --type=incremental --compress=9 --encrypt -v

# Dry run with exclusions
./cli backup /home/user --exclude="*.tmp" --exclude="cache/*" --dry-run

Released under the MIT License.