From 532d9bf88bb7b7267e9e1b7c2a2d95ed9c35fb3c Mon Sep 17 00:00:00 2001 From: Jesse Donat Date: Thu, 18 Jun 2026 19:21:30 -0500 Subject: [PATCH 1/3] Add editorconfig --- .editorconfig | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..276f6d3 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,4 @@ +[*.php] +charset = utf-8 +indent_style = tab +indent_size = 4 From a88a8a7ecf18c72a7c7cacd1d037c3f49db7fe37 Mon Sep 17 00:00:00 2001 From: Jesse Donat Date: Thu, 18 Jun 2026 19:21:58 -0500 Subject: [PATCH 2/3] Set up phpstan at level 9 --- .github/workflows/ci.yml | 4 ++- .gitignore | 1 + composer.json | 3 +- phpstan.neon | 4 +++ src/Flags.php | 73 ++++++++++++++++++++++------------------ 5 files changed, 51 insertions(+), 34 deletions(-) create mode 100644 phpstan.neon diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7a6683a..1f970a2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,10 +23,12 @@ jobs: uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php-versions }} - extensions: sockets, json, curl - name: Install dependencies with composer run: composer install - name: Run tests run: ./vendor/bin/phpunit + + - name: Run static analysis + run: ./vendor/bin/phpstan diff --git a/.gitignore b/.gitignore index c7101f0..b00b4dc 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ vendor/ .idea/ clover.xml phpunit.xml +*.cache diff --git a/composer.json b/composer.json index 3aa34a3..2607361 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,8 @@ ], "require-dev": { "donatj/drop": "*", - "phpunit/phpunit": "^9 || ^10" + "phpunit/phpunit": "^9 || ^10", + "phpstan/phpstan": "^2.2" }, "license": "MIT", "authors": [ diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000..c158993 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,4 @@ +parameters: + level: 9 + paths: + - src diff --git a/src/Flags.php b/src/Flags.php index 5b5917c..89ad03f 100644 --- a/src/Flags.php +++ b/src/Flags.php @@ -5,19 +5,26 @@ use donatj\Exceptions\InvalidFlagParamException; use donatj\Exceptions\InvalidFlagTypeException; use donatj\Exceptions\MissingFlagParamException; +use function PHPStan\dumpType; class Flags { - /** @var array | null */ - protected $args; + /** @var list */ + protected array $args ; /** @var bool */ - protected $skipFirstArgument; - - private $definedFlags = []; - private $definedShortFlags = []; - private $arguments = []; - private $parsed = false; + protected bool $skipFirstArgument; + /** + * @var array + */ + private array $definedFlags = []; + /** + * @var array + */ + private array $definedShortFlags = []; + /** @var list */ + private array $arguments = []; + private bool $parsed = false; /** @access private */ const DEF_TYPE = 'type'; @@ -44,7 +51,7 @@ class Flags { /** * Flags constructor. * - * @param array|null $args The arguments to parse, defaults to $_SERVER['argv'] + * @param array|null $args The arguments to parse, defaults to $_SERVER['argv'] * @param bool $skipFirstArgument Setting to false causes the first argument to be parsed as an parameter * rather than the command. */ @@ -53,17 +60,17 @@ public function __construct( ?array $args = null, $skipFirstArgument = true ) { $args = (array)$_SERVER['argv']; } - $this->args = $args; - $this->skipFirstArgument = $skipFirstArgument; + $this->args = array_values($args ?? []); // @phpstan-ignore assign.propertyType (this is fine for now) + $this->skipFirstArgument = (bool)$skipFirstArgument; } /** * Returns the n'th command-line argument. `arg(0)` is the first remaining argument after flags have been processed. * * @param int $index - * @return string + * @return string|null */ - public function arg( $index ) { + public function arg( $index ) : ?string { return isset($this->arguments[$index]) ? $this->arguments[$index] : null; } @@ -72,7 +79,7 @@ public function arg( $index ) { * * @return string[] Array of argument strings */ - public function args() { + public function args() : array { return $this->arguments; } @@ -81,9 +88,9 @@ public function args() { * * `-v` would set the 'v' index to 1, whereas `-vvv` will set the 'v' index to 3 * - * @return array + * @return array map of short value to instances */ - public function shorts() { + public function shorts() : array { $out = []; foreach( $this->definedShortFlags as $key => $data ) { $out[$key] = $data[self::DEF_VALUE]; @@ -95,9 +102,9 @@ public function shorts() { /** * Returns an array of long-flag values indexed by flag name * - * @return array + * @return array */ - public function longs() { + public function longs() : array { $out = []; foreach( $this->definedFlags as $key => $data ) { $out[$key] = $data[self::DEF_VALUE]; @@ -240,7 +247,7 @@ public function &string( $name, $value = null, $usage = '' ) { * @param string $usage * @return mixed */ - private function &storeFlag( $type, $name, $value, $usage ) { + private function &storeFlag( $type, $name, $value, $usage ) : mixed { $this->definedFlags[$name] = [ self::DEF_TYPE => $type, @@ -301,7 +308,7 @@ public function getDefaults() { * * Will throw exceptions on Missing Require Flags, Unknown Flags or Incorrect Flag Types * - * @param array|null $args The arguments to parse. Defaults to arguments defined in the constructor. + * @param array|null $args The arguments to parse. Defaults to arguments defined in the constructor. * @param bool $ignoreExceptions Setting to true causes parsing to continue even after an exception has been * thrown. * @param bool $skipFirstArgument Option to parse the first argument as an parameter rather than the command. @@ -310,9 +317,11 @@ public function getDefaults() { * @throws Exceptions\InvalidFlagParamException * @throws Exceptions\InvalidFlagTypeException */ - public function parse( ?array $args = null, $ignoreExceptions = false, $skipFirstArgument = null ) { + public function parse( ?array $args = null, $ignoreExceptions = false, $skipFirstArgument = null ) : void { if( $args === null ) { $args = $this->args; + }else{ + $args = array_values($args); } if( $skipFirstArgument === null ) { @@ -368,7 +377,7 @@ public function parse( ?array $args = null, $ignoreExceptions = false, $skipFirs * * @return bool */ - public function parsed() { + public function parsed() : bool { return $this->parsed; } @@ -379,7 +388,7 @@ public function parsed() { */ private function validateType( $type, &$value ) : bool { $validate = [ - self::TYPE_BOOL => function ( &$val ) { + self::TYPE_BOOL => function( &$val ) { $val = strtolower((string)$val); if( $val == '0' || $val == 'f' || $val == 'false' ) { $val = false; @@ -394,7 +403,7 @@ private function validateType( $type, &$value ) : bool { return false; }, - self::TYPE_UINT => function ( &$val ) { + self::TYPE_UINT => function( &$val ) { if( abs((float)$val) == (int)$val ) { $val = (int)$val; @@ -403,7 +412,7 @@ private function validateType( $type, &$value ) : bool { return false; }, - self::TYPE_INT => function ( &$val ) { + self::TYPE_INT => function( &$val ) { if( is_numeric($val) && floatval($val) == intval($val) ) { $val = intval($val); @@ -412,7 +421,7 @@ private function validateType( $type, &$value ) : bool { return false; }, - self::TYPE_FLOAT => function ( &$val ) { + self::TYPE_FLOAT => function( &$val ) { if( is_numeric($val) ) { $val = floatval($val); @@ -421,7 +430,7 @@ private function validateType( $type, &$value ) : bool { return false; }, - self::TYPE_STRING => function ( &$val ) { + self::TYPE_STRING => function( &$val ) { if( $val !== true ) { $val = (string)$val; @@ -438,9 +447,9 @@ private function validateType( $type, &$value ) : bool { } /** - * @param array $args - * @param array $definedFlags - * @return array + * @param list $args + * @param array $definedFlags + * @return array{array<0|string, string|true>, array>, list} */ protected function splitArguments( array $args, array $definedFlags ) : array { $longParams = []; @@ -451,7 +460,7 @@ protected function splitArguments( array $args, array $definedFlags ) : array { $getValue = false; $startArgs = false; foreach( $args as $arg ) { - if( isset($arg[0]) && $arg[0] == '-' && !$startArgs && !$forceValue && $arg !== '-' ) { + if( isset($arg[0]) && $arg[0] === '-' && !$startArgs && !$forceValue && $arg !== '-' ) { $cleanArg = ltrim($arg, '- '); if( $getValue ) { @@ -470,7 +479,7 @@ protected function splitArguments( array $args, array $definedFlags ) : array { } else { $getValue = $cleanArg; - if( isset($definedFlags[$cleanArg]) && $definedFlags[$cleanArg][self::DEF_TYPE] != self::TYPE_BOOL ) { + if( isset($definedFlags[$cleanArg]) && $definedFlags[$cleanArg][self::DEF_TYPE] !== self::TYPE_BOOL ) { $forceValue = true; } } From b33dd3ddf9c63734e2684950c90a13770e3f2849 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 19 Jun 2026 00:30:09 +0000 Subject: [PATCH 3/3] fix: restore PHP 7.4 compatibility --- src/Flags.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Flags.php b/src/Flags.php index 89ad03f..c8a92b7 100644 --- a/src/Flags.php +++ b/src/Flags.php @@ -247,7 +247,7 @@ public function &string( $name, $value = null, $usage = '' ) { * @param string $usage * @return mixed */ - private function &storeFlag( $type, $name, $value, $usage ) : mixed { + private function &storeFlag( $type, $name, $value, $usage ) { $this->definedFlags[$name] = [ self::DEF_TYPE => $type,