4 * This file is part of the Symfony package.
6 * (c) Fabien Potencier <fabien@symfony.com>
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Symfony\Component\Console\Input;
15 * ArgvInput represents an input coming from the CLI arguments.
19 * $input = new ArgvInput();
21 * By default, the `$_SERVER['argv']` array is used for the input values.
23 * This can be overridden by explicitly passing the input values in the constructor:
25 * $input = new ArgvInput($_SERVER['argv']);
27 * If you pass it yourself, don't forget that the first element of the array
28 * is the name of the running application.
30 * When passing an argument to the constructor, be sure that it respects
31 * the same rules as the argv one. It's almost always better to use the
32 * `StringInput` when you want to provide your own input.
34 * @author Fabien Potencier <fabien@symfony.com>
36 * @see http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html
37 * @see http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap12.html#tag_12_02
41 class ArgvInput extends Input
49 * @param array $argv An array of parameters from the CLI (in the argv format)
50 * @param InputDefinition $definition A InputDefinition instance
54 public function __construct(array $argv = null, InputDefinition $definition = null)
57 $argv = $_SERVER['argv'];
60 // strip the application name
63 $this->tokens = $argv;
65 parent::__construct($definition);
68 protected function setTokens(array $tokens)
70 $this->tokens = $tokens;
74 * Processes command line arguments.
76 protected function parse()
79 $this->parsed = $this->tokens;
80 while (null !== $token = array_shift($this->parsed)) {
81 if ($parseOptions && '' == $token) {
82 $this->parseArgument($token);
83 } elseif ($parseOptions && '--' == $token) {
84 $parseOptions = false;
85 } elseif ($parseOptions && 0 === strpos($token, '--')) {
86 $this->parseLongOption($token);
87 } elseif ($parseOptions && '-' === $token[0]) {
88 $this->parseShortOption($token);
90 $this->parseArgument($token);
96 * Parses a short option.
98 * @param string $token The current token.
100 private function parseShortOption($token)
102 $name = substr($token, 1);
104 if (strlen($name) > 1) {
105 if ($this->definition->hasShortcut($name[0]) && $this->definition->getOptionForShortcut($name[0])->acceptValue()) {
106 // an option with a value (with no space)
107 $this->addShortOption($name[0], substr($name, 1));
109 $this->parseShortOptionSet($name);
112 $this->addShortOption($name, null);
117 * Parses a short option set.
119 * @param string $name The current token
121 * @throws \RuntimeException When option given doesn't exist
123 private function parseShortOptionSet($name)
125 $len = strlen($name);
126 for ($i = 0; $i < $len; $i++) {
127 if (!$this->definition->hasShortcut($name[$i])) {
128 throw new \RuntimeException(sprintf('The "-%s" option does not exist.', $name[$i]));
131 $option = $this->definition->getOptionForShortcut($name[$i]);
132 if ($option->acceptValue()) {
133 $this->addLongOption($option->getName(), $i === $len - 1 ? null : substr($name, $i + 1));
137 $this->addLongOption($option->getName(), true);
143 * Parses a long option.
145 * @param string $token The current token
147 private function parseLongOption($token)
149 $name = substr($token, 2);
151 if (false !== $pos = strpos($name, '=')) {
152 $this->addLongOption(substr($name, 0, $pos), substr($name, $pos + 1));
154 $this->addLongOption($name, null);
159 * Parses an argument.
161 * @param string $token The current token
163 * @throws \RuntimeException When too many arguments are given
165 private function parseArgument($token)
167 $c = count($this->arguments);
169 // if input is expecting another argument, add it
170 if ($this->definition->hasArgument($c)) {
171 $arg = $this->definition->getArgument($c);
172 $this->arguments[$arg->getName()] = $arg->isArray()? array($token) : $token;
174 // if last argument isArray(), append token to last argument
175 } elseif ($this->definition->hasArgument($c - 1) && $this->definition->getArgument($c - 1)->isArray()) {
176 $arg = $this->definition->getArgument($c - 1);
177 $this->arguments[$arg->getName()][] = $token;
179 // unexpected argument
181 throw new \RuntimeException('Too many arguments.');
186 * Adds a short option value.
188 * @param string $shortcut The short option key
189 * @param mixed $value The value for the option
191 * @throws \RuntimeException When option given doesn't exist
193 private function addShortOption($shortcut, $value)
195 if (!$this->definition->hasShortcut($shortcut)) {
196 throw new \RuntimeException(sprintf('The "-%s" option does not exist.', $shortcut));
199 $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);
203 * Adds a long option value.
205 * @param string $name The long option key
206 * @param mixed $value The value for the option
208 * @throws \RuntimeException When option given doesn't exist
210 private function addLongOption($name, $value)
212 if (!$this->definition->hasOption($name)) {
213 throw new \RuntimeException(sprintf('The "--%s" option does not exist.', $name));
216 $option = $this->definition->getOption($name);
218 if (null === $value && $option->acceptValue()) {
219 // if option accepts an optional or mandatory argument
220 // let's see if there is one provided
221 $next = array_shift($this->parsed);
222 if ('-' !== $next[0]) {
225 array_unshift($this->parsed, $next);
229 if (null === $value) {
230 if ($option->isValueRequired()) {
231 throw new \RuntimeException(sprintf('The "--%s" option requires a value.', $name));
234 $value = $option->isValueOptional() ? $option->getDefault() : true;
237 if ($option->isArray()) {
238 $this->options[$name][] = $value;
240 $this->options[$name] = $value;
245 * Returns the first argument from the raw parameters (not parsed).
247 * @return string The value of the first argument or null otherwise
249 public function getFirstArgument()
251 foreach ($this->tokens as $token) {
252 if ($token && '-' === $token[0]) {
261 * Returns true if the raw parameters (not parsed) contain a value.
263 * This method is to be used to introspect the input parameters
264 * before they have been validated. It must be used carefully.
266 * @param string|array $values The value(s) to look for in the raw parameters (can be an array)
268 * @return Boolean true if the value is contained in the raw parameters
270 public function hasParameterOption($values)
272 $values = (array) $values;
274 foreach ($this->tokens as $v) {
275 if (in_array($v, $values)) {
284 * Returns the value of a raw option (not parsed).
286 * This method is to be used to introspect the input parameters
287 * before they have been validated. It must be used carefully.
289 * @param string|array $values The value(s) to look for in the raw parameters (can be an array)
290 * @param mixed $default The default value to return if no result is found
292 * @return mixed The option value
294 public function getParameterOption($values, $default = false)
296 $values = (array) $values;
298 $tokens = $this->tokens;
299 while ($token = array_shift($tokens)) {
300 foreach ($values as $value) {
301 if (0 === strpos($token, $value)) {
302 if (false !== $pos = strpos($token, '=')) {
303 return substr($token, $pos + 1);
306 return array_shift($tokens);