data = self::extract($options, $values); $this->options = $options; } /** * Has Option * * Wheter an option with name $optionName is extracted. * * @param string $optionName */ public function has($optionName) { return isset($this->data[$optionName]); } /** * Get Option * * Returns the value of option with name $optionName. In case of * such a value does not exist, null is returned. * * @return mixed */ public function get($optionName) { return ($this->has($optionName)) ? $this->data[$optionName] : null; } /** * Get Options * * Get all options. * * @return array */ public function getOptions() { return $this->options; } /** * Is Flag * * Wheter an option with name $optionName is a flag. */ public function isFlag($optionName) { return isset($this->options[$optionName]) && !empty($this->options[$optionName]['flag']); } private static function extract(array $options, array $values) { $returnValue = []; foreach ($options as $optionName => $optionParams) { // Ignore non string-indexed options. if (is_string($optionName)) { $prefix = empty($optionParams['prefix']) ? '' : $optionParams['prefix']; $longPrefix = empty($optionParams['longPrefix']) ? '' : $optionParams['longPrefix']; if (empty($prefix) && empty($longPrefix)) { throw new \LogicException("Argument with name '${optionName}' has no prefix, nor long prefix."); } if (!empty($optionParams['flag'])) { // It's a flag! if (is_int(self::searchOptionIndex($prefix, $longPrefix, $values))) { $returnValue[$optionName] = true; } } else { // It's a regular option! $required = empty($optionParams['required']) ? false : true; $castTo = empty($optionParams['cast']) ? null : $optionParams['cast']; $optionIndex = self::searchOptionIndex($prefix, $longPrefix, $values); if ($required && $optionIndex === false) { throw new MissingOptionException("Required argument '${optionName}' is missing.", $optionName); } if ($optionIndex === false && isset($optionParams['defaultValue'])) { $returnValue[$optionName] = self::cast($optionParams['defaultValue'], $castTo); } else { $valueIndex = $optionIndex + 1; if ($optionIndex !== false && isset($values[$valueIndex])) { $returnValue[$optionName] = self::cast($values[$valueIndex], $castTo); } else { // Edge case. Option found, but it is the last value of the $value array. if ($required) { throw new MissingOptionException("No value given for required argument '${optionName}'.", $optionName); } elseif (isset($optionParams['defaultValue'])) { $returnValue[$optionName] = self::cast($optionParams['defaultValue'], $castTo); } } } } } } return $returnValue; } private static function searchOptionIndex($prefix, $longPrefix, array $values) { $optionIndex = false; $prefixes = [$prefix, $longPrefix]; for ($i = 0; $i < count($prefixes); $i++) { $dashes = str_repeat('-', $i + 1); $p = $prefixes[$i]; if (!empty($p)) { if (($search = array_search("${dashes}${p}", $values)) !== false) { $optionIndex = $search; break; } } } return $optionIndex; } private static function cast($value, $to) { $casted = $value; if (is_string($to)) { switch (strtolower($to)) { case 'integer': case 'int': $casted = @intval($value); break; case 'float': $casted = @floatval($value); break; case 'string': $casted = @strval($value); break; case 'boolean': case 'bool': $casted = @boolval($value); break; } } return $casted; } }