# 如何使用提问
* [如何使用提问](https://www.kancloud.cn/uuling/tp5-console/366134#_0)
* [要求用户确认](https://www.kancloud.cn/uuling/tp5-console/366134#_4)
* [询问用户信息](https://www.kancloud.cn/uuling/tp5-console/366134#_146)
* [让用户从答案列表中选择](https://www.kancloud.cn/uuling/tp5-console/366134#_183)
* [多选](https://www.kancloud.cn/uuling/tp5-console/366134#_376)
* [自动完成](https://www.kancloud.cn/uuling/tp5-console/366134#_397)
* [隐藏用户输入](https://www.kancloud.cn/uuling/tp5-console/366134#_440)
* [验证答案](https://www.kancloud.cn/uuling/tp5-console/366134#_488)
* [验证一个隐藏的响应](https://www.kancloud.cn/uuling/tp5-console/366134#_581)
## 要求用户确认
假设你希望在一个方法被执行之前先行确认。添加以下代码到你的命令中:
~~~
<?php
namespace app\console;
use think\console\Command;
use think\console\Output;
use think\console\Input;
class QuestionCommand extends Command
{
protected function configure()
{
$this
// 命令的名字("think" 后面的部分)
->setName('demo:question')
->setDescription('Test question');
}
public function execute(Input $input, Output $output)
{
$question = $output->confirm($input, 'Continue with this action?', false);
if (!$question) {
return;
}
}
}
~~~
本例中,用户会被问到 "Continue with this action?"。如果用户回答`yes`或者`y`开头的字符串 它就返回`true`,如果答案是`no`或者`n`开头的字符串的话,它就返回`false`。`confirm()`的第三个参数,是当用户不键入任何有效input时,返回的默认值。如果没有提供第三个参数, true 会被取用。
现在,你可以传入用户名到命令中:
~~~
$ php think demo:question
Continue with this action? (yes/no) [no]:
> yes
~~~
如果我们想输入其他的字符(如:`j`) 也表示`yes`的意思,该怎么处理呢?
前面的示例调用的是 Output 中的方法, 我们可以参考其代码:
~~~
// ...
public function confirm(Input $input, $question, $default = true)
{
return $this->askQuestion($input, new Confirmation($question, $default));
}
// ...
protected function askQuestion(Input $input, Question $question)
{
$ask = new Ask($input, $this, $question);
$answer = $ask->run();
if ($input->isInteractive()) {
$this->newLine();
}
return $answer;
}
// ...
~~~
我们再看下类`\think\console\output\question\Confirmation`的构造方法`__construct()`
~~~
// ...
public function __construct($question, $default = true, $trueAnswerRegex = '/^y/i')
{
// ...
}
~~~
我们可以看到构造器的第三个参数中自定义一个正则表达式,用于判断答案是否是 "yes"的意思(默认的正则表达式是`/^y/i`)。
我们将上面的示例代码进行改造:
~~~
<?php
namespace app\console;
use think\console\Command;
use think\console\Output;
use think\console\Input;
use think\console\output\Ask;
use think\console\output\question\Confirmation;
class QuestionCommand extends Command
{
protected function configure()
{
$this
// 命令的名字("think" 后面的部分)
->setName('demo:question')
->setDescription('Test question');
}
public function execute(Input $input, Output $output)
{
$question = new Confirmation('Continue with this action?', false, '/^(y|j)/i');
$ask = new Ask($input, $output, $question);
$answer = $ask->run();
// if ($input->isInteractive()) {
// // 输出空行
// $output->newLine();
// }
if (!$answer) {
$output->writeln('false');
return;
}
$output->writeln('true');
}
}
~~~
测试一下成果:
~~~
php think demo:question
Continue with this action? (yes/no) [no]:
> j
true
~~~
## 询问用户信息
你也可以用超过一个简单的`yes/no`的答案来向用户提问。例如,如果你想要知道 behavior 的名称,可以把下面代码添加到你的命令中:
~~~
<?php
namespace app\console;
use think\console\Command;
use think\console\Output;
use think\console\Input;
use think\console\output\Ask;
use think\console\output\question\Confirmation;
class QuestionCommand extends Command
{
protected function configure()
{
$this
// 命令的名字("think" 后面的部分)
->setName('demo:question')
->setDescription('Test question');
}
public function execute(Input $input, Output $output)
{
$behavior = $output->ask($input, 'Please enter the name of the behavior', 'initBehavior');
$output->writeln($behavior);
}
}
~~~
用户会被问 "Please enter the name of the behavior"。我们可以输入一些会被 ask() 方法返回的名称。如果用户留空,默认值 (此处是 initBehavior) 会被返回。
## 让用户从答案列表中选择
如果你预定义了一组答案让用户从中选择,你可以使用`choice`,它确保用户只能从预定义列表中输入有效字符串:
~~~
<?php
namespace app\console;
use think\console\Command;
use think\console\Output;
use think\console\Input;
class QuestionCommand extends Command
{
protected function configure()
{
$this
// 命令的名字("think" 后面的部分)
->setName('demo:question')
->setDescription('Test question');
}
public function execute(Input $input, Output $output)
{
$color = $output->choice(
$input,
'Please select your favorite color (defaults to red)',
['red', 'blue', 'yellow'],
'red'
);
$output->writeln('You have just selected: ' . $color);
}
}
~~~
现在,我们可以传入颜色到命令中:
~~~
$ php think demo:question
Please select your favorite color (defaults to red) [red]:
[0] red
[1] blue
[2] yellow
> 0
red
$ php think demo:question
Please select your favorite color (defaults to red) [red]:
[0] red
[1] blue
[2] yellow
> 10
Value "10" is invalid
Please select your favorite color (defaults to red) [red]:
[0] red
[1] blue
[2] yellow
>
~~~
上面的示例可以看到,当我们输入的数据超出范围后,出现错误并让我们重新输入, 但错误提示不怎么友好,因此我们需要对其进行改造:
我们看下`choice()`代码:
~~~
// ...
public function choice(Input $input, $question, array $choices, $default = null)
{
if (null !== $default) {
$values = array_flip($choices);
$default = $values[$default];
}
return $this->askQuestion($input, new Choice($question, $choices, $default));
}
protected function askQuestion(Input $input, Question $question)
{
$ask = new Ask($input, $this, $question);
$answer = $ask->run();
if ($input->isInteractive()) {
$this->newLine();
}
return $answer;
}
// ...
~~~
我们可以看到,choice 中使用了`\think\console\output\question\Choice`,分析代码可以看到,修改错误提示的方法是:
~~~
// ...
/**
* 设置错误提示信息
* @param string $errorMessage
* @return self
*/
public function setErrorMessage($errorMessage)
{
// ...
}
// ...
~~~
我们将上面的示例代码进行改造:
~~~
<?php
namespace app\console;
use think\console\Command;
use think\console\Output;
use think\console\Input;
use think\console\output\Ask;
use think\console\output\question\Choice;
class QuestionCommand extends Command
{
protected function configure()
{
$this
// 命令的名字("think" 后面的部分)
->setName('demo:question')
->setDescription('Test question');
}
public function execute(Input $input, Output $output)
{
$question = new Choice(
'Please select your favorite color (defaults to red)',
['red', 'blue', 'yellow'],
0
);
$question->setErrorMessage('Color %s is invalid.');
$ask = new Ask($input, $output, $question);
$color = $ask->run();
$output->writeln('You have just selected: '.$color);
}
}
~~~
现在,你可以传入颜色到命令中:
~~~
$ php think demo:question
Please select your favorite color (defaults to red) [red]:
[0] red
[1] blue
[2] yellow
> 0
red
$ php think demo:question
Please select your favorite color (defaults to red) [red]:
[0] red
[1] blue
[2] yellow
> 10
Color 10 is invalid
Please select your favorite color (defaults to red) [red]:
[0] red
[1] blue
[2] yellow
>
~~~
默认被选中的选项由构造器的第三个参数提供。默认是`null`,代表没有默认的选项。
如果用户输入了无效字符串,会显示一个错误信息,用户会被要求再一次提供答案,直到他们输入一个有效字符串,或是达到了尝试上限为止。默认的最大尝试次数是`null`,代表可以无限次尝试。你可以使用 setErrorMessage() 定义自己的错误信息。
### 多选
有时,可以给出多个答案。`Choice`使用逗号分隔的值,提供了此项功能。默认是禁用的,开启它可使用`setMultiselect()`:
> `\think\Console`中没有提供该方法
现在,你可以传入颜色到命令中:
~~~
$ php think demo:question
Please select your favorite color (defaults to red) [red, blue]:
[0] red
[1] blue
[2] yellow
> 1,2
You have just selected: blue,yellow
~~~
如果用户不输入任何内容,结果是:`You have just selected: red, blue`。
## 自动完成
对于给定的问题,你也可以提供一个默认的答案数组。它们将根据用户的操作而自动完成:
~~~
<?php
namespace app\console;
use think\console\Command;
use think\console\Output;
use think\console\Input;
use think\console\output\Ask;
use think\console\output\Question;
use think\console\output\question\Choice;
class QuestionCommand extends Command
{
protected function configure()
{
$this
// 命令的名字("think" 后面的部分)
->setName('demo:question')
->setDescription('Test question');
}
public function execute(Input $input, Output $output)
{
$question = new Question('Please enter the name of a color', 'pink');
$question->setAutocompleterValues(['red', 'blue', 'yellow']);
$ask = new Ask($input, $output, $question);
$color = $ask->run();
$output->writeln('You have just selected: ' . $color);
}
}
~~~
## 隐藏用户输入
你也可以在问问题时隐藏输入。这对密码来说极为方便:
~~~
<?php
namespace app\console;
use think\console\Command;
use think\console\Output;
use think\console\Input;
use think\console\output\Ask;
use think\console\output\Question;
use think\console\output\question\Choice;
class QuestionCommand extends Command
{
protected function configure()
{
$this
// 命令的名字("think" 后面的部分)
->setName('demo:question')
->setDescription('Test question');
}
public function execute(Input $input, Output $output)
{
$password = $output->askHidden($input, 'What is the database password?');
$output->writeln($password);
}
}
~~~
现在,你可以传入登录密码到命令中:
~~~
$ php think demo:question
What is the login password?:
>
123456
~~~
## 验证答案
你甚至可以验证答案。例如,前面例子中你曾询问过 behavior 名称。假设我们设置了后缀 Behavior,那么我们可以使用`setValidator()`方法 来验证它:
~~~
<?php
namespace app\console;
use think\console\Command;
use think\console\Output;
use think\console\Input;
class QuestionCommand extends Command
{
protected function configure()
{
$this
// 命令的名字("think" 后面的部分)
->setName('demo:question')
->setDescription('Test question');
}
public function execute(Input $input, Output $output)
{
$name = $output->ask($input,
'Please enter the name of the behavior',
'demoBehavior',
function ($answer) {
if ('Behavior' !== substr($answer, -8)) {
throw new \RuntimeException(
'The name of the behavior should be suffixed with \'Behavior\''
);
}
return $answer;
});
$output->writeln($name);
}
}
~~~
`$validator`是一个`callback`,专门处理验证。它在有错误发生时应抛出一个异常。异常信息会被显示在控制台中,所以在里面放入一些有用的信息是一个很好的实践。回调函数在验证通过时,应该返回用户的`input`。
如果我们想设置最大提问次数该怎么办呢?
你可以用`setMaxAttempts()`方法来设置(验证失败时的)最大的提问次数。如果达到最大值,它将使用默认值。使用`null`代表可以无限次尝试回答(直到验证通过)。用户将被始终提问,直到他们提供了有效答案为止,也只有输入有效时命令才会继续执行。
~~~
<?php
namespace app\console;
use think\console\Command;
use think\console\Output;
use think\console\Input;
use think\console\output\Ask;
use think\console\output\Question;
class QuestionCommand extends Command
{
protected function configure()
{
$this
// 命令的名字("think" 后面的部分)
->setName('demo:question')
->setDescription('Test question');
}
public function execute(Input $input, Output $output)
{
// ...
$question = new Question('Please enter the name of the behavior', 'demoBehavior');
$question->setValidator(function ($answer) {
if ('Behavior' !== substr($answer, -8)) {
throw new \RuntimeException(
'The name of the behavior should be suffixed with \'Behavior\''
);
}
return $answer;
});
// 设置最大提问数
$question->setMaxAttempts(2);
$ask = new Ask($input, $output, $question);
$name = $ask->run();
$output->writeln($name);
}
}
~~~
## 验证一个隐藏的响应
你也可以在隐藏(答案输入)的提问中使用validator:
~~~
<?php
namespace app\console;
use think\console\Command;
use think\console\Output;
use think\console\Input;
class QuestionCommand extends Command
{
protected function configure()
{
$this
// 命令的名字("think" 后面的部分)
->setName('demo:question')
->setDescription('Test question');
}
public function execute(Input $input, Output $output)
{
$name = $output->askHidden($input,
'Please enter your password',
'demoBehavior',
function ($value) {
if (trim($value) == '') {
throw new \Exception('The password can not be empty');
}
return $value;
});
$output->writeln($name);
}
}
~~~
或者使用下面的方式:
~~~
<?php
namespace app\console;
use think\console\Command;
use think\console\Output;
use think\console\Input;
use think\console\output\Ask;
use think\console\output\Question;
class QuestionCommand extends Command
{
protected function configure()
{
$this
// 命令的名字("think" 后面的部分)
->setName('demo:question')
->setDescription('Test question');
}
public function execute(Input $input, Output $output)
{
// ...
$question = new Question('Please enter your password');
$question->setValidator(function ($value) {
if (trim($value) == '') {
throw new \Exception('The password can not be empty');
}
return $value;
});
$question->setHidden(true);
$question->setMaxAttempts(2);
$ask = new Ask($input, $output, $question);
$name = $ask->run();
$output->writeln($name);
}
}
~~~
- 序言
- 数据库操作
- 自定义数据操作
- DBCreate
- DBUpdate
- DBList
- DBDelete
- 事务
- 插入数据
- 更新数据
- 验证场景
- ✦事务队列✦
- DBWhere
- 分页
- 分类
- 新增分类
- 编辑分类
- 删除分类
- 分类数据
- Excel
- 数据验证
- 自定义验证类
- Where技巧
- 标签和文章
- tag数据库
- TagManager
- 标签管理页面
- 标签列表页
- 新增标签
- 编辑标签
- 删除标签
- 标签&文章
- 新建标签文章
- 更新标签文章
- 删除标签文章
- 界面
- 【官方】ME.js
- 【官方】jquery-mini-enjoy.js
- bootstrap
- 前端错误页面模板
- 后台界面
- 后台页面模板框架
- 后台左边菜单
- 后台页面控制
- Search表单
- 基础界面
- Panel-Tab
- Panel-Tab基础
- 前端
- IOS禁止页面滚动
- layer技巧
- JS中通过LayUI弹出文本输入层,多个按钮回调
- 表单-Ajax
- token
- 表单验证+Ajax提交
- 前端验证
- 后端验证
- ajax
- checkbox 全选
- ajaxUploader
- ajaxText
- ajax-get
- ajax-input
- 文章
- CRM
- 用户模块
- User
- LoginData
- UserLogin
- UserUpdate
- 商城
- 商品表+SKU
- 购物车
- 订单
- 创建订单-来至于购物车
- 创建订单-来至于立即购买
- 取消订单
- 卡券
- 卡券数据库
- 插件
- 单图片上传插件
- search 搜索插件
- 富文本编辑器
- 表单零部件
- 单文件上传
- Form表单插件
- 隐藏表单
- 标题文字单行
- 文本
- 下拉框select
- CheckBox
- 单图片
- textarea
- 文件上传
- 颜色选择器
- 标签
- 微信
- jssdk
- 自定义回复
- 网页授权流程
- 网页授权
- 用户信息
- 公众号对接配置
- 第三方类库
- VUE库
- php 第三方
- H5库
- 小程序
- 消息队列 Beanstalkd
- API-3
- chrome-开发
- 采集QueryList
- moment.php
- Helper类库
- PageHistory
- FileWeChat
- Text
- Mini-Enjoy
- TODO-LIST
- 视频
- CSS
- 技术文章
- 【shop】订单延时
- IDE&工具
- system
- 路由
- swoole
- 关闭守护进程
- 基于swoole的定时器程序,支持秒级处理
- 测试
- 客户端
- 服务器端
- 入门篇
- 环境搭建及扩展安装
- Swoole的Task使用以及swoole_client
- Timer定时器、心跳检测及Task进阶实例:mysql连接池
- Swoole多端口监听、热重启以及Timer进阶:简单crontab
- Swoole的自定义协议功能的使用
- 命令行模式
- 控制台命令
- 使用Console命令、快捷方式和内建命令
- 理解控制台参数是如何被操作的
- 如何使用提问
- 如何对命令行进行彩色和样式输出
- ★如何从控制器中调用一个命令★
- 控制台输出(参数和选项)
- 冗长级别
- 自定义命令
- RestAPI
- 设计规范
- API
- 商品分类+数据
- [小程序]-新增用户登录
- 外卖平台
- 设计
- 扩展
- SSL
