From b2efd91008fbebfa2f4db05112301a8833b63a04 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Tue, 5 Apr 2022 20:01:46 +0200 Subject: [PATCH] static code analysis fixes --- Ai/Ocr/BasicOcr.php | 4 +- Algorithm/PathFinding/AStar.php | 4 +- Algorithm/PathFinding/Grid.php | 2 + Algorithm/PathFinding/Path.php | 8 ---- .../Database/Mapper/DataMapperAbstract.php | 10 ++--- DataStorage/Database/Mapper/ReadMapper.php | 42 +++++++++---------- Dispatcher/Dispatcher.php | 2 +- Event/EventManager.php | 4 +- Localization/L11nManager.php | 4 +- Math/Matrix/Matrix.php | 12 ++++-- Math/Stochastic/NaiveBayesClassifier.php | 8 ---- Message/Http/HttpRequest.php | 4 +- Module/ModuleAbstract.php | 2 +- Module/ModuleManager.php | 9 +++- Module/StatusAbstract.php | 4 -- Stdlib/Base/Enum.php | 2 +- System/File/FileUtils.php | 4 +- System/File/Local/Directory.php | 2 +- System/File/Storage.php | 5 ++- System/SystemUtils.php | 2 +- Uri/Argument.php | 2 +- Uri/UriFactory.php | 28 +++++++------ Utils/Compression/LZW.php | 2 +- Utils/Converter/Ip.php | 8 ++-- Utils/Git/Repository.php | 4 +- Views/View.php | 2 +- composer.json | 2 +- 27 files changed, 88 insertions(+), 94 deletions(-) diff --git a/Ai/Ocr/BasicOcr.php b/Ai/Ocr/BasicOcr.php index 68d3fa6ab..c7b03300a 100644 --- a/Ai/Ocr/BasicOcr.php +++ b/Ai/Ocr/BasicOcr.php @@ -107,12 +107,12 @@ final class BasicOcr if (($read = \fread($fp, 4)) === false || ($unpack = \unpack('N', $read)) === false) { return []; // @codeCoverageIgnore } - $numberOfRows = $unpack[1]; + $numberOfRows = (int) $unpack[1]; if (($read = \fread($fp, 4)) === false || ($unpack = \unpack('N', $read)) === false) { return []; // @codeCoverageIgnore } - $numberOfColumns = $unpack[1]; + $numberOfColumns = (int) $unpack[1]; $images = []; for ($i = 0; $i < $numberOfImages; ++$i) { diff --git a/Algorithm/PathFinding/AStar.php b/Algorithm/PathFinding/AStar.php index 2bdc19394..3726e82a4 100644 --- a/Algorithm/PathFinding/AStar.php +++ b/Algorithm/PathFinding/AStar.php @@ -83,7 +83,9 @@ final class AStar implements PathFinderInterface if (!$neighbor->isOpened() || $ng < $neighbor->getG()) { $neighbor->setG($ng); - $neighbor->setH($neighbor->getG() ?? $neighbor->getWeight() * Heuristic::metric($neighbor->getCoordinates(), $endNode->getCoordinates(), $heuristic)); + $neighbor->setH($neighbor->getH() ?? ( + $neighbor->getWeight() * Heuristic::metric($neighbor->getCoordinates(), $endNode->getCoordinates(), $heuristic) + )); $neighbor->setF($neighbor->getG() + $neighbor->getH()); $neighbor->parent = $node; diff --git a/Algorithm/PathFinding/Grid.php b/Algorithm/PathFinding/Grid.php index bb429c1dd..330cd1831 100755 --- a/Algorithm/PathFinding/Grid.php +++ b/Algorithm/PathFinding/Grid.php @@ -71,9 +71,11 @@ class Grid foreach ($gridArray as $y => $yRow) { foreach ($yRow as $x => $xElement) { if ($xElement === 0 || $xElement === 1 || $xElement === 2) { + /** @var \phpOMS\Algorithm\PathFinding\Node $empty */ $empty = new $node($x, $y, 1.0, true); $grid->setNode($x, $y, $empty); } elseif ($xElement === 9) { + /** @var \phpOMS\Algorithm\PathFinding\Node $wall */ $wall = new $node($x, $y, 1.0, false); $grid->setNode($x, $y, $wall); } diff --git a/Algorithm/PathFinding/Path.php b/Algorithm/PathFinding/Path.php index 38c7dad82..a5f3b6be1 100644 --- a/Algorithm/PathFinding/Path.php +++ b/Algorithm/PathFinding/Path.php @@ -53,14 +53,6 @@ class Path */ private array $expandedNodes = []; - /** - * Path length - * - * @var float - * @since 1.0.0 - */ - private float $length = 0.0; - /** * Cosntructor. * diff --git a/DataStorage/Database/Mapper/DataMapperAbstract.php b/DataStorage/Database/Mapper/DataMapperAbstract.php index a884a17f8..8a3711a0e 100644 --- a/DataStorage/Database/Mapper/DataMapperAbstract.php +++ b/DataStorage/Database/Mapper/DataMapperAbstract.php @@ -156,7 +156,7 @@ abstract class DataMapperAbstract $split = \explode('/', $member); $memberSplit = \array_shift($split); - $this->with[$memberSplit ?? ''][] = [ + $this->with[$memberSplit][] = [ 'child' => \implode('/', $split), ]; @@ -178,7 +178,7 @@ abstract class DataMapperAbstract $split = \explode('/', $member); $memberSplit = \array_shift($split); - $this->sort[$memberSplit ?? ''][] = [ + $this->sort[$memberSplit][] = [ 'child' => \implode('/', $split), 'order' => $order, ]; @@ -201,7 +201,7 @@ abstract class DataMapperAbstract $split = \explode('/', $member); $memberSplit = \array_shift($split); - $this->offset[$memberSplit ?? ''][] = [ + $this->offset[$memberSplit][] = [ 'child' => \implode('/', $split), 'offset' => $offset, ]; @@ -224,7 +224,7 @@ abstract class DataMapperAbstract $split = \explode('/', $member); $memberSplit = \array_shift($split); - $this->limit[$memberSplit ?? ''][] = [ + $this->limit[$memberSplit][] = [ 'child' => \implode('/', $split), 'limit' => $limit, ]; @@ -249,7 +249,7 @@ abstract class DataMapperAbstract $split = \explode('/', $member); $memberSplit = \array_shift($split); - $this->where[$memberSplit ?? ''][] = [ + $this->where[$memberSplit][] = [ 'child' => \implode('/', $split), 'value' => $value, 'logic' => $logic, diff --git a/DataStorage/Database/Mapper/ReadMapper.php b/DataStorage/Database/Mapper/ReadMapper.php index b09e5e4df..dae1b3195 100644 --- a/DataStorage/Database/Mapper/ReadMapper.php +++ b/DataStorage/Database/Mapper/ReadMapper.php @@ -155,19 +155,13 @@ final class ReadMapper extends DataMapperAbstract switch($this->type) { case MapperType::GET: /** @var null|Builder ...$options */ - return $options !== null - ? $this->executeGet(...$options) - : $this->executeGet(); + return $this->executeGet(...$options); case MapperType::GET_RAW: /** @var null|Builder ...$options */ - return $options !== null - ? $this->executeGetRaw(...$options) - : $this->executeGetRaw(); + return $this->executeGetRaw(...$options); case MapperType::GET_ALL: /** @var null|Builder ...$options */ - return $options !== null - ? $this->executeGetAll(...$options) - : $this->executeGetAll(); + return $this->executeGetAll(...$options); case MapperType::GET_RANDOM: return $this->executeGetRaw(); case MapperType::COUNT_MODELS: @@ -361,9 +355,9 @@ final class ReadMapper extends DataMapperAbstract $comparison = \is_array($where['value']) && \count($where['value']) > 1 ? 'in' : $where['logic']; $query->where($this->mapper::TABLE . '_d' . $this->depth . '.' . $col, $comparison, $where['value'], $where['comparison']); } - } elseif (isset($this->mapper::HAS_MANY[$member])) { - /* variable in has many */ - /* @todo: maybe needed in the future, but needs adjustment, doesn't make sense at the moment + } /* elseif (isset($this->mapper::HAS_MANY[$member])) { + // variable in has many + // @todo: maybe needed in the future, but needs adjustment, doesn't make sense at the moment foreach ($values as $where) { // @todo: the has many, etc. if checks only work if it is a relation on the first level, if we have a deeper where condition nesting this fails if ($where['child'] !== '') { @@ -388,10 +382,10 @@ final class ReadMapper extends DataMapperAbstract ); } } - */ - } elseif (isset($this->mapper::BELONGS_TO[$member])) { - /* variable in belogns to */ - /* @todo: maybe needed in the future, but needs adjustment, doesn't make sense at the moment + + } */ /* elseif (isset($this->mapper::BELONGS_TO[$member])) { + // variable in belogns to + // @todo: maybe needed in the future, but needs adjustment, doesn't make sense at the moment foreach ($values as $index => $where) { // @todo: the has many, etc. if checks only work if it is a relation on the first level, if we have a deeper where condition nesting this fails if ($where['child'] !== '') { @@ -408,10 +402,9 @@ final class ReadMapper extends DataMapperAbstract $this->mapper::BELONGS_TO[$member]['mapper']::TABLE . '_d' . $this->depth ); } - */ - } elseif (isset($this->mapper::OWNS_ONE[$member])) { - /* variable in owns one */ - /* @todo: maybe needed in the future, but needs adjustment, doesn't make sense at the moment + } */ /* elseif (isset($this->mapper::OWNS_ONE[$member])) { + // variable in owns one + // @todo: maybe needed in the future, but needs adjustment, doesn't make sense at the moment foreach ($values as $index => $where) { // @todo: the has many, etc. if checks only work if it is a relation on the first level, if we have a deeper where condition nesting this fails if ($where['child'] !== '') { @@ -427,8 +420,7 @@ final class ReadMapper extends DataMapperAbstract $this->mapper::OWNS_ONE[$member]['mapper']::TABLE . '_d' . $this->depth ); } - */ - } + } */ } // load relations @@ -806,7 +798,11 @@ final class ReadMapper extends DataMapperAbstract /** @var self $belongsToMapper */ $belongsToMapper = $this->createRelationMapper($mapper::get($this->db), $member); $belongsToMapper->depth = $this->depth + 1; - $belongsToMapper->where($this->mapper::BELONGS_TO[$member]['by'], $result[$mapper::getColumnByMember($this->mapper::BELONGS_TO[$member]['by']) . '_d' . $this->depth + 1], '='); + $belongsToMapper->where( + $this->mapper::BELONGS_TO[$member]['by'], + $result[$mapper::getColumnByMember($this->mapper::BELONGS_TO[$member]['by']) . '_d' . ($this->depth + 1)], + '=' + ); return $belongsToMapper->execute(); } diff --git a/Dispatcher/Dispatcher.php b/Dispatcher/Dispatcher.php index cd6db7af2..d59b58c4a 100644 --- a/Dispatcher/Dispatcher.php +++ b/Dispatcher/Dispatcher.php @@ -65,7 +65,7 @@ final class Dispatcher implements DispatcherInterface public function dispatch(array | string | \Closure $controller, ...$data) : array { $views = []; - $data = $data !== null ? \array_values($data) : null; + $data = \array_values($data); if (\is_array($controller) && isset($controller['dest'])) { if (!empty($controller['data'])) { diff --git a/Event/EventManager.php b/Event/EventManager.php index 34f0bc15f..fb87badda 100644 --- a/Event/EventManager.php +++ b/Event/EventManager.php @@ -257,8 +257,8 @@ final class EventManager implements \Countable $data, ]; - $data[':triggerGroup'] ??= $group; - $data[':triggerId'] = $id; + $data[':triggerGroup'] = $group; + $data[':triggerId'] = $id; } $this->dispatcher->dispatch($func, ...$data); diff --git a/Localization/L11nManager.php b/Localization/L11nManager.php index 0b41b6777..5f5f77c79 100644 --- a/Localization/L11nManager.php +++ b/Localization/L11nManager.php @@ -278,7 +278,7 @@ final class L11nManager */ public function getCurrency(Localization $l11n, int | float $currency, string $format = null, string $symbol = null, int $divide = 1) : string { - $language = $l11n->getLanguage() ?? 'en'; + $language = $l11n->getLanguage(); $symbol ??= $l11n->getCurrency(); if (\is_float($currency)) { @@ -299,7 +299,7 @@ final class L11nManager (int) ($currency / $divide), $l11n->getThousands(), $l11n->getDecimal(), - $symbol ?? $l11n->getCurrency(), + $symbol, (int) $l11n->getCurrencyFormat() ); diff --git a/Math/Matrix/Matrix.php b/Math/Matrix/Matrix.php index 0fd51886b..6d682e60c 100644 --- a/Math/Matrix/Matrix.php +++ b/Math/Matrix/Matrix.php @@ -704,7 +704,8 @@ class Matrix implements \ArrayAccess, \Iterator */ public function offsetGet($offset) { - $row = (int) ($offset / $this->m); + $offset = (int) $offset; + $row = (int) ($offset / $this->m); return $this->matrix[$row][$offset - $row * $this->n]; } @@ -738,7 +739,8 @@ class Matrix implements \ArrayAccess, \Iterator */ public function offsetExists($offset) : bool { - $row = (int) ($offset / $this->m); + $offset = (int) $offset; + $row = (int) ($offset / $this->m); return isset($this->matrix[$row][$offset - $row * $this->n]); } @@ -756,7 +758,8 @@ class Matrix implements \ArrayAccess, \Iterator */ public function offsetSet($offset, $value) : void { - $row = (int) ((int) $offset / $this->m); + $offset = (int) $offset; + $row = (int) ($offset / $this->m); $this->matrix[$row][$offset - $row * $this->n] = $value; } @@ -765,7 +768,8 @@ class Matrix implements \ArrayAccess, \Iterator */ public function offsetUnset($offset) : void { - $row = (int) ($offset / $this->m); + $offset = (int) $offset; + $row = (int) ($offset / $this->m); unset($this->matrix[$row][$offset - $row * $this->n]); } } diff --git a/Math/Stochastic/NaiveBayesClassifier.php b/Math/Stochastic/NaiveBayesClassifier.php index bd17ce80b..1c9829f71 100644 --- a/Math/Stochastic/NaiveBayesClassifier.php +++ b/Math/Stochastic/NaiveBayesClassifier.php @@ -34,14 +34,6 @@ final class NaiveBayesClassifier */ private array $dict = []; - /** - * Dictionary changed. - * - * @var bool - * @since 1.0.0 - */ - private bool $changed = true; - /** * Cached probabilities. * diff --git a/Message/Http/HttpRequest.php b/Message/Http/HttpRequest.php index e80905598..24e5c9343 100644 --- a/Message/Http/HttpRequest.php +++ b/Message/Http/HttpRequest.php @@ -107,8 +107,8 @@ final class HttpRequest extends RequestAbstract private function initCurrentRequest() : void { $this->uri = HttpUri::fromCurrent(); - $this->data = ($_GET ?? []) + ($_POST ?? []); - $this->files = $_FILES ?? []; + $this->data = $_GET + $_POST; + $this->files = $_FILES; $this->header->l11n->setLanguage($this->getRequestLanguage()); $this->initNonGetData(); diff --git a/Module/ModuleAbstract.php b/Module/ModuleAbstract.php index f1a8280b4..7762a8413 100644 --- a/Module/ModuleAbstract.php +++ b/Module/ModuleAbstract.php @@ -59,7 +59,7 @@ abstract class ModuleAbstract /** * Module id. * - * @var string + * @var int * @since 1.0.0 */ public const ID = 0; diff --git a/Module/ModuleManager.php b/Module/ModuleManager.php index 2125d2b53..ea55a3d2e 100644 --- a/Module/ModuleManager.php +++ b/Module/ModuleManager.php @@ -202,7 +202,11 @@ final class ModuleManager $content = \file_get_contents($path); $json = \json_decode($content === false ? '[]' : $content, true); - $this->active[$json['name']['internal']] = $json === false ? [] : $json; + if ($json === false) { + return []; + } + + $this->active[$json['name']['internal']] = $json; } } @@ -646,7 +650,8 @@ final class ModuleManager * @todo Remove docblock type hint hack "object". * The return type object is only used to stop the annoying warning that a method doesn't exist * if you chain call the methods part of the returned ModuleAbstract implementation. - * Remove it once alternative inline type hinting is possible for the specific returned implementation + * Remove it once alternative inline type hinting is possible for the specific returned implementation. + * This also causes phpstan type inspection errors, which we have to live with or ignore in the settings * * @since 1.0.0 */ diff --git a/Module/StatusAbstract.php b/Module/StatusAbstract.php index a26e8c027..0815522aa 100644 --- a/Module/StatusAbstract.php +++ b/Module/StatusAbstract.php @@ -262,10 +262,6 @@ abstract class StatusAbstract return; } - if (!\is_file($destRoutePath)) { - throw new PathException($destRoutePath); // @codeCoverageIgnore - } - if (!\is_writable($destRoutePath)) { throw new PermissionException($destRoutePath); // @codeCoverageIgnore } diff --git a/Stdlib/Base/Enum.php b/Stdlib/Base/Enum.php index 40983def2..ee2748457 100644 --- a/Stdlib/Base/Enum.php +++ b/Stdlib/Base/Enum.php @@ -55,7 +55,7 @@ abstract class Enum { $reflect = new \ReflectionClass(static::class); - return $reflect->getConstants() ?? []; + return $reflect->getConstants(); } /** diff --git a/System/File/FileUtils.php b/System/File/FileUtils.php index f59b99398..1d7d5544c 100644 --- a/System/File/FileUtils.php +++ b/System/File/FileUtils.php @@ -131,10 +131,8 @@ final class FileUtils if ($part !== '..' || empty($path)) { $path[] = $part; - } elseif (!empty($path)) { - \array_pop($path); } else { - throw new PathException($origPath); // @codeCoverageIgnore + \array_pop($path); } } diff --git a/System/File/Local/Directory.php b/System/File/Local/Directory.php index 756c7eb91..0a8da5936 100644 --- a/System/File/Local/Directory.php +++ b/System/File/Local/Directory.php @@ -359,7 +359,7 @@ final class Directory extends FileAbstract implements DirectoryInterface if (!\is_dir($to)) { self::create($to, 0755, true); - } elseif ($overwrite && \is_dir($to)) { + } elseif ($overwrite) { self::delete($to); self::create($to, 0755, true); } diff --git a/System/File/Storage.php b/System/File/Storage.php index 53745cbb0..4f3d1d6ec 100644 --- a/System/File/Storage.php +++ b/System/File/Storage.php @@ -59,11 +59,13 @@ final class Storage { if (isset(self::$registered[$env])) { if (\is_string(self::$registered[$env])) { + /** @var StorageAbstract $instance */ $instance = new self::$registered[$env](); self::$registered[$env] = $instance; } elseif (self::$registered[$env] instanceof StorageAbstract || self::$registered[$env] instanceof ContainerInterface ) { + /** @var StorageAbstract $instance */ $instance = self::$registered[$env]; } else { throw new \Exception('Invalid type'); @@ -71,10 +73,11 @@ final class Storage } else { $stg = $env; $env = \ucfirst(\strtolower($env)); + /** @var StorageAbstract $env */ $env = __NAMESPACE__ . '\\' . $env . '\\' . $env . 'Storage'; try { - /** @var StorageAbstract $env */ + /** @var StorageAbstract $instance */ $instance = new $env(); self::$registered[$stg] = $instance; diff --git a/System/SystemUtils.php b/System/SystemUtils.php index 9aafe2e96..5ab8a0e9b 100644 --- a/System/SystemUtils.php +++ b/System/SystemUtils.php @@ -93,7 +93,7 @@ final class SystemUtils $freeArr = \explode("\n", $free); $mem = \explode(' ', $freeArr[1]); $mem = \array_values(\array_filter($mem)); - $memUsage = $mem[2] / $mem[1] * 100; + $memUsage = ((float) ($mem[2] ?? 0.0)) / ((float) ($mem[1] ?? 1.0)) * 100; } return (int) $memUsage; diff --git a/Uri/Argument.php b/Uri/Argument.php index 922b828d4..1334e2cda 100644 --- a/Uri/Argument.php +++ b/Uri/Argument.php @@ -297,7 +297,7 @@ final class Argument implements UriInterface public function getQuery(string $key = null) : string { if ($key !== null) { - $key = \strtolower($key); + $key = (int) \strtolower($key); return $this->query[$key] ?? ''; } diff --git a/Uri/UriFactory.php b/Uri/UriFactory.php index 3bc48cb10..1c1f82c47 100644 --- a/Uri/UriFactory.php +++ b/Uri/UriFactory.php @@ -270,8 +270,8 @@ final class UriFactory * @ = * $ = Other data * - * @param string $uri Path data - * @param array $toMatch Optional special replacements + * @param string $uri Path data + * @param array $toMatch Optional special replacements * * @return string * @@ -285,17 +285,21 @@ final class UriFactory return $uri; } - $parsed = \preg_replace_callback('(\{[\/#\?%@\.\$][a-zA-Z0-9\-]*\})', function ($match) use ($toMatch) { - $match = \substr($match[0], 1, \strlen($match[0]) - 2); + $parsed = \preg_replace_callback( + '(\{[\/#\?%@\.\$][a-zA-Z0-9\-]*\})', + function ($match) use ($toMatch) : string { + $match = \substr($match[0], 1, \strlen($match[0]) - 2); - return $toMatch[$match] - ?? (self::$uri[$match] ?? ( - ($match[0] ?? '') === '?' - ? '---' // only do this for query parameters - : '' - ) - ); - }, $uri); + return $toMatch[$match] + ?? (self::$uri[$match] ?? ( + ($match[0] ?? '') === '?' + ? '---' // only do this for query parameters + : '' + ) + ); + }, + $uri + ); return self::unique($parsed ?? ''); } diff --git a/Utils/Compression/LZW.php b/Utils/Compression/LZW.php index 73feca479..d7f3b0b79 100644 --- a/Utils/Compression/LZW.php +++ b/Utils/Compression/LZW.php @@ -69,7 +69,7 @@ class LZW implements CompressionInterface $entry = ''; $dictSize = 256; - if (empty($compressed) || $compressed === [''] || $compressed === false) { + if ($compressed === [] || $compressed === [''] || $compressed === false) { return ''; } diff --git a/Utils/Converter/Ip.php b/Utils/Converter/Ip.php index 7bd465065..357cecff6 100644 --- a/Utils/Converter/Ip.php +++ b/Utils/Converter/Ip.php @@ -49,9 +49,9 @@ final class Ip { $split = \explode('.', $ip); - return ((int) $split[0] ?? 0) * (256 ** 3) - + ((int) $split[1] ?? 0) * (256 ** 2) - + ((int) $split[2] ?? 0) * (256 ** 1) - + ((int) $split[3] ?? 0); + return ((int) ($split[0] ?? 0)) * (256 ** 3) + + ((int) ($split[1] ?? 0)) * (256 ** 2) + + ((int) ($split[2] ?? 0)) * (256 ** 1) + + ((int) ($split[3] ?? 0)); } } diff --git a/Utils/Git/Repository.php b/Utils/Git/Repository.php index 3d6841795..6bd8d35b1 100644 --- a/Utils/Git/Repository.php +++ b/Utils/Git/Repository.php @@ -95,7 +95,7 @@ class Repository $this->path = \realpath($path); - if (\is_dir($this->path . '/.git') && \is_dir($this->path . '/.git')) { + if (\is_dir($this->path . '/.git')) { $this->bare = false; } elseif (\is_file($this->path . '/config')) { // Is this a bare repo? $parseIni = \parse_ini_file($this->path . '/config'); @@ -903,7 +903,7 @@ class Repository $commit = new Commit($matches[0]); $commit->setAuthor(new Author(\trim($author[0] ?? ''), \rtrim($author[1] ?? '', '>'))); - $commit->setDate(new \DateTime(\trim($date ?? 'now'))); + $commit->setDate(new \DateTime(\trim($date))); $commit->setMessage($lines[3]); $commit->setTag(new Tag()); $commit->setRepository($this); diff --git a/Views/View.php b/Views/View.php index 572482124..1349a798b 100644 --- a/Views/View.php +++ b/Views/View.php @@ -214,7 +214,7 @@ class View extends ViewAbstract /** @var string $theme */ $theme = $theme ?? $this->theme; - return $this->l11nManager->getText($this->l11n->getLanguage() ?? 'en', $module, $theme, $translation); + return $this->l11nManager->getText($this->l11n->getLanguage(), $module, $theme, $translation); } /** diff --git a/composer.json b/composer.json index de62bb644..9391f7681 100755 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ "friendsofphp/php-cs-fixer": ">=3.2", "squizlabs/php_codesniffer": ">=3.6", "phpmd/phpmd": ">=2.9", - "phpstan/phpstan": ">=0.12.58", + "phpstan/phpstan": ">=1.5.4", "phan/phan": ">=3.2.6" }, "minimum-stability": "dev",