提示
介绍
Laravel Prompts 是一个 PHP 包,用于为您的命令行应用程序添加美观且用户友好的表单,具有浏览器般的功能,包括占位符文本和验证。

Laravel Prompts 非常适合在您的 Artisan 控制台命令 中接受用户输入,但也可以在任何命令行 PHP 项目中使用。
Laravel Prompts 支持 macOS、Linux 和带有 WSL 的 Windows。有关更多信息,请参见我们关于 不支持的环境和回退 的文档。
安装
Laravel Prompts 已包含在最新版本的 Laravel 中。
您还可以通过使用 Composer 包管理器在其他 PHP 项目中安装 Laravel Prompts:
composer require laravel/prompts
可用提示
文本
text
函数将提示用户给定的问题,接受他们的输入,然后返回它:
use function Laravel\Prompts\text;
$name = text('你叫什么名字?');
您还可以包含占位符文本、默认值和信息提示:
$name = text(
label: '你叫什么名字?',
placeholder: '例如:Taylor Otwell',
default: $user?->name,
hint: '这将显示在您的个人资料上。'
);
必填值
如果您需要输入值,可以传递 required
参数:
$name = text(
label: '你叫什么名字?',
required: true
);
如果您想自定义验证消息,也可以传递一个字符串:
$name = text(
label: '你叫什么名字?',
required: '您的名字是必填的。'
);
额外验证
最后,如果您想执行额外的验证逻辑,可以将闭包传递给 validate
参数:
$name = text(
label: '你叫什么名字?',
validate: fn (string $value) => match (true) {
strlen($value) < 3 => '名字必须至少 3 个字符。',
strlen($value) > 255 => '名字不得超过 255 个字符。',
default => null
}
);
闭包将接收输入的值,并可以返回错误消息,或者如果验证通过则返回 null
。
或者,您可以利用 Laravel 的 验证器。为此,请提供一个包含属性名称和所需验证规则的数组作为 validate
参数:
$name = text(
label: '你叫什么名字?',
validate: ['name' => 'required|max:255|unique:users']
);
文本区域
textarea
函数将提示用户给定的问题,通过多行文本区域接受他们的输入,然后返回它:
use function Laravel\Prompts\textarea;
$story = textarea('给我讲个故事。');
您还可以包含占位符文本、默认值和信息提示:
$story = textarea(
label: '给我讲个故事。',
placeholder: '这是一个关于...的故事。',
hint: '这将显示在您的个人资料上。'
);
必填值
如果您需要输入值,可以传递 required
参数:
$story = textarea(
label: '给我讲个故事。',
required: true
);
如果您想自定义验证消息,也可以传递一个字符串:
$story = textarea(
label: '给我讲个故事。',
required: '故事是必填的。'
);
额外验证
最后,如果您想执行额外的验证逻辑,可以将闭包传递给 validate
参数:
$story = textarea(
label: '给我讲个故事。',
validate: fn (string $value) => match (true) {
strlen($value) < 250 => '故事必须至少 250 个字符。',
strlen($value) > 10000 => '故事不得超过 10,000 个字符。',
default => null
}
);
闭包将接收输入的值,并可以返回错误消息,或者如果验证通过则返回 null
。
或者,您可以利用 Laravel 的 验证器。为此,请提供一个包含属性名称和所需验证规则的数组作为 validate
参数:
$story = textarea(
label: '给我讲个故事。',
validate: ['story' => 'required|max:10000']
);
密码
password
函数与 text
函数类似,但用户输入时会被掩码。这在询问敏感信息(如密码)时非常有用:
use function Laravel\Prompts\password;
$password = password('你的密码是什么?');
您还可以包含占位符文本和信息提示:
$password = password(
label: '你的密码是什么?',
placeholder: '密码',
hint: '至少 8 个字符。'
);
必填值
如果您需要输入值,可以传递 required
参数:
$password = password(
label: '你的密码是什么?',
required: true
);
如果您想自定义验证消息,也可以传递一个字符串:
$password = password(
label: '你的密码是什么?',
required: '密码是必填的。'
);
额外验证
最后,如果您想执行额外的验证逻辑,可以将闭包传递给 validate
参数:
$password = password(
label: '你的密码是什么?',
validate: fn (string $value) => match (true) {
strlen($value) < 8 => '密码必须至少 8 个字符。',
default => null
}
);
闭包将接收输入的值,并可以返回错误消息,或者如果验证通过则返回 null
。
或者,您可以利用 Laravel 的 验证器。为此,请提供一个包含属性名称和所需验证规则的数组作为 validate
参数:
$password = password(
label: '你的密码是什么?',
validate: ['password' => 'min:8']
);
确认
如果您需要询问用户“是或否”的确认,可以使用 confirm
函数。用户可以使用箭头键或按 y
或 n
选择他们的响应。此函数将返回 true
或 false
。
use function Laravel\Prompts\confirm;
$confirmed = confirm('您接受条款吗?');
您还可以包含默认值、自定义“是”和“否”标签的措辞,以及信息提示:
$confirmed = confirm(
label: '您接受条款吗?',
default: false,
yes: '我接受',
no: '我拒绝',
hint: '必须接受条款才能继续。'
);
要求“是”
如果需要,您可以通过传递 required
参数来要求用户选择“是”:
$confirmed = confirm(
label: '您接受条款吗?',
required: true
);
如果您想自定义验证消息,也可以传递一个字符串:
$confirmed = confirm(
label: '您接受条款吗?',
required: '您必须接受条款才能继续。'
);
选择
如果您需要用户从预定义的选项集中进行选择,可以使用 select
函数:
use function Laravel\Prompts\select;
$role = select(
label: '用户应该拥有什么角色?',
options: ['成员', '贡献者', '所有者']
);
您还可以指定默认选择和信息提示:
$role = select(
label: '用户应该拥有什么角色?',
options: ['成员', '贡献者', '所有者'],
default: '所有者',
hint: '角色可以随时更改。'
);
您还可以将关联数组传递给 options
参数,以便返回所选键而不是其值:
$role = select(
label: '用户应该拥有什么角色?',
options: [
'member' => '成员',
'contributor' => '贡献者',
'owner' => '所有者',
],
default: 'owner'
);
最多将显示五个选项,然后列表将开始滚动。您可以通过传递 scroll
参数自定义此设置:
$role = select(
label: '您想分配哪个类别?',
options: Category::pluck('name', 'id'),
scroll: 10
);
额外验证
与其他提示函数不同,select
函数不接受 required
参数,因为不可能选择无。 但是,如果您需要呈现一个选项但防止其被选中,可以将闭包传递给 validate
参数:
$role = select(
label: '用户应该拥有什么角色?',
options: [
'member' => '成员',
'contributor' => '贡献者',
'owner' => '所有者',
],
validate: fn (string $value) =>
$value === 'owner' && User::where('role', 'owner')->exists()
? '已经存在一个所有者。'
: null
);
如果 options
参数是关联数组,则闭包将接收所选键,否则将接收所选值。闭包可以返回错误消息,或者如果验证通过则返回 null
。
多选
如果您需要用户能够选择多个选项,可以使用 multiselect
函数:
use function Laravel\Prompts\multiselect;
$permissions = multiselect(
label: '应该分配哪些权限?',
options: ['读取', '创建', '更新', '删除']
);
您还可以指定默认选择和信息提示:
use function Laravel\Prompts\multiselect;
$permissions = multiselect(
label: '应该分配哪些权限?',
options: ['读取', '创建', '更新', '删除'],
default: ['读取', '创建'],
hint: '权限可以随时更新。'
);
您还可以将关联数组传递给 options
参数,以返回所选选项的键而不是它们的值:
$permissions = multiselect(
label: '应该分配哪些权限?',
options: [
'read' => '读取',
'create' => '创建',
'update' => '更新',
'delete' => '删除',
],
default: ['read', 'create']
);
最多将显示五个选项,然后列表将开始滚动。您可以通过传递 scroll
参数自定义此设置:
$categories = multiselect(
label: '应该分配哪些类别?',
options: Category::pluck('name', 'id'),
scroll: 10
);
要求值
默认情况下,用户可以选择零个或多个选项。您可以传递 required
参数以强制选择一个或多个选项:
$categories = multiselect(
label: '应该分配哪些类别?',
options: Category::pluck('name', 'id'),
required: true
);
如果您想自定义验证消息,可以提供一个字符串作为 required
参数:
$categories = multiselect(
label: '应该分配哪些类别?',
options: Category::pluck('name', 'id'),
required: '您必须选择至少一个类别'
);
额外验证
如果您需要呈现一个选项但防止其被选中,可以将闭包传递给 validate
参数:
$permissions = multiselect(
label: '用户应该拥有哪些权限?',
options: [
'read' => '读取',
'create' => '创建',
'update' => '更新',
'delete' => '删除',
],
validate: fn (array $values) => ! in_array('read', $values)
? '所有用户都需要读取权限。'
: null
);
如果 options
参数是关联数组,则闭包将接收所选键,否则将接收所选值。闭包可以返回错误消息,或者如果验证通过则返回 null
。
建议
suggest
函数可用于为可能的选择提供自动补全。用户仍然可以提供任何答案,而不管自动补全提示:
use function Laravel\Prompts\suggest;
$name = suggest('你叫什么名字?', ['Taylor', 'Dayle']);
或者,您可以将闭包作为第二个参数传递给 suggest
函数。每当用户输入字符时,闭包将被调用。闭包应接受一个包含用户迄今为止输入的字符串参数,并返回一个用于自动补全的选项数组:
$name = suggest(
label: '你叫什么名字?',
options: fn ($value) => collect(['Taylor', 'Dayle'])
->filter(fn ($name) => Str::contains($name, $value, ignoreCase: true))
)
您还可以包含占位符文本、默认值和信息提示:
$name = suggest(
label: '你叫什么名字?',
options: ['Taylor', 'Dayle'],
placeholder: '例如:Taylor',
default: $user?->name,
hint: '这将显示在您的个人资料上。'
);
必填值
如果您需要输入值,可以传递 required
参数:
$name = suggest(
label: '你叫什么名字?',
options: ['Taylor', 'Dayle'],
required: true
);
如果您想自定义验证消息,也可以传递一个字符串:
$name = suggest(
label: '你叫什么名字?',
options: ['Taylor', 'Dayle'],
required: '您的名字是必填的。'
);
额外验证
最后,如果您想执行额外的验证逻辑,可以将闭包传递给 validate
参数:
$name = suggest(
label: '你叫什么名字?',
options: ['Taylor', 'Dayle'],
validate: fn (string $value) => match (true) {
strlen($value) < 3 => '名字必须至少 3 个字符。',
strlen($value) > 255 => '名字不得超过 255 个字符。',
default => null
}
);
闭包将接收输入的值,并可以返回错误消息,或者如果验证通过则返回 null
。
或者,您可以利用 Laravel 的 验证器。为此,请提供一个包含属性名称和所需验证规则的数组作为 validate
参数:
$name = suggest(
label: '你叫什么名字?',
options: ['Taylor', 'Dayle'],
validate: ['name' => 'required|min:3|max:255']
);
搜索
如果您有很多选项供用户选择,search
函数允许用户输入搜索查询以过滤结果,然后使用箭头键选择选项:
use function Laravel\Prompts\search;
$id = search(
label: '搜索应该接收邮件的用户',
options: fn (string $value) => strlen($value) > 0
? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all()
: []
);
闭包将接收用户迄今为止输入的文本,并必须返回一个选项数组。如果您返回一个关联数组,则将返回所选选项的键;否则,将返回其值。
在过滤数组时,如果您打算返回值,您应该使用 array_values
函数或 values
集合方法,以确保数组不会变成关联数组:
$names = collect(['Taylor', 'Abigail']);
$selected = search(
label: '搜索应该接收邮件的用户',
options: fn (string $value) => $names
->filter(fn ($name) => Str::contains($name, $value, ignoreCase: true))
->values()
->all(),
);
您还可以包含占位符文本和信息提示:
$id = search(
label: '搜索应该接收邮件的用户',
placeholder: '例如:Taylor Otwell',
options: fn (string $value) => strlen($value) > 0
? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all()
: [],
hint: '该用户将立即收到电子邮件。'
);
最多将显示五个选项,然后列表将开始滚动。您可以通过传递 scroll
参数自定义此设置:
$id = search(
label: '搜索应该接收邮件的用户',
options: fn (string $value) => strlen($value) > 0
? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all()
: [],
scroll: 10
);
额外验证
如果您想执行额外的验证逻辑,可以将闭包传递给 validate
参数:
$id = search(
label: '搜索应该接收邮件的用户',
options: fn (string $value) => strlen($value) > 0
? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all()
: [],
validate: function (int|string $value) {
$user = User::findOrFail($value);
if ($user->opted_out) {
return '该用户已选择不接收邮件。';
}
}
);
如果 options
闭包返回一个关联数组,则闭包将接收所选键;否则,它将接收所选值。闭包可以返回错误消息,或者如果验证通过则返回 null
。
多重搜索
如果您有很多可搜索的选项,并且需要用户能够选择多个项目,multisearch
函数允许用户输入搜索查询以过滤结果,然后使用箭头键和空格键选择选项:
use function Laravel\Prompts\multisearch;
$ids = multisearch(
'搜索应该接收邮件的用户',
fn (string $value) => strlen($value) > 0
? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all()
: []
);
闭包将接收用户迄今为止输入的文本,并必须返回一个选项数组。如果您返回一个关联数组,则将返回所选选项的键;否则,将返回其值。
在过滤数组时,如果您打算返回值,您应该使用 array_values
函数或 values
集合方法,以确保数组不会变成关联数组:
$names = collect(['Taylor', 'Abigail']);
$selected = multisearch(
label: '搜索应该接收邮件的用户',
options: fn (string $value) => $names
->filter(fn ($name) => Str::contains($name, $value, ignoreCase: true))
->values()
->all(),
);
您还可以包含占位符文本和信息提示:
$ids = multisearch(
label: '搜索应该接收邮件的用户',
placeholder: '例如:Taylor Otwell',
options: fn (string $value) => strlen($value) > 0
? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all()
: [],
hint: '该用户将立即收到电子邮件。'
);
最多将显示五个选项,然后列表将开始滚动。您可以通过提供 scroll
参数自定义此设置:
$ids = multisearch(
label: '搜索应该接收邮件的用户',
options: fn (string $value) => strlen($value) > 0
? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all()
: [],
scroll: 10
);
要求值
默认情况下,用户可以选择零个或多个选项。您可以传递 required
参数以强制选择一个或多个选项:
$ids = multisearch(
label: '搜索应该接收邮件的用户',
options: fn (string $value) => strlen($value) > 0
? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all()
: [],
required: true
);
如果您想自定义验证消息,可以将字符串提供给 required
参数:
$ids = multisearch(
label: '搜索应该接收邮件的用户',
options: fn (string $value) => strlen($value) > 0
? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all()
: [],
required: '您必须选择至少一个用户。'
);
额外验证
如果您想执行额外的验证逻辑,可以将闭包传递给 validate
参数:
$ids = multisearch(
label: '搜索应该接收邮件的用户',
options: fn (string $value) => strlen($value) > 0
? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all()
: [],
validate: function (array $values) {
$optedOut = User::whereLike('name', '%a%')->findMany($values);
if ($optedOut->isNotEmpty()) {
return $optedOut->pluck('name')->join(', ', ', 和 ').' 已选择不接收邮件。';
}
}
);
如果 options
闭包返回一个关联数组,则闭包将接收所选键;否则,它将接收所选值。闭包可以返回错误消息,或者如果验证通过则返回 null
。
暂停
pause
函数可用于向用户显示信息文本,并等待他们通过按 Enter / Return 键确认他们希望继续:
use function Laravel\Prompts\pause;
pause('按 ENTER 继续。');
在验证前转换输入
有时,您可能希望在验证发生之前转换提示输入。例如,您可能希望删除提供字符串中的空格。为此,许多提示函数提供了一个 transform
参数,该参数接受一个闭包:
$name = text(
label: '你叫什么名字?',
transform: fn (string $value) => trim($value),
validate: fn (string $value) => match (true) {
strlen($value) < 3 => '名字必须至少 3 个字符。',
strlen($value) > 255 => '名字不得超过 255 个字符。',
default => null
}
);
表单
通常,您将有多个提示将按顺序显示,以收集信息,然后执行其他操作。您可以使用 form
函数创建一组分组的提示供用户完成:
use function Laravel\Prompts\form;
$responses = form()
->text('你叫什么名字?', required: true)
->password('你的密码是什么?', validate: ['password' => 'min:8'])
->confirm('您接受条款吗?')
->submit();
submit
方法将返回一个包含表单提示的所有响应的数字索引数组。但是,您可以通过 name
参数为每个提示提供名称。当提供名称时,可以通过该名称访问命名提示的响应:
use App\Models\User;
use function Laravel\Prompts\form;
$responses = form()
->text('你叫什么名字?', required: true, name: 'name')
->password(
label: '你的密码是什么?',
validate: ['password' => 'min:8'],
name: 'password'
)
->confirm('您接受条款吗?')
->submit();
User::create([
'name' => $responses['name'],
'password' => $responses['password'],
]);
使用 form
函数的主要好处是用户可以使用 CTRL + U
返回表单中的先前提示。这允许用户修正错误或更改选择,而无需取消并重新启动整个表单。
如果您需要对表单中的提示进行更细粒度的控制,可以调用 add
方法,而不是直接调用其中一个提示函数。add
方法将传递用户提供的所有先前响应:
use function Laravel\Prompts\form;
use function Laravel\Prompts\outro;
$responses = form()
->text('你叫什么名字?', required: true, name: 'name')
->add(function ($responses) {
return text("你多大了,{$responses['name']}?");
}, name: 'age')
->submit();
outro("你的名字是 {$responses['name']},你 {$responses['age']} 岁。");
信息消息
note
、info
、warning
、error
和 alert
函数可用于显示信息消息:
use function Laravel\Prompts\info;
info('包安装成功。');
表格
table
函数使得显示多行和多列数据变得简单。您只需提供列名和表格数据:
use function Laravel\Prompts\table;
table(
headers: ['姓名', '电子邮件'],
rows: User::all(['name', 'email'])->toArray()
);
旋转
spin
函数在执行指定的回调时显示一个旋转器和可选消息。它用于指示正在进行的过程,并在完成后返回回调的结果:
use function Laravel\Prompts\spin;
$response = spin(
message: '正在获取响应...',
callback: fn () => Http::get('http://example.com')
);
spin
函数需要 pcntl
PHP 扩展才能动画旋转器。当此扩展不可用时,将显示旋转器的静态版本。
进度条
对于长时间运行的任务,显示进度条可以帮助用户了解任务的完成情况。使用 progress
函数,Laravel 将显示进度条,并在对给定可迭代值的每次迭代中推进其进度:
use function Laravel\Prompts\progress;
$users = progress(
label: '正在更新用户',
steps: User::all(),
callback: fn ($user) => $this->performTask($user)
);
progress
函数类似于映射函数,并将返回一个包含每次迭代的回调返回值的数组。
回调还可以接受 Laravel\Prompts\Progress
实例,允许您在每次迭代中修改标签和提示:
$users = progress(
label: '正在更新用户',
steps: User::all(),
callback: function ($user, $progress) {
$progress
->label("正在更新 {$user->name}")
->hint("创建于 {$user->created_at}");
return $this->performTask($user);
},
hint: '这可能需要一些时间。'
);
有时,您可能需要更手动地控制进度条的推进。首先,定义过程将迭代的总步骤数。然后,在处理每个项目后,通过 advance
方法推进进度条:
$progress = progress(label: '正在更新用户', steps: 10);
$users = User::all();
$progress->start();
foreach ($users as $user) {
$this->performTask($user);
$progress->advance();
}
$progress->finish();
清除终端
clear
函数可用于清除用户的终端:
use function Laravel\Prompts\clear;
clear();
终端注意事项
终端宽度
如果任何标签、选项或验证消息的长度超过用户终端中的“列”数,它将自动截断以适应。考虑在用户可能使用较窄的终端时最小化这些字符串的长度。通常安全的最大长度是 74 个字符,以支持 80 字符的终端。
终端高度
对于接受 scroll
参数的任何提示,配置的值将自动减少以适应用户终端的高度,包括验证消息的空间。
不支持的环境和回退
Laravel Prompts 支持 macOS、Linux 和带有 WSL 的 Windows。由于 Windows 版本的 PHP 的限制,目前无法在不带 WSL 的 Windows 上使用 Laravel Prompts。
因此,Laravel Prompts 支持回退到替代实现,例如 Symfony Console Question Helper。
当在 Laravel 框架中使用 Laravel Prompts 时,已为您配置每个提示的回退,并将在不支持的环境中自动启用。
回退条件
如果您不使用 Laravel 或需要自定义何时使用回退行为,可以将布尔值传递给 Prompt
类上的 fallbackWhen
静态方法:
use Laravel\Prompts\Prompt;
Prompt::fallbackWhen(
! $input->isInteractive() || windows_os() || app()->runningUnitTests()
);
回退行为
如果您不使用 Laravel 或需要自定义回退行为,可以将闭包传递给每个提示类上的 fallbackUsing
静态方法:
use Laravel\Prompts\TextPrompt;
use Symfony\Component\Console\Question\Question;
use Symfony\Component\Console\Style\SymfonyStyle;
TextPrompt::fallbackUsing(function (TextPrompt $prompt) use ($input, $output) {
$question = (new Question($prompt->label, $prompt->default ?: null))
->setValidator(function ($answer) use ($prompt) {
if ($prompt->required && $answer === null) {
throw new \RuntimeException(
is_string($prompt->required) ? $prompt->required : '必填。'
);
}
if ($prompt->validate) {
$error = ($prompt->validate)($answer ?? '');
if ($error) {
throw new \RuntimeException($error);
}
}
return $answer;
});
return (new SymfonyStyle($input, $output))
->askQuestion($question);
});
必须单独为每个提示类配置回退。闭包将接收提示类的实例,并必须返回提示的适当类型。