# fix: do not read an undefined offset when a value argument is last ## Problem When an argument that expects a value is the last token on the command line and is preceded by an unconsumed non-prefixed token, the parser emits an `Undefined array key` warning under PHP 8: ```php $climate = new League\CLImate\CLImate(); $climate->arguments->add([ 'name' => ['prefix' => 'n', 'longPrefix' => 'name', 'defaultValue' => 'default-name'], ]); $climate->arguments->parse(['script', 'somefile', '-n']); // PHP Warning: Undefined array key 2 in Parser.php on line 270 ``` On top of the warning, the argument is then set to an empty value instead of falling back to its configured default, which is inconsistent with the behaviour when a value argument is the only remaining token (that case correctly falls back to the default). ## Root cause `src/Argument/Parser.php`, `setArgumentValue()`: ```php if (is_null($value)) { if (count($argv) === 0) { return $argv; } // If the value wasn't previously defined in "key=value" // format then define it from the next command argument. $nextArgvValue = $argv[$key + 1]; ... } ``` The remaining arguments array is not reindexed after previously matched arguments are removed with `unset()`. `count($argv) === 0` is therefore not a reliable test for "there is no following token": when an unconsumed token still sits at another offset (for example `somefile` at offset 0), `count($argv)` is non-zero even though offset `$key + 1` does not exist, so `$argv[$key + 1]` reads an undefined key. ## The fix Check that the next offset actually exists instead of relying on the overall count. When there is no following token the method returns without setting a value, so the argument falls back to its default (matching the existing last-token behaviour): ```php if (is_null($value)) { if (!isset($argv[$key + 1])) { return $argv; } $nextArgvValue = $argv[$key + 1]; if ($this->isValidArgumentValue($nextArgvValue)) { $argument->setValue($nextArgvValue); unset($argv[$key + 1]); return $argv; } } ``` ## Test Added `ManagerTest::testItParsesAValueTakingArgumentThatIsLastWithoutAWarning`, which installs an error handler that turns any warning into an exception, parses `['command', 'somefile', '-n']`, and asserts that no warning is raised and the argument falls back to its default value. ## Gate ``` composer install && composer test ``` `composer test` runs `vendor/bin/phpunit`. Result: exit code `0` - `OK (274 tests, 152 assertions)`. Counterfactual: reverting `setArgumentValue()` to the `count($argv) === 0` guard makes the new test fail with `ErrorException: Undefined array key 2` raised at `Parser.php:270`.