# Args

In questo esempio vedremo la costruzione della classe `Args`, la quale, data in input una stringa di formattazione e degli argomenti, e poi possibile interrogarla chiedendole il valore degli argomenti.

### **ArgumentMarshaler**

```
<?php

interface ArgumentMarshaler
{
    /**
     * @param ArgumentMarshaler $am
     * @return mixed
     */
    public static function getValue(ArgumentMarshaler $am);

    /**
     * @param mixed $currentArgument
     * @return void
     */
    public function set($currentArgument): void;
}
```

### **BooleanArgumentMarshaler**

```
<?php
include_once('ArgumentMarshaler.php');

class BooleanArgumentMarshaler implements ArgumentMarshaler
{
    /** @var bool */
    private $value = false;

    /**
     * @param ArgumentMarshaler $am
     * @return bool
     */
    public static function getValue(ArgumentMarshaler $am)
    {
        if ($am instanceof BooleanArgumentMarshaler) {
            return $am->value;
        }

        return false;
    }

    /**
     * {@inheritDoc}
     */
    public function set($currentArgument): void
    {
        $this->value = true;
    }
}
```

### **FloatArgumentMarshaler**

```
<?php
include_once('ArgumentMarshaler.php');

class FloatArgumentMarshaler implements ArgumentMarshaler
{
    public const SYMBOL = '##';

    /** @var float */
    private $value = 0.0;

    /**
     * @param ArgumentMarshaler $am
     * @return float
     */
    public static function getValue(ArgumentMarshaler $am)
    {
        if ($am instanceof FloatArgumentMarshaler) {
            return $am->value;
        }

        return 0.0;
    }

    /**
     * {@inheritDoc}
     */
    public function set($currentArgument): void
    {
        $this->value = (float)$currentArgument;
    }
}
```

### **IntegerArgumentMarshaler**

```
<?php
include_once('ArgumentMarshaler.php');

class IntegerArgumentMarshaler implements ArgumentMarshaler
{
    public const SYMBOL = '#';

    /** @var int */
    private $value = 0;

    /**
     * @param ArgumentMarshaler $am
     * @return int
     */
    public static function getValue(ArgumentMarshaler $am)
    {
        if ($am instanceof IntegerArgumentMarshaler) {
            return $am->value;
        }

        return 0;
    }

    /**
     * {@inheritDoc}
     */
    public function set($currentArgument): void
    {
        $this->value = (int)$currentArgument;
    }
}
```

### **StringArgumentMarshaler**

```
<?php
include_once('ArgumentMarshaler.php');

class StringArgumentMarshaler implements ArgumentMarshaler
{
    public const SYMBOL = '*';

    /** @var string */
    private $value = '';

    /**
     * @param ArgumentMarshaler $am
     * @return string
     */
    public static function getValue(ArgumentMarshaler $am)
    {
        if ($am instanceof StringArgumentMarshaler) {
            return $am->value;
        }

        return '';
    }

    /**
     * {@inheritDoc}
     */
    public function set($currentArgument): void
    {
        $this->value = (string)$currentArgument;
    }
}
```

### **ArgumentMarshalerCollection**

```
<?php
include_once('ArgsException.php');
include_once('ArgumentMarshaler.php');

class ArgumentMarshalerCollection
{
    /** @var array */
    private $array = [];

    /**
     * @param string $elementId
     * @return ArgumentMarshaler
     * @throws ArgsException
     */
    public function get(string $elementId): ArgumentMarshaler
    {
        if (!isset($this->array[$elementId])) {
            throw new ArgsException(ArgsException::UNEXPECTED_ARGUMENT, $elementId);
        }

        return $this->array[$elementId];
    }

    /**
     * @param string $elementId
     * @param ArgumentMarshaler $am
     * @return void
     */
    public function put(string $elementId, ArgumentMarshaler $am): void
    {
        $this->array[$elementId] = $am;
    }
}
```

### **ArgsException**

```
<?php

class ArgsException extends Exception
{
    public const INVALID_ARGUMENT_FORMAT = 1;
    public const UNEXPECTED_ARGUMENT = 2;
    public const INVALID_ARGUMENT_NAME = 3;

    /** @var string|null */
    private $argumentId;

    /** @var string|null */
    private $parameter;

    /**
     * ArgsException constructor.
     * @param int $code
     * @param string|null $argumentId
     * @param string|null $parameter
     */
    public function __construct(int $code, string $argumentId = null, string $parameter = null)
    {
        $this->code = $code;
        $this->argumentId = $argumentId;
        $this->parameter = $parameter;
        parent::__construct($this->formatErrorMessage(), $code);
    }

    /**
     * @return string|null
     */
    public function getArgumentId(): ?string
    {
        return $this->argumentId;
    }

    /**
     * @return string|null
     */
    public function getParameter(): ?string
    {
        return $this->parameter;
    }

    /**
     * @return string
     */
    private function formatErrorMessage(): string
    {
        switch ($this->code) {
            case self::INVALID_ARGUMENT_FORMAT:
                return sprintf('`%s` is not a valid argument format.', $this->parameter);
            case self::UNEXPECTED_ARGUMENT:
                return sprintf('Argument -%s unexpected.', $this->argumentId);
            case self::INVALID_ARGUMENT_NAME:
                return sprintf('`%s` is not a valid argument name.', $this->argumentId);
            default:
                return 'TILT: Should not get here.';
        }
    }
}
```

