跳转到主要内容

什么是 Artisan

Artisan 是 Laravel 内置的命令行接口(CLI)工具。 它以项目根目录下的 artisan 脚本形式存在,提供了大量提升开发和运维效率的命令。 要查看可用命令列表,请使用 list
php artisan list
若想查看命令用法,前面加 help 即可。
php artisan help migrate
使用 Laravel Sail 时,请以 sail artisan 取代 php artisan 执行。 命令会在 Docker 容器内运行。
./vendor/bin/sail artisan list

Tinker

Laravel Tinker 是一个 REPL 环境,能在命令行中交互式操作整个应用,包括 Eloquent 模型、Job、事件等。
php artisan tinker
启动后可以直接执行 PHP 代码。
// 查看用户
>>> App\Models\User::find(1)
// 通过工厂创建记录
>>> App\Models\User::factory()->create()
// 直接调用服务类
>>> app(App\Services\OrderService::class)->process(1)
Tinker 会实际修改数据。在生产环境执行时请务必谨慎。 它适合用于本地或 staging 环境的功能确认和调试。

创建自定义命令

生成命令

使用 make:command 生成命令类的骨架。
php artisan make:command ImportProducts
会生成 app/Console/Commands/ImportProducts.php

命令的基本结构

生成的命令类包含 $signature$descriptionhandle() 三个主要要素。
<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;

class ImportProducts extends Command
{
    /**
     * 命令名与参数/选项定义
     */
    protected $signature = 'import:products';

    /**
     * 命令说明(会显示在 php artisan list 中)
     */
    protected $description = '从 CSV 导入商品数据';

    /**
     * 命令的执行体
     */
    public function handle(): void
    {
        $this->info('开始导入...');
        // 编写处理逻辑
        $this->info('完成。');
    }
}
Laravel 13 也支持使用 PHP 属性来书写。
use Illuminate\Console\Attributes\Description;
use Illuminate\Console\Attributes\Signature;

#[Signature('import:products')]
#[Description('从 CSV 导入商品数据')]
class ImportProducts extends Command
{
    public function handle(): void
    {
        // ...
    }
}

定义参数与选项

$signature 中可以一并定义命令名、参数与选项。
protected $signature = 'import:products
                        {file : 要导入的 CSV 文件路径}
                        {--limit= : 要导入的最大条数}
                        {--dry-run : 不真正写入数据库(仅确认)}';
语法类别说明
{file}必需参数缺省会报错
{file?}可选参数缺省时为 null
{file=products.csv}带默认值的参数缺省时使用默认值
{--queue}布尔选项指定为 true,未指定为 false
{--limit=}带值的选项通过 --limit=100 传值
{--limit=50}带默认值的选项缺省时为 50
{--Q|queue}带简写的选项也可用 -Q

读取参数与选项

handle() 中通过 argument()option() 获取值。
public function handle(): void
{
    $file    = $this->argument('file');       // 获取参数
    $limit   = $this->option('limit');        // 获取选项
    $dryRun  = $this->option('dry-run');      // 布尔选项

    $this->info("文件:{$file}");

    if ($dryRun) {
        $this->warn('干运行模式:跳过写入数据库');
    }
}

input() — 类型化访问器

使用 input() 方法可以像 HTTP 请求那样通过类型化访问器读取命令参数或选项。
use App\Enums\ReportType;

public function handle(): void
{
    // 以 CommandInput 实例获取参数/选项
    $from = $this->input()->date('from');
    $type = $this->input()->enum('type', ReportType::class);
    $limit = $this->input()->integer('limit');
}
要按名称直接取值可传入名字(会同时在参数与选项中查找)。
$queue = $this->input('queue', 'default');
argument() / option() 返回字符串,而 input() 的类型化访问器会转换为合适的类型。适合需要类型安全的日期、数字、Enum 等场景。

与用户交互

输出消息

有专门的方法用于向控制台输出带颜色的文本。
$this->info('处理正常完成');    // 绿色
$this->warn('该操作不可撤销');    // 黄色
$this->error('发生错误');       // 红色
$this->line('普通文本');             // 无颜色
$this->comment('补充信息');               // 浅灰色

询问用户

可以从用户交互式接收输入。
// 文本输入
$name = $this->ask('请输入负责人姓名');

// 带默认值
$env = $this->ask('选择运行环境', 'production');

// 密码等敏感信息(不会在屏幕上显示)
$password = $this->secret('请输入 API 密钥');

// Yes / No 确认
if (! $this->confirm('确认导入到生产数据库?')) {
    $this->info('已取消。');
    return;
}

// 从选项中选择
$format = $this->choice('请选择输出格式', ['csv', 'json', 'xml'], 0);

进度条

在处理大量数据时可以直观展示进度。
use App\Models\Product;

// 传入集合即自动显示进度条
$this->withProgressBar(Product::cursor(), function (Product $product) {
    $this->processProduct($product);
});
若想手动细致控制,可使用如下方式:
$total = Product::count();
$bar = $this->output->createProgressBar($total);
$bar->start();

Product::cursor()->each(function (Product $product) use ($bar) {
    $this->processProduct($product);
    $bar->advance();
});

