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

Laravel Prompts 非常适合在你的 Artisan 控制台命令 中接受用户输入,但它也可以用于任何命令行 PHP 项目。
NOTE
Laravel Prompts 支持 macOS、Linux 和带有 WSL 的 Windows。有关更多信息,请参阅我们的 不支持的环境与回退 文档。
安装
Laravel Prompts 已经包含在最新版本的 Laravel 中。
Laravel Prompts 也可以通过 Composer 包管理器安装到你的其他 PHP 项目中:
composer require laravel/prompts可用提示
文本
text 函数将用给定的问题提示用户,接受他们的输入,然后返回:
use function Laravel\Prompts\text;
$name = text('你叫什么名字?');你也可以包含占位符文本、默认值和信息性提示:
$name = text(
label: '你叫什么名字?',
placeholder: '例如 张三',
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']
);数字
number 函数将用给定的问题提示用户,接受他们的数字输入,然后返回。number 函数允许用户使用上下箭头键来操纵数字:
use function Laravel\Prompts\number;
$number = number('你想要多少份?');你也可以包含占位符文本、默认值和信息性提示:
$name = number(
label: '你想要多少份?',
placeholder: '5',
default: 1,
hint: '这将决定要创建多少份。'
);必需值
如果你需要输入一个值,可以传递 required 参数:
$copies = number(
label: '你想要多少份?',
required: true
);如果你想自定义验证消息,也可以传递一个字符串:
$copies = number(
label: '你想要多少份?',
required: '需要输入份数。'
);额外验证
最后,如果你想执行额外的验证逻辑,可以传递一个闭包给 validate 参数:
$copies = number(
label: '你想要多少份?',
validate: fn (?int $value) => match (true) {
$value < 1 => '至少需要一份。',
$value > 100 => '你不能创建超过 100 份。',
default => null
}
);该闭包将接收输入的值,并可能返回错误消息,如果验证通过则返回 null。
或者,你可以利用 Laravel 验证器 的强大功能。为此,将包含属性名称和所需验证规则的数组提供给 validate 参数:
$copies = number(
label: '你想要多少份?',
validate: ['copies' => 'required|integer|min:1|max:100']
);密码
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
);辅助信息
info 参数可用于显示关于当前高亮选项的额外信息。当提供一个闭包时,它将接收当前高亮选项的值,并应返回一个字符串或 null:
$role = select(
label: '该用户应拥有什么角色?',
options: [
'member' => '成员',
'contributor' => '贡献者',
'owner' => '所有者',
],
info: fn (string $value) => match ($value) {
'member' => '可以查看和评论。',
'contributor' => '可以查看、评论和编辑。',
'owner' => '对所有资源的完全访问权限。',
default => null,
}
);如果信息不依赖于高亮的选项,你也可以向 info 参数传递一个静态字符串:
$role = select(
label: '该用户应拥有什么角色?',
options: ['成员', '贡献者', '所有者'],
info: '角色可以随时更改。'
);额外验证
与其他提示函数不同,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
);辅助信息
info 参数可用于显示关于当前高亮选项的额外信息。当提供一个闭包时,它将接收当前高亮选项的值,并应返回一个字符串或 null:
$permissions = multiselect(
label: '应该分配哪些权限?',
options: [
'read' => '读取',
'create' => '创建',
'update' => '更新',
'delete' => '删除',
],
info: fn (string $value) => match ($value) {
'read' => '查看资源及其属性。',
'create' => '创建新资源。',
'update' => '修改现有资源。',
'delete' => '永久移除资源。',
default => null,
}
);必需值
默认情况下,用户可以选择零个或多个选项。你可以传递 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('你叫什么名字?', ['张三', '李四']);或者,你可以向 suggest 函数的第二个参数传递一个闭包。每次用户键入一个输入字符时,该闭包将被调用。闭包应接受一个包含用户到目前为止输入的字符串参数,并返回一个用于自动完成的选项数组:
$name = suggest(
label: '你叫什么名字?',
options: fn ($value) => collect(['张三', '李四'])
->filter(fn ($name) => Str::contains($name, $value, ignoreCase: true))
);你也可以包含占位符文本、默认值和信息性提示:
$name = suggest(
label: '你叫什么名字?',
options: ['张三', '李四'],
placeholder: '例如 张三',
default: $user?->name,
hint: '这将显示在你的个人资料中。'
);辅助信息
info 参数可用于显示关于当前高亮选项的额外信息。当提供一个闭包时,它将接收当前高亮选项的值,并应返回一个字符串或 null:
$name = suggest(
label: '你叫什么名字?',
options: ['Taylor', 'Dayle'],
info: fn (string $value) => match ($value) {
'Taylor' => '管理员',
'Dayle' => '贡献者',
default => null,
}
);必需值
如果你需要输入一个值,可以传递 required 参数:
$name = suggest(
label: '你叫什么名字?',
options: ['张三', '李四'],
required: true
);如果你想自定义验证消息,也可以传递一个字符串:
$name = suggest(
label: '你叫什么名字?',
options: ['张三', '李四'],
required: '姓名是必需的。'
);额外验证
最后,如果你想执行额外的验证逻辑,可以传递一个闭包给 validate 参数:
$name = suggest(
label: '你叫什么名字?',
options: ['张三', '李四'],
validate: fn (string $value) => match (true) {
strlen($value) < 3 => '姓名必须至少 3 个字符。',
strlen($value) > 255 => '姓名不能超过 255 个字符。',
default => null
}
);该闭包将接收输入的值,并可能返回错误消息,如果验证通过则返回 null。
或者,你可以利用 Laravel 验证器 的强大功能。为此,将包含属性名称和所需验证规则的数组提供给 validate 参数:
$name = suggest(
label: '你叫什么名字?',
options: ['张三', '李四'],
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 Collection 方法,以确保数组不会变成关联数组:
$names = collect(['张三', '李四']);
$selected = search(
label: '搜索应接收邮件的用户',
options: fn (string $value) => $names
->filter(fn ($name) => Str::contains($name, $value, ignoreCase: true))
->values()
->all(),
);你也可以包含占位符文本和信息性提示:
$id = search(
label: '搜索应接收邮件的用户',
placeholder: '例如 张三',
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
);辅助信息
info 参数可用于显示关于当前高亮选项的额外信息。当提供一个闭包时,它将接收当前高亮选项的值,并应返回一个字符串或 null:
$id = search(
label: '搜索应接收邮件的用户',
options: fn (string $value) => strlen($value) > 0
? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all()
: [],
info: fn (int $userId) => User::find($userId)?->email
);额外验证
如果你想执行额外的验证逻辑,可以传递一个闭包给 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 Collection 方法,以确保数组不会变成关联数组:
$names = collect(['张三', '李四']);
$selected = multisearch(
label: '搜索应接收邮件的用户',
options: fn (string $value) => $names
->filter(fn ($name) => Str::contains($name, $value, ignoreCase: true))
->values()
->all(),
);你也可以包含占位符文本和信息性提示:
$ids = multisearch(
label: '搜索应接收邮件的用户',
placeholder: '例如 张三',
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
);辅助信息
info 参数可用于显示关于当前高亮选项的额外信息。当提供一个闭包时,它将接收当前高亮选项的值,并应返回一个字符串或 null:
$ids = multisearch(
label: '搜索应接收邮件的用户',
options: fn (string $value) => strlen($value) > 0
? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all()
: [],
info: fn (int $userId) => User::find($userId)?->email
);必需值
默认情况下,用户可以选择零个或多个选项。你可以传递 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(', ', ', and ').' 已选择不接收邮件。';
}
}
);如果 options 闭包返回一个关联数组,那么闭包将接收选中的键;否则将接收选中的值。闭包可以返回错误消息,如果验证通过则返回 null。
暂停
pause 函数可用于向用户显示信息性文本,并等待他们按回车键确认继续的意愿:
use function Laravel\Prompts\pause;
pause('按 ENTER 键继续。');自动完成
autocomplete 函数可用于为可能的选项提供内联自动完成。当用户输入时,匹配其输入的建议将作为幽灵文本显示,可以通过按 Tab 或右箭头键接受:
use function Laravel\Prompts\autocomplete;
$name = autocomplete(
label: '你叫什么名字?',
options: ['Taylor', 'Dayle', 'Jess', 'Nuno', 'Tim']
);您还可以包含占位符文本、默认值和信息性提示:
$name = autocomplete(
label: '你叫什么名字?',
options: ['Taylor', 'Dayle', 'Jess', 'Nuno', 'Tim'],
placeholder: '例如 Taylor',
default: $user?->name,
hint: '使用 Tab 接受,上下键循环选择。'
);动态选项
您也可以传递一个闭包,根据用户的输入动态生成选项。每次用户输入一个字符时都会调用该闭包,并应返回一个用于自动完成的选项数组:
$file = autocomplete(
label: '哪个文件?',
options: fn (string $value) => collect($files)
->filter(fn ($file) => str_starts_with(strtolower($file), strtolower($value)))
->values()
->all(),
);必需值
如果您需要输入一个值,可以传递 required 参数:
$name = autocomplete(
label: '你叫什么名字?',
options: ['Taylor', 'Dayle', 'Jess', 'Nuno', 'Tim'],
required: true
);如果您想自定义验证消息,也可以传递一个字符串:
$name = autocomplete(
label: '你叫什么名字?',
options: ['Taylor', 'Dayle', 'Jess', 'Nuno', 'Tim'],
required: '姓名是必填项。'
);额外验证
最后,如果您想执行额外的验证逻辑,可以向 validate 参数传递一个闭包:
$name = autocomplete(
label: '你叫什么名字?',
options: ['Taylor', 'Dayle', 'Jess', 'Nuno', 'Tim'],
validate: fn (string $value) => match (true) {
strlen($value) < 3 => '姓名必须至少包含 3 个字符。',
strlen($value) > 255 => '姓名不能超过 255 个字符。',
default => null
}
);该闭包将接收已输入的值,并可以返回错误消息,如果验证通过则返回 null。
验证前转换输入
有时你可能希望在验证发生之前转换提示输入。例如,你可能希望从任何提供的字符串中删除空格。为了实现这一点,许多提示函数提供了一个 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;
use function Laravel\Prompts\text;
$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(
callback: fn () => Http::get('http://example.com'),
message: '正在获取响应...'
);WARNING
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();任务
task 函数在执行给定回调时,会显示一个带有标签、旋转器和滚动实时输出区域的任务。它非常适合包装长时间运行的进程,例如依赖安装或部署脚本,提供正在发生的事情的实时可见性:
use function Laravel\Prompts\task;
task(
label: '正在安装依赖',
callback: function ($logger) {
// 长时间运行的进程...
}
);回调接收一个 Logger 实例,您可以使用它在任务的输出区域中显示日志行、状态消息和流式文本。
WARNING
task 函数需要 PCNTL PHP 扩展来运行动画旋转器。当此扩展不可用时,将显示任务的静态版本。
记录日志行
line 方法向任务的滚动输出区域写入单行日志:
task(
label: '正在安装依赖',
callback: function ($logger) {
$logger->line('正在解析包...');
// ...
$logger->line('正在下载 laravel/framework');
// ...
}
);状态消息
您可以使用 success、warning 和 error 方法来显示状态消息。它们将作为稳定、高亮的消息显示在滚动日志区域上方:
task(
label: '正在部署应用',
callback: function ($logger) {
$logger->line('正在拉取最新更改...');
// ...
$logger->success('更改已拉取!');
$logger->line('正在运行迁移...');
// ...
$logger->warning('没有新的迁移可运行。');
$logger->line('正在清除缓存...');
// ...
$logger->success('缓存已清除!');
}
);更新标签
label 方法允许您在任务运行时更新任务的标签:
task(
label: '开始部署...',
callback: function ($logger) {
$logger->label('正在拉取最新更改...');
// ...
$logger->label('正在运行迁移...');
// ...
$logger->label('正在清除缓存...');
// ...
}
);显示子标签
subLabel 方法会在任务主标签下方显示一行暗淡的文本,适用于传达临时状态,例如当前正在进行的步骤。传入一个空字符串即可清除子标签:
task(
label: 'Deploying',
callback: function ($logger) {
$logger->subLabel('Building assets...');
// ...
$logger->subLabel('Running migrations...');
// ...
$logger->subLabel('');
}
);你还可以通过 subLabel 参数提供一个初始子标签:
task(
label: 'Deploying',
callback: function ($logger) {
// ...
},
subLabel: 'Preparing...'
);流式文本
对于增量产生输出的进程,例如 AI 生成的响应,partial 方法允许您逐词或逐块地流式传输文本。流完成后,调用 commitPartial 以完成输出:
task(
label: '正在生成响应...',
callback: function ($logger) {
foreach ($words as $word) {
$logger->partial($word . ' ');
}
$logger->commitPartial();
}
);自定义输出限制
默认情况下,任务最多显示 10 行滚动输出。您可以通过 limit 参数自定义此值:
task(
label: '正在安装依赖',
callback: function ($logger) {
// ...
},
limit: 20
);保留摘要
默认情况下,任务输出在回调函数执行完毕即被清除。如果你希望在任务完成后仍将状态信息保留在屏幕上,可以传入 keepSummary 参数:
task(
label: 'Deploying',
callback: function ($logger) {
$logger->success('Assets built');
// ...
$logger->success('Migrations complete');
},
keepSummary: true,
);流
stream 函数显示流式传输到终端的文本,非常适合显示 AI 生成的内容或任何增量到达的文本:
use function Laravel\Prompts\stream;
$stream = stream();
foreach ($words as $word) {
$stream->append($word . ' ');
usleep(25_000); // 模拟块之间的延迟...
}
$stream->close();append 方法向流中添加文本,并呈现逐渐淡入的效果。当所有内容流式传输完成后,调用 close 方法以完成输出并恢复光标。
终端标题
title 函数更新用户终端窗口或标签页的标题:
use function Laravel\Prompts\title;
title('正在安装依赖');要将终端标题重置为默认值,传递一个空字符串:
title('');清空终端
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。
NOTE
当在 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 : 'Required.'
);
}
if ($prompt->validate) {
$error = ($prompt->validate)($answer ?? '');
if ($error) {
throw new \RuntimeException($error);
}
}
return $answer;
});
return (new SymfonyStyle($input, $output))
->askQuestion($question);
});必须为每个提示类单独配置回退。闭包将接收一个提示类的实例,并且必须为提示返回适当的类型。
测试
Laravel 提供了多种方法来测试你的命令是否显示了预期的提示消息:
test('报告生成', function () {
$this->artisan('report:generate')
->expectsPromptsInfo('欢迎使用应用程序!')
->expectsPromptsWarning('此操作无法撤消')
->expectsPromptsError('出错了')
->expectsPromptsAlert('重要通知!')
->expectsPromptsIntro('正在启动进程...')
->expectsPromptsOutro('进程完成!')
->expectsPromptsTable(
headers: ['姓名', '邮箱'],
rows: [
['张三', 'zhangsan@example.com'],
['李四', 'lisi@example.com'],
]
)
->assertExitCode(0);
});public function test_report_generation(): void
{
$this->artisan('report:generate')
->expectsPromptsInfo('欢迎使用应用程序!')
->expectsPromptsWarning('此操作无法撤消')
->expectsPromptsError('出错了')
->expectsPromptsAlert('重要通知!')
->expectsPromptsIntro('正在启动进程...')
->expectsPromptsOutro('进程完成!')
->expectsPromptsTable(
headers: ['姓名', '邮箱'],
rows: [
['张三', 'zhangsan@example.com'],
['李四', 'lisi@example.com'],
]
)
->assertExitCode(0);
}