### **Args**

```
<?php
include_once('ArgsException.php');
include_once('ArgumentMarshaler/ArgumentMarshalerCollection.php');
include_once('ArgumentMarshaler/BooleanArgumentMarshaler.php');
include_once('ArgumentMarshaler/FloatArgumentMarshaler.php');
include_once('ArgumentMarshaler/IntegerArgumentMarshaler.php');
include_once('ArgumentMarshaler/StringArgumentMarshaler.php');

class Args
{
    private const SCHEMA_SEPARATOR = ',';

    /** @var ArgumentMarshalerCollection */
    private $marshalers;

    /** @var string[] */
    private $args = [];

    /** @var string[] */
    private $argsFound = [];

    /**
     * Args constructor.
     * @param string $schema
     * @param string[] $args
     * @throws ArgsException
     */
    public function __construct(string $schema, array $args)
    {
        $this->marshalers = new ArgumentMarshalerCollection();
        $this->args = $args;
        $this->parseSchema($schema);
        $this->parseArgumentStrings();
    }

    /**
     * @param string $schema
     * @return void
     * @throws ArgsException
     */
    private function parseSchema(string $schema): void
    {
        $elements = explode(self::SCHEMA_SEPARATOR, $schema);
        foreach ($elements as $element) {
            if (strlen($element) > 0) {
                $this->parseSchemaElement(trim($element));
            }
        }
    }

    /**
     * @param string $element
     * @return void
     * @throws ArgsException
     */
    private function parseSchemaElement(string $element): void
    {
        $elementId = $element[0];
        $elementTail = substr($element, 1);
        $this->validateSchemaElementId($elementId);
        if (strlen($elementTail) === 0) {
            $this->marshalers->put($elementId, new BooleanArgumentMarshaler());
        } elseif ($elementTail === StringArgumentMarshaler::SYMBOL) {
            $this->marshalers->put($elementId, new StringArgumentMarshaler());
        } elseif ($elementTail === IntegerArgumentMarshaler::SYMBOL) {
            $this->marshalers->put($elementId, new IntegerArgumentMarshaler());
        } elseif ($elementTail === FloatArgumentMarshaler::SYMBOL) {
            $this->marshalers->put($elementId, new FloatArgumentMarshaler());
        } else {
            throw new ArgsException(ArgsException::INVALID_ARGUMENT_FORMAT, $elementId, $elementTail);
        }
    }

    /**
     * @param string $elementId
     * @return void
     * @throws ArgsException
     */
    private function validateSchemaElementId(string $elementId): void
    {
        if (!ctype_alpha($elementId)) {
            throw new ArgsException(ArgsException::INVALID_ARGUMENT_NAME, $elementId);
        }
    }

    /**
     * @return void
     * @throws ArgsException
     */
    private function parseArgumentStrings(): void
    {
        foreach ($this->args as $arg) {
            if (substr($arg, 0, 1) === '-') {
                $this->parseArgumentCharacters(substr($arg, 1));
            }
        }
    }

    /**
     * @param string $argChars
     * @return void
     * @throws ArgsException
     */
    private function parseArgumentCharacters(string $argChars): void
    {
        for ($i = 0; $i < strlen($argChars); $i++) {
            $this->parseArgumentCharacter($argChars[$i]);
        }
    }

    /**
     * @param string $argChar
     * @return void
     * @throws ArgsException
     */
    private function parseArgumentCharacter(string $argChar): void
    {
        $am = $this->marshalers->get($argChar);
        $am->set(next($this->args));
        $this->argsFound[] = $argChar;
    }

    /**
     * @param string $arg
     * @return bool
     */
    public function has(string $arg): bool
    {
        return in_array($arg, $this->argsFound);
    }

    /**
     * @param string $arg
     * @return bool
     * @throws ArgsException
     */
    public function getBoolean(string $arg): bool
    {
        return BooleanArgumentMarshaler::getValue($this->marshalers->get($arg));
    }

    /**
     * @param string $arg
     * @return string
     * @throws ArgsException
     */
    public function getString(string $arg): string
    {
        return StringArgumentMarshaler::getValue($this->marshalers->get($arg));
    }

    /**
     * @param string $arg
     * @return int
     * @throws ArgsException
     */
    public function getInteger(string $arg): int
    {
        return IntegerArgumentMarshaler::getValue($this->marshalers->get($arg));
    }

    /**
     * @param string $arg
     * @return float
     * @throws ArgsException
     */
    public function getFloat(string $arg): float
    {
        return FloatArgumentMarshaler::getValue($this->marshalers->get($arg));
    }
}
```

### **Index**

```
<?php
include_once('Args.php');

try {
    $args = new Args('l,p#,d*,x##', ['-lpdx', true, 42, 'param', 16.5]);

    var_dump($args->getBoolean('l'));
    var_dump($args->getInteger('p'));
    var_dump($args->getString('d'));
    var_dump($args->getFloat('x'));
} catch (ArgsException $e) {
    var_dump($e->getMessage());
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://mirkorap16.gitbook.io/clean-code/esempi/args.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
