public static function choice($question, array $choices, $defaultValue = null)
    {
        $value = '';
        while (trim($value) == '') {

            // Write prompt.
            self::writeln('');
            self::write(' ' . $question, 'info');
            if ($defaultValue !== null) {
                // @codeCoverageIgnoreStart
                self::write(' [');
                self::write((string)$defaultValue, 'comment');
                self::write(']');
                // @codeCoverageIgnoreEnd
            }
            self::writeln(':');

            // Write choices.
            if (count($choices) > 0) {
                foreach ($choices as $index => $choice) {
                    self::write('  [');
                    self::write((string)($index + 1), 'comment');
                    self::writeln('] ' . $choice);
                }
            }

            // Input.
            if (self::$testValue === null) {
                // @codeCoverageIgnoreStart
                $value = readline(' > ');
                // @codeCoverageIgnoreEnd
            } else {
                $value = self::$testValue;
            }
            if (trim($value) == '') {
                // @codeCoverageIgnoreStart
                $value = $defaultValue;
                // @codeCoverageIgnoreEnd
            }
            if (!isset($choices[intval($value) - 1])) {
                // @codeCoverageIgnoreStart
                self::writeln('');
                self::block('[ERROR] Value "' . $value . '" is invalid', 'error');
                $value = '';
                // @codeCoverageIgnoreEnd
            } elseif (trim($value) == '') {
                // @codeCoverageIgnoreStart
                self::writeln('');
                self::block('[ERROR] A value is required', 'error');
                // @codeCoverageIgnoreEnd
            }
            self::writeln('');
        }
        return trim($value);
    }