$bar->finish();
$this->newLine();

实用场景

数据导入命令

以下是一个从 CSV 导入商品数据的实用命令示例。
1

生成命令

php artisan make:command ImportProducts
2

实现命令

<?php

namespace App\Console\Commands;

use App\Models\Product;
use Illuminate\Console\Command;

class ImportProducts extends Command
{
    protected $signature = 'import:products
                            {file : CSV 文件路径}
                            {--limit= : 最大导入条数}
                            {--dry-run : 仅确认(不写入数据库)}';

    protected $description = '从 CSV 文件导入商品数据';

    public function handle(): void
    {
        $filePath = $this->argument('file');
        $limit    = $this->option('limit') ? (int) $this->option('limit') : null;
        $dryRun   = $this->option('dry-run');

        if (! file_exists($filePath)) {
            $this->error("找不到文件:{$filePath}");
            return;
        }

        // 使用 PHP 内置函数读取 CSV
        $handle = fopen($filePath, 'r');
        $headers = fgetcsv($handle); // 第一行为表头
        $rows = [];
        while (($row = fgetcsv($handle)) !== false) {
            $rows[] = array_combine($headers, $row);
            if ($limit !== null && count($rows) >= $limit) {
                break;
            }
        }
        fclose($handle);

        $count = 0;

        $this->withProgressBar($rows, function (array $row) use ($dryRun, &$count) {
            if (! $dryRun) {
                Product::updateOrCreate(
                    ['sku' => $row['sku']],
                    [
                        'name'  => $row['name'],
                        'price' => $row['price'],
                    ]
                );
            }
            $count++;
        });

        $this->newLine();

        if ($dryRun) {
            $this->warn("共 {$count} 条(干运行:已跳过保存)");
        } else {
            $this->info("已导入 {$count} 条。");
        }
    }
}
3

运行命令

# 常规导入
php artisan import:products storage/products.csv

# 限制条数
php artisan import:products storage/products.csv --limit=100

# 干运行确认
php artisan import:products storage/products.csv --dry-run

定期维护命令

以下是一个定期删除过期数据的维护命令示例。
<?php

namespace App\Console\Commands;

use App\Models\Order;
use Illuminate\Console\Command;

class PruneOldOrders extends Command
{
    protected $signature = 'orders:prune {--days=90 : 删除多少天前的数据}';

    protected $description = '删除超过指定天数的已完成订单';

    public function handle(): void
    {
        $days = (int) $this->option('days');

        if (! $this->confirm("确认删除 {$days} 天以上的已完成订单吗?")) {
            $this->info('已取消。');
            return;
        }

        $deleted = Order::where('status', 'completed')
            ->where('created_at', '<', now()->subDays($days))
            ->delete();

        $this->info("已删除 {$deleted} 条订单。");
    }
}

结合调度执行

创建的命令可以在 routes/console.php 中安排调度执行。 详见任务调度
use Illuminate\Support\Facades\Schedule;

// 每天凌晨 2 点执行
Schedule::command('orders:prune --days=90')->dailyAt('2:00');

// 每周一 9 点执行
Schedule::command('import:products storage/weekly.csv')->weeklyOn(1, '9:00');

命令测试

可以使用 Laravel 的测试功能来验证 Artisan 命令。
<?php

namespace Tests\Feature\Commands;

use App\Models\Order;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class PruneOldOrdersTest extends TestCase
{
    use RefreshDatabase;

    public function test_it_deletes_old_completed_orders(): void
    {
        // 创建 90 天前的已完成订单
        Order::factory()->create([
            'status'     => 'completed',
            'created_at' => now()->subDays(100),
        ]);

        // 近期已完成订单(不应被删除)
        Order::factory()->create([
            'status'     => 'completed',
            'created_at' => now()->subDays(10),
        ]);

        $this->artisan('orders:prune', ['--days' => 90])
            ->expectsConfirmation('确认删除 90 天以上的已完成订单吗?', 'yes')
            ->expectsOutput('已删除 1 条订单。')
            ->assertExitCode(0);

        $this->assertDatabaseCount('orders', 1);
    }

    public function test_it_cancels_when_user_declines(): void
    {
        Order::factory()->create(['status' => 'completed', 'created_at' => now()->subDays(100)]);

        $this->artisan('orders:prune', ['--days' => 90])
            ->expectsConfirmation('确认删除 90 天以上的已完成订单吗?', 'no')
            ->expectsOutput('已取消。')
            ->assertExitCode(0);

        $this->assertDatabaseCount('orders', 1);
    }
}
artisan() 可用的断言方法示例:
方法说明
expectsOutput('...')校验指定文本是否被输出
expectsQuestion('?', '答案')模拟 ask() 输入
expectsConfirmation('?', 'yes')模拟 confirm() 应答
expectsChoice('?', '选项')模拟 choice() 选择
assertExitCode(0)校验退出码(0 = 成功)
assertFailed()校验退出码不为 0

常用命令汇总

# 新建命令
php artisan make:command CommandName

# 可用命令列表
php artisan list

# 查看命令用法
php artisan help command:name

# 启动 Tinker
php artisan tinker
最后修改于 2026年7月13日