From 521085e223c2058e74bd0b8c4050e86e5959694b Mon Sep 17 00:00:00 2001 From: Gwilyn Date: Thu, 26 Feb 2026 20:38:34 +1100 Subject: [PATCH 01/22] Bump minimum PHP to 8.1. --- composer.json | 2 +- composer.lock | 4 ++-- phpcs.xml | 2 +- phpstan.neon | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/composer.json b/composer.json index 5c2674f..8e6264c 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,7 @@ ], "require": { "symfony/polyfill-php73": "*", - "php": "^7.2|^8", + "php": "^8.1", "symfony/polyfill-php81": "^1.26", "karmabunny/interfaces": "^1.2" }, diff --git a/composer.lock b/composer.lock index 7499a97..07fb5aa 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3250080f6aa48c9395618cd62548d528", + "content-hash": "69465ea33744748216e3131da697fc40", "packages": [ { "name": "karmabunny/interfaces", @@ -2133,7 +2133,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "^7.2|^8" + "php": "^8.1" }, "platform-dev": {}, "plugin-api-version": "2.6.0" diff --git a/phpcs.xml b/phpcs.xml index 2cbd096..c62e534 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -8,7 +8,7 @@ src - + diff --git a/phpstan.neon b/phpstan.neon index 2b523b3..b1dbe47 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,7 +1,7 @@ parameters: level: 5 phpVersion: - min: 70200 + min: 80100 max: 80400 paths: - src From b4ee68aa8cc1079bac0fbdc9ba10377c4252a11f Mon Sep 17 00:00:00 2001 From: Gwilyn Date: Thu, 26 Feb 2026 20:42:11 +1100 Subject: [PATCH 02/22] Remove conditional PHP version code. --- src/AttributeTag.php | 12 ------------ src/CsvExport.php | 28 ++++++++-------------------- src/Json.php | 2 -- src/PropertiesTrait.php | 14 ++++++-------- src/Reflect.php | 10 ++++------ src/XML.php | 8 -------- 6 files changed, 18 insertions(+), 56 deletions(-) diff --git a/src/AttributeTag.php b/src/AttributeTag.php index a96f541..50b0a3d 100644 --- a/src/AttributeTag.php +++ b/src/AttributeTag.php @@ -168,14 +168,6 @@ public static function parseReflector($reflect, int $modes = self::MODE_ALL): ar { $tags = []; - if (PHP_VERSION_ID < 80000) { - if ($modes === self::MODE_ATTRIBUTES) { - throw new Error('Attributes are not supported in this version of PHP'); - } - - $modes ^= self::MODE_ATTRIBUTES; - } - if ($modes & self::MODE_ATTRIBUTES) { $more = static::parseReflectorAttributes($reflect); array_push($tags, ...$more); @@ -198,10 +190,6 @@ public static function parseReflector($reflect, int $modes = self::MODE_ALL): ar */ public static function parseReflectorAttributes($reflect): array { - if (PHP_VERSION_ID < 80000) { - throw new Error('Attributes are not supported in this version of PHP'); - } - // Safety net only because we haven't got strong types on '$reflect'. if (!method_exists($reflect, 'getAttributes')) { throw new Error('Cannot parse attributes from: ' . get_class($reflect)); diff --git a/src/CsvExport.php b/src/CsvExport.php index b6ca2ab..29f63c0 100644 --- a/src/CsvExport.php +++ b/src/CsvExport.php @@ -298,25 +298,13 @@ protected function _write(array $row) $items[$key] = $this->_format($key, $value); } - if (PHP_VERSION_ID > 80100) { - // @phpstan-ignore-next-line : newer PHP has more fields. - fputcsv( - $this->handle, - $items, - $this->delimiter, - $this->enclosure, - $this->escape, - $this->break - ); - } - else { - fputcsv( - $this->handle, - $items, - $this->delimiter, - $this->enclosure, - $this->escape - ); - } + fputcsv( + $this->handle, + $items, + $this->delimiter, + $this->enclosure, + $this->escape, + $this->break + ); } } diff --git a/src/Json.php b/src/Json.php index a576aed..1d2436b 100644 --- a/src/Json.php +++ b/src/Json.php @@ -39,7 +39,6 @@ public static function encode($json, $flags = 0): string $out = json_encode($json, $flags); - // PHP <= 7.2 $error = json_last_error(); if ($error !== JSON_ERROR_NONE) { throw new JsonException(json_last_error_msg(), $error); @@ -66,7 +65,6 @@ public static function decode(string $str, $flags = 0) $out = json_decode($str, true, self::RECURSIVE_DEPTH, $flags); - // PHP <= 7.2 $error = json_last_error(); if ($error !== JSON_ERROR_NONE) { throw new JsonException(json_last_error_msg(), $error); diff --git a/src/PropertiesTrait.php b/src/PropertiesTrait.php index 43b65e5..b6044b6 100644 --- a/src/PropertiesTrait.php +++ b/src/PropertiesTrait.php @@ -75,8 +75,8 @@ public static function getPropertyDefaults(): array /** * Get a list of properties, with respective types (if available). * - * Beginning with PHP 7.4 object properties can have strict types. If not - * typed or running a older PHP all properties will be `mixed`. + * Object properties can have strict types. If not typed, all properties + * will be `mixed`. * * @return string[] [ name => type ] */ @@ -97,12 +97,10 @@ public static function getPropertyTypes(): array $name = $property->getName(); $type = null; - if (PHP_VERSION_ID >= 74000) { - // @phpstan-ignore-next-line - $type = $property->getType(); - if ($type !== null) { - $type = $type->getName(); - } + // @phpstan-ignore-next-line + $type = $property->getType(); + if ($type !== null) { + $type = $type->getName(); } $fields[$name] = $type ?? 'mixed'; diff --git a/src/Reflect.php b/src/Reflect.php index b0ca653..c994823 100644 --- a/src/Reflect.php +++ b/src/Reflect.php @@ -163,15 +163,13 @@ public static function getProperties($target, $flags = true): array // Fix private/protected access. $property->setAccessible(true); - // @phpstan-ignore-next-line : PHP 7.4+ - if (PHP_VERSION_ID >= 70400 and !$property->isInitialized($target)) { + if (!$property->isInitialized($target)) { // Don't serialize uninitialized properties continue; } - else { - // We need to use getValue() so to bypass any __get() magic. - $value = $property->getValue($target); - } + + // We need to use getValue() so to bypass any __get() magic. + $value = $property->getValue($target); $key = $property->getName(); $data[$key] = $value; diff --git a/src/XML.php b/src/XML.php index 939fdb3..b6ab077 100644 --- a/src/XML.php +++ b/src/XML.php @@ -14,11 +14,6 @@ use DOMXPath; use Generator; -// Just to be sure. -if (PHP_VERSION_ID < 80000) { - libxml_disable_entity_loader(true); -} - /** * XML helper methods. * @@ -149,9 +144,6 @@ private static function createDocument(array &$config) // Automatic entity loading isn't a thing anymore. Although we still // loading for loading schemas and such. Use the 'entities' callback // and built-in loaders for this, or build you own. - if (PHP_VERSION_ID < 80000) { - libxml_disable_entity_loader(true); - } if (!isset($config['options'])) $config['options'] = 0; if (!isset($config['filename'])) $config['filename'] = ''; From 6b21d477df21229e0e4feb9e25ce2beb577e5522 Mon Sep 17 00:00:00 2001 From: Gwilyn Date: Thu, 26 Feb 2026 21:59:47 +1100 Subject: [PATCH 03/22] Add strong types everywhere. --- src/Arrays.php | 85 ++++++++++++++++++++++------------------- src/AttributeTag.php | 27 +++++-------- src/Buffer.php | 5 ++- src/Cli.php | 17 +++++---- src/Config.php | 26 ++++++------- src/Configure.php | 17 +++++---- src/EventableTrait.php | 4 +- src/Events.php | 15 ++++---- src/Json.php | 7 ++-- src/PropertiesTrait.php | 10 ++--- src/Reflect.php | 10 +++-- src/XML.php | 47 ++++++++++++----------- 12 files changed, 136 insertions(+), 134 deletions(-) diff --git a/src/Arrays.php b/src/Arrays.php index 8532e07..9f08b6b 100644 --- a/src/Arrays.php +++ b/src/Arrays.php @@ -1,4 +1,5 @@ $item) { return [$key, $item]; @@ -67,7 +68,7 @@ public static function firstPair($iterable) * @param iterable $iterable * @return array [ key, item ] */ - public static function lastPair($iterable) + public static function lastPair(iterable $iterable): array { if (is_array($iterable)) { $item = end($iterable); @@ -90,7 +91,7 @@ public static function lastPair($iterable) * @param iterable $iterable * @return int|string|null */ - public static function firstKey($iterable) + public static function firstKey(iterable $iterable): int|string|null { list($key) = self::firstPair($iterable); return $key; @@ -103,7 +104,7 @@ public static function firstKey($iterable) * @param iterable $iterable * @return int|string|null */ - public static function lastKey($iterable) + public static function lastKey(iterable $iterable): int|string|null { list($key) = self::lastPair($iterable); return $key; @@ -117,7 +118,7 @@ public static function lastKey($iterable) * @param T[]|iterable $iterable * @return T|null */ - public static function first($iterable) + public static function first(iterable $iterable): mixed { list( , $value) = self::firstPair($iterable); return $value; @@ -131,7 +132,7 @@ public static function first($iterable) * @param T[]|iterable $iterable * @return T|null */ - public static function last($iterable) + public static function last(iterable $iterable): mixed { list( , $value) = self::lastPair($iterable); return $value; @@ -150,10 +151,10 @@ public static function last($iterable) * TBH not entirely sure why I wrote this. * * @template T - * @param T[]|iterable $array + * @param iterable $array * @return iterable */ - public static function reverse($array) + public static function reverse(iterable $array): iterable { end($array); while (($key = key($array)) !== null) @@ -185,7 +186,7 @@ public static function reverse($array) * @param callable $fn (&$index) => $value * @return array */ - public static function fill(int $size, callable $fn) + public static function fill(int $size, callable $fn): array { $array = []; for ($i = 0; $i < $size; $i++) { @@ -212,7 +213,7 @@ public static function fill(int $size, callable $fn) * @param callable $fn ($index) => [$key, $value] * @return array */ - public static function fillKeyed(int $size, callable $fn) + public static function fillKeyed(int $size, callable $fn): array { $array = []; for ($i = 0; $i < $size; $i++) { @@ -240,7 +241,7 @@ public static function fillKeyed(int $size, callable $fn) * @param mixed $fill * @return array */ - public static function fillIntersectionKeys(array $keys, array $array, $fill = null) + public static function fillIntersectionKeys(array $keys, array $array, mixed $fill = null): array { $keys = array_fill_keys($keys, $fill); $array = array_merge($keys, array_intersect_key($array, $keys)); @@ -259,7 +260,7 @@ public static function fillIntersectionKeys(array $keys, array $array, $fill = n * @param string $inner_glue * @return string */ - public static function implodeWithKeys(array $array, string $outer_glue = '', string $inner_glue = '') + public static function implodeWithKeys(array $array, string $outer_glue = '', string $inner_glue = ''): string { $output = ''; @@ -280,7 +281,7 @@ public static function implodeWithKeys(array $array, string $outer_glue = '', st * @param T|null $initial * @return T */ - public static function reverseReduce($array, $fn, $initial = null) + public static function reverseReduce(iterable $array, callable $fn, mixed $initial = null): mixed { $reversed = self::reverse($array); $carry = $initial; @@ -309,7 +310,7 @@ public static function reverseReduce($array, $fn, $initial = null) * @param array $arrays * @return array */ - public static function mergeKeyed(...$arrays) + public static function mergeKeyed(array ...$arrays): array { $reversed = self::reverse($arrays); @@ -341,7 +342,7 @@ public static function mergeKeyed(...$arrays) * @param callable $fn ($value, $key) => bool * @return T|null */ - public static function find($iterable, callable $fn) + public static function find(iterable $iterable, callable $fn): mixed { foreach ($iterable as $key => $item) { if ($fn($item, $key)) return $item; @@ -363,7 +364,7 @@ public static function find($iterable, callable $fn) * @param callable $fn ($value, $key) => bool * @return T|null */ - public static function findKey($iterable, callable $fn) + public static function findKey(iterable $iterable, callable $fn): mixed { foreach ($iterable as $key => $item) { if ($fn($item, $key)) return $key; @@ -380,7 +381,7 @@ public static function findKey($iterable, callable $fn) * @param string $key * @return null|int */ - public static function indexOf(array $array, string $key) + public static function indexOf(array $array, string $key): ?int { $index = array_search($key, array_keys($array)); @@ -408,7 +409,7 @@ public static function indexOf(array $array, string $key) * @param mixed|null $initial * @return mixed */ - public static function reduce($iterable, callable $fn, $initial = null) + public static function reduce(iterable $iterable, callable $fn, mixed $initial = null): mixed { $carry = $initial; foreach ($iterable as $key => $value) { @@ -510,7 +511,7 @@ public static function filterRecursive(array $array, ?callable $callback = null, * @param bool $fill Replace missing keys with null. * @return T[] */ - public static function filterKeys(array $array, array $keys, $fill = false): array + public static function filterKeys(array $array, array $keys, bool $fill = false): array { $items = []; @@ -529,7 +530,7 @@ public static function filterKeys(array $array, array $keys, $fill = false): arr * @param iterable $arrays * @return array */ - public static function zip(...$arrays): array + public static function zip(iterable ...$arrays): array { $output = []; @@ -577,7 +578,7 @@ public static function zip(...$arrays): array * @param callable $fn (item) => item * @return array */ - public static function map($array, $fn): array + public static function map(iterable $array, callable $fn): array { $items = []; @@ -613,7 +614,7 @@ public static function map($array, $fn): array * @param callable $fn (item, key) => item * @return array */ - public static function mapWithKeys($array, $fn): array + public static function mapWithKeys(iterable $array, callable $fn): array { $items = []; @@ -640,7 +641,7 @@ public static function mapWithKeys($array, $fn): array * @param callable $fn (item, key) => [key, item] * @return array */ - public static function mapKeys($array, $fn): array + public static function mapKeys(iterable $array, callable $fn): array { $items = []; @@ -667,7 +668,7 @@ public static function mapKeys($array, $fn): array * @param int $mode LEAVES_ONLY (default), SELF_FIRST, CHILD_FIRST * @return array */ - public static function mapRecursive(array $array, $fn, $mode = self::LEAVES_ONLY): array + public static function mapRecursive(array $array, callable $fn, int $mode = self::LEAVES_ONLY): array { $process = null; $process = function($rootkey, array $array, $fn, $mode) use (&$process) { @@ -712,7 +713,7 @@ public static function mapRecursive(array $array, $fn, $mode = self::LEAVES_ONLY * @param bool $preserve_keys * @return T[] */ - public static function shuffle($array, bool $preserve_keys = false): array + public static function shuffle(iterable $array, bool $preserve_keys = false): array { if (!is_array($array)) { $array = iterator_to_array($array, $preserve_keys); @@ -744,7 +745,7 @@ public static function shuffle($array, bool $preserve_keys = false): array * @param int $depth * @return array */ - public static function flatten($array, $keys = false, int $depth = 25): array + public static function flatten(iterable $array, bool $keys = false, int $depth = 25): array { $return = []; @@ -865,7 +866,7 @@ public static function flattenKeys(array $array, string $glue = '.'): array * @param string|int $index * @return array */ - public static function explodeKeys(array $array, string $glue = '.', $index = ''): array + public static function explodeKeys(array $array, string $glue = '.', string|int $index = ''): array { $output = []; @@ -920,16 +921,20 @@ public static function explodeKeys(array $array, string $glue = '.', $index = '' * * This converts any nested arrayables to arrays. * - * @param ArrayableInterface|Traversable|array $array + * @param object|array $array * @param bool $recurse - recurse into nested arrays * @return array */ - public static function toArray($array, bool $recurse = true): array + public static function toArray(object|array $array, bool $recurse = true): array { if ($array instanceof ArrayableInterface) { return $array->toArray(); } + if (is_object($array) and !$array instanceof Traversable) { + $array = (array) $array; + } + foreach ($array as &$item) { if ($item instanceof ArrayableInterface) { $item = $item->toArray(); @@ -974,7 +979,7 @@ public static function toArray($array, bool $recurse = true): array * @param mixed $array * @return bool */ - public static function isNumeric($array): bool + public static function isNumeric(mixed $array): bool { if (!is_array($array)) { return false; @@ -999,7 +1004,7 @@ public static function isNumeric($array): bool * @param mixed $array * @return bool */ - public static function isAssociated($array): bool + public static function isAssociated(mixed $array): bool { return !self::isNumeric($array); } @@ -1039,7 +1044,7 @@ public static function isAssociated($array): bool * @param array $array * @return mixed */ - public static function value($array, string $query) + public static function value(mixed $array, string $query): mixed { /** @var mixed $array */ @@ -1126,7 +1131,7 @@ public static function value($array, string $query) * @param string|null $select Include a 'choose' option * @return array */ - public static function createMap($items, string $key, string $name, ?string $select = null) + public static function createMap(iterable $items, string $key, string $name, ?string $select = null): array { $map = []; @@ -1184,7 +1189,7 @@ public static function createMap($items, string $key, string $name, ?string $sel * @param mixed $default * @return array */ - public static function normalizeOptions($items, $default): array + public static function normalizeOptions(iterable $items, mixed $default): array { $output = []; @@ -1225,7 +1230,7 @@ public static function normalizeOptions($items, $default): array * @param string $path * @return array|null `null` if the file is invalid or missing. */ - public static function config(string $path) + public static function config(string $path): ?array { static $cache = []; $output = $cache[$path] ?? null; @@ -1261,7 +1266,7 @@ public static function config(string $path) * @param string|null $mode null => 'default' * @return callable(mixed, mixed): int */ - public static function createSort(int $dir = SORT_ASC, ?string $mode = null) + public static function createSort(int $dir = SORT_ASC, ?string $mode = null): callable { $dir = $dir === SORT_DESC ? -1 : 1; @@ -1336,7 +1341,7 @@ public static function createSort(int $dir = SORT_ASC, ?string $mode = null) * @param array $modes [ name => SORT ] * @return callable(mixed, mixed): int */ - public static function createMultisort(array $modes) + public static function createMultisort(array $modes): callable { $modes = self::normalizeOptions($modes, SORT_ASC); @@ -1366,7 +1371,7 @@ public static function createMultisort(array $modes) * @param string|null $mode null => 'default' * @return void */ - public static function sort(array &$array, bool $preserve_keys = false, int $dir = SORT_ASC, ?string $mode = null) + public static function sort(array &$array, bool $preserve_keys = false, int $dir = SORT_ASC, ?string $mode = null): void { $fn = self::createSort($dir, $mode); @@ -1408,7 +1413,7 @@ public static function sorted(array $array, bool $preserve_keys = false, int $di * @param string[] $modes [ name => SORT ] * @return void */ - public static function multisort(array &$array, bool $preserve_keys, array $modes) + public static function multisort(array &$array, bool $preserve_keys, array $modes): void { $fn = self::createMultisort($modes); @@ -1431,7 +1436,7 @@ public static function multisort(array &$array, bool $preserve_keys, array $mode * @param string[] $modes [ name => SORT ] * @return T[] */ - public static function multisorted(array $array, bool $preserve_keys, array $modes) + public static function multisorted(array $array, bool $preserve_keys, array $modes): array { self::multisort($array, $preserve_keys, $modes); return $array; diff --git a/src/AttributeTag.php b/src/AttributeTag.php index 50b0a3d..4457e55 100644 --- a/src/AttributeTag.php +++ b/src/AttributeTag.php @@ -1,4 +1,5 @@ getAttributes(static::class, ReflectionAttribute::IS_INSTANCEOF); $tags = []; @@ -219,7 +210,7 @@ public static function parseReflectorAttributes($reflect): array * @param ReflectionClass|ReflectionFunctionAbstract|ReflectionProperty|ReflectionClassConstant|ReflectionParameter $reflect * @return static[] */ - public static function parseReflectorDocTags($reflect): array + public static function parseReflectorDocTags(Reflector $reflect): array { // Static store for class metadata. This only needs to be parsed once. // A bit of inception here. We're parsing the @doctags of the tag diff --git a/src/Buffer.php b/src/Buffer.php index 7ca8d8d..a43c12f 100644 --- a/src/Buffer.php +++ b/src/Buffer.php @@ -1,4 +1,5 @@ level() > 0) { throw new RuntimeException('Buffer is already open'); diff --git a/src/Cli.php b/src/Cli.php index 4aad675..e6ee6cc 100644 --- a/src/Cli.php +++ b/src/Cli.php @@ -1,4 +1,5 @@ name => instance */ - protected static $instances = []; + protected static array $instances = []; /** @var array name => [key => value] */ - protected $overrides = []; + protected array $overrides = []; /** @var array name => config */ - protected $cache = []; + protected array $cache = []; /** @var array name => [paths] */ - protected $loaded = []; + protected array $loaded = []; /** * Get or create an instance of this config. * - * @param bool $refresh - * @return static */ - public static function instance(bool $refresh = false) + public static function instance(bool $refresh = false): static { $instance = self::$instances[static::class] ?? null; @@ -74,11 +73,9 @@ public abstract function getPaths(): array; /** * Does this config exist? * - * @param string $name - * @return string[] * @throws InvalidArgumentException on an invalid config name. */ - public function find(string $name) + public function find(string $name): array { if (preg_match('![^-_a-zA-Z0-9]!', $name)) { throw new InvalidArgumentException("Invalid config file '{$name}'"); @@ -100,6 +97,7 @@ public function find(string $name) /** * Load and merge configs. * + * @param array $config * @param string $path * @param string $name * @return bool @@ -171,7 +169,7 @@ public static function load(string $path, string $name = 'config'): array * @throws InvalidArgumentException When a config doesn't exist. * @throws RuntimeException if a recursive config file is detected. */ - public static function get(string $key, $required = true) + public static function get(string $key, bool $required = true): mixed { $instance = static::instance(); [$name, $subkey] = explode('.', $key, 2) + ['', null]; @@ -222,7 +220,7 @@ public static function get(string $key, $required = true) * @param mixed $value * @return void */ - public static function set(string $key, $value) + public static function set(string $key, mixed $value): void { $instance = static::instance(); [$name, $key] = explode('.', $key, 2) + ['', null]; @@ -237,7 +235,7 @@ public static function set(string $key, $value) * @param string $query dot-noted string: foo.bar.baz * @return mixed|null */ - public static function query(array $array, string $query) + public static function query(array $array, string $query): mixed { if (empty($array)) { return null; @@ -282,7 +280,7 @@ public static function query(array $array, string $query) * @param mixed $value fill value for the key * @return void */ - public static function querySet(array &$array, string $query, $value = null) + public static function querySet(array &$array, string $query, mixed $value = null): void { if (empty($query)) { return; diff --git a/src/Configure.php b/src/Configure.php index a9809b4..82c29bf 100644 --- a/src/Configure.php +++ b/src/Configure.php @@ -1,4 +1,5 @@ $class * @param class-string|class-string[] $assert * @return T * @throws InvalidArgumentException */ - public static function instance(string $class, $assert = null) + public static function instance(string $class, string|array|null $assert = null): object { // Check the class exists. try { @@ -199,7 +200,7 @@ public static function instance(string $class, $assert = null) * @param array $config * @return void */ - public static function update($object, array $config) + public static function update(object $object, array $config): void { // Do configurable things because we can. if ($object instanceof ConfigurableInterface) { @@ -223,12 +224,12 @@ public static function update($object, array $config) /** * Instance a single object. * - * @template T + * @template T of object * @param class-string $class * @param array $config * @return T */ - public static function create(string $class, array $config) + public static function create(string $class, array $config): object { $object = self::instance($class); self::update($object, $config); @@ -244,7 +245,7 @@ public static function create(string $class, array $config) * @param array[] $items * @return T[] */ - public static function createAll(string $class, array $items) + public static function createAll(string $class, array $items): array { /** @var array $items */ diff --git a/src/EventableTrait.php b/src/EventableTrait.php index dde2c43..9e77960 100644 --- a/src/EventableTrait.php +++ b/src/EventableTrait.php @@ -77,7 +77,7 @@ protected function trigger(?string $class, EventInterface $event, bool $once = f * @return void * @throws InvalidArgumentException */ - public function on($event, $fn = null, bool $append = true) + public function on(string|callable $event, callable|bool|null $fn = null, bool $append = true) { // Unlike trigger, using dynamic class names here is OK. A user is not // surprised (hopefully) that they only receive events appropriate for @@ -94,7 +94,7 @@ public function on($event, $fn = null, bool $append = true) * @param class-string|null $event * @return void */ - public function off($event) + public function off(?string $event = null): void { Events::off($this, $event); } diff --git a/src/Events.php b/src/Events.php index 335cd35..f36efa4 100644 --- a/src/Events.php +++ b/src/Events.php @@ -1,4 +1,5 @@ |null $event * @return void */ - public static function off($sender, ?string $event = null) + public static function off(string|object|null $sender, ?string $event = null): void { if (is_object($sender)) { $sender = get_class($sender); @@ -349,7 +350,7 @@ public static function hasRun(string $sender, string $event): bool * @param bool $logging * @return void */ - public static function setLogging(bool $logging) + public static function setLogging(bool $logging): void { self::$_log = $logging ? [] : null; } @@ -361,7 +362,7 @@ public static function setLogging(bool $logging) * @param bool $clearRunLog * @return void */ - public static function clearLog(bool $clearRunLog = false) + public static function clearLog(bool $clearRunLog = false): void { if (self::$_log !== null) { self::$_log = []; diff --git a/src/Json.php b/src/Json.php index 1d2436b..ccbba1c 100644 --- a/src/Json.php +++ b/src/Json.php @@ -1,4 +1,5 @@ isStatic()) continue; $name = $property->getName(); - $type = null; + $type_name = null; - // @phpstan-ignore-next-line $type = $property->getType(); - if ($type !== null) { - $type = $type->getName(); + if ($type instanceof ReflectionNamedType) { + $type_name = $type->getName(); } - $fields[$name] = $type ?? 'mixed'; + $fields[$name] = $type_name ?? 'mixed'; } $_FIELDS[static::class] = $fields; diff --git a/src/Reflect.php b/src/Reflect.php index c994823..c8fefd2 100644 --- a/src/Reflect.php +++ b/src/Reflect.php @@ -1,4 +1,5 @@ getName(); diff --git a/src/XML.php b/src/XML.php index b6ab077..640afe0 100644 --- a/src/XML.php +++ b/src/XML.php @@ -1,4 +1,5 @@ schemaValidateSource($source); @@ -139,7 +140,7 @@ public static function validate(DOMDocument $doc, string $source) * @param array $config * @return DOMDocument */ - private static function createDocument(array &$config) + private static function createDocument(array &$config): DOMDocument { // Automatic entity loading isn't a thing anymore. Although we still // loading for loading schemas and such. Use the 'entities' callback @@ -168,7 +169,7 @@ private static function createDocument(array &$config) * @return void * @throws XMLException */ - private static function collectLibXmlErrors(string $class, $filename) + private static function collectLibXmlErrors(string $class, ?string $filename): void { $errors = libxml_get_errors(); if (empty($errors)) return; @@ -197,7 +198,7 @@ private static function collectLibXmlErrors(string $class, $filename) * * @return void */ - private static function cleanLibXml() + private static function cleanLibXml(): void { libxml_clear_errors(); libxml_use_internal_errors(false); @@ -222,7 +223,7 @@ private static function cleanLibXml() * @param array $entities * @return callable (public_id, system_id, context) => resource|null */ - public static function allowedEntities(array $entities) + public static function allowedEntities(array $entities): callable { return function ($public_id, $system_id, $context) use ($entities) @@ -250,7 +251,7 @@ public static function allowedEntities(array $entities) * @param array $prefixes * @return callable (public_id, system_id, context) => resource|null */ - public static function prefixEntities(array $prefixes) + public static function prefixEntities(array $prefixes): callable { return function ($public_id, $system_id, $context) use ($prefixes) @@ -290,7 +291,7 @@ public static function prefixEntities(array $prefixes) * @return void * @throws XMLException */ - public static function processConditionals(DOMNode $node, array $conditions) + public static function processConditionals(DOMNode $node, array $conditions): void { /** @var DOMDocument */ $document = $node->ownerDocument ?? $node; @@ -445,7 +446,7 @@ public static function format(string $template, array $args): DOMDocument * @param string $type string|bool|int|float|element|list|nodes * @return string|bool|int|float|DOMElement|DOMNode[]|Generator|null */ - public static function xpath(DOMNode $node, string $query, string $type = 'nodes') + public static function xpath(DOMNode $node, string $query, string $type = 'nodes'): mixed { // If 'ownerDocument' is null, then the node _is_ the document. /** @var DOMDocument $document */ @@ -504,7 +505,7 @@ public static function xpath(DOMNode $node, string $query, string $type = 'nodes * @param DOMNodeList $list * @return Generator */ - private static function getNodeIterator(DOMNodeList $list) + private static function getNodeIterator(DOMNodeList $list): Generator { for ($i = 0; $i < $list->length; $i++) { $item = $list->item($i); @@ -521,7 +522,7 @@ private static function getNodeIterator(DOMNodeList $list) * @param DOMNodeList $list * @return Generator */ - private static function getElementIterator(DOMNodeList $list) + private static function getElementIterator(DOMNodeList $list): Generator { foreach (self::getNodeIterator($list) as $i => $item) { if (!($item instanceof DOMElement)) continue; @@ -552,7 +553,7 @@ private static function getElementIterator(DOMNodeList $list) * @param array $params * @return mixed */ - public static function enum(DOMNode $xml, string $path, array $params) + public static function enum(DOMNode $xml, string $path, array $params): mixed { $value = self::xpath($xml, $path, 'int') ?: 0; $value = $params[$value] ?? null; @@ -571,7 +572,7 @@ public static function enum(DOMNode $xml, string $path, array $params) * @param DOMNode $thing * @return bool true/false and nothing else */ - public static function boolean(DOMNode $thing) + public static function boolean(DOMNode $thing): bool { // No element. $thing = self::text($thing); @@ -626,7 +627,7 @@ public static function boolean(DOMNode $thing) * @return DOMElement * @throws XMLAssertException If there were no nodes with that tag */ - public static function expectFirst(DOMNode $parent, string $tag_name) + public static function expectFirst(DOMNode $parent, string $tag_name): DOMElement { $element = self::first($parent, $tag_name); @@ -647,7 +648,7 @@ public static function expectFirst(DOMNode $parent, string $tag_name) * @return string * @throws XMLAssertException If there were no nodes with that tag name */ - public static function expectFirstText(DOMNode $parent, string $tag_name) + public static function expectFirstText(DOMNode $parent, string $tag_name): string { return self::text(self::expectFirst($parent, $tag_name)); } @@ -660,7 +661,7 @@ public static function expectFirstText(DOMNode $parent, string $tag_name) * @param string $tag_name * @return DOMElement|null */ - public static function first(DOMNode $parent, string $tag_name) + public static function first(DOMNode $parent, string $tag_name): ?DOMElement { // Get the root element of a document first. if ($parent instanceof DOMDocument) { @@ -684,7 +685,7 @@ public static function first(DOMNode $parent, string $tag_name) * @param string $tag_name * @return string|null */ - public static function firstText(DOMNode $parent, string $tag_name) + public static function firstText(DOMNode $parent, string $tag_name): ?string { $element = self::first($parent, $tag_name); if ($element === null) return null; @@ -706,7 +707,7 @@ public static function firstText(DOMNode $parent, string $tag_name) * @return DOMElement[] [name => element] * @throws XMLAssertException If not all wanted tags are found */ - public static function gatherChildren(DOMNode $parent, array $wanted) + public static function gatherChildren(DOMNode $parent, array $wanted): array { $wanted = array_fill_keys($wanted, true); $fetched = []; @@ -753,7 +754,7 @@ public static function getChildrenText(DOMElement $node, string $tag): array * @return DOMElement * @throws XMLAssertException If no tag found */ - public static function expectOneOf(DOMNode $parent, array $wanted) + public static function expectOneOf(DOMNode $parent, array $wanted): DOMElement { foreach (self::getElementIterator($parent->childNodes) as $element) { /** @var DOMElement $element */ @@ -772,7 +773,7 @@ public static function expectOneOf(DOMNode $parent, array $wanted) * @param DOMNode $node * @return string */ - public static function text(DOMNode $node) + public static function text(DOMNode $node): string { return trim($node->textContent); } @@ -785,7 +786,7 @@ public static function text(DOMNode $node) * @param string $name * @return string|null */ - public static function attr($element, string $name) + public static function attr(DOMDocument|DOMElement $element, string $name): ?string { if ($element instanceof DOMDocument) { $element = $element->documentElement; @@ -818,7 +819,7 @@ public static function toString(DOMNode $node): string * @param DOMNode $node * @return void echos */ - public static function print(DOMNode $node) + public static function print(DOMNode $node): void { /** @var DOMDocument */ $document = $node->ownerDocument ?? $node; From f05c9eb3d2eb1f47c160b883005226836add553c Mon Sep 17 00:00:00 2001 From: Gwilyn Date: Thu, 26 Feb 2026 22:01:11 +1100 Subject: [PATCH 04/22] Use native JSON errors. --- src/Json.php | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/src/Json.php b/src/Json.php index ccbba1c..540bd01 100644 --- a/src/Json.php +++ b/src/Json.php @@ -26,25 +26,23 @@ class Json * Encode a json array as a string. * * @param mixed $json - * @param bool|int $flags Applies pretty flags if `true`. + * @param bool|int $flags Applies pretty flags if `true`, default: `JSON_THROW_ON_ERROR` * @return string * @throws JsonException Any parsing error */ - public static function encode(mixed $json, bool|int $flags = 0): string + public static function encode(mixed $json, bool|int $flags = -1): string { if ($flags === true) { $flags = 0; $flags |= JSON_UNESCAPED_SLASHES; $flags |= JSON_PRETTY_PRINT; } - - $out = json_encode($json, $flags); - - $error = json_last_error(); - if ($error !== JSON_ERROR_NONE) { - throw new JsonException(json_last_error_msg(), $error); + else if ($flags === -1) { + $flags = 0; + $flags |= JSON_THROW_ON_ERROR; } + $out = json_encode($json, $flags); return $out; } @@ -54,23 +52,17 @@ public static function encode(mixed $json, bool|int $flags = 0): string * * @throws JsonException Any parsing error * @param string $str A JSON string. As per the spec, this should be UTF-8 encoded - * @param int $flags Default JSON_INVALID_UTF8_SUBSTITUTE (if available) + * @param int $flags Default: `JSON_INVALID_UTF8_SUBSTITUTE` and `JSON_THROW_ON_ERROR` * @return mixed The decoded value */ - public static function decode(string $str, int $flags = 0): mixed + public static function decode(string $str, int $flags = -1): mixed { - if ($flags == 0 and defined('JSON_INVALID_UTF8_SUBSTITUTE')) { - // phpcs:ignore + if ($flags === -1) { $flags |= JSON_INVALID_UTF8_SUBSTITUTE; + $flags |= JSON_THROW_ON_ERROR; } $out = json_decode($str, true, self::RECURSIVE_DEPTH, $flags); - - $error = json_last_error(); - if ($error !== JSON_ERROR_NONE) { - throw new JsonException(json_last_error_msg(), $error); - } - return $out; } From 63192ad74d03076c54ce08addc0e3536840eb694 Mon Sep 17 00:00:00 2001 From: Gwilyn Date: Fri, 27 Feb 2026 10:31:57 +1100 Subject: [PATCH 05/22] Fix XML formatter for non-string args. --- src/XML.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/XML.php b/src/XML.php index 640afe0..ebee117 100644 --- a/src/XML.php +++ b/src/XML.php @@ -415,7 +415,7 @@ public static function format(string $template, array $args): DOMDocument foreach ($args as $key => $value) { $subjects[] = '{{' . $key . '}}'; - $replace[] = htmlspecialchars($value); + $replace[] = htmlspecialchars((string) $value); } $xml = str_replace($subjects, $replace, $template); From 3694d156dae017f27d0787412d1f44fafac1da9d Mon Sep 17 00:00:00 2001 From: Gwilyn Date: Fri, 17 Jul 2026 10:05:09 +1000 Subject: [PATCH 06/22] Remove positional hack for on() append. --- src/EventableTrait.php | 4 ++-- src/Events.php | 9 +++------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/EventableTrait.php b/src/EventableTrait.php index 9e77960..160bee8 100644 --- a/src/EventableTrait.php +++ b/src/EventableTrait.php @@ -72,12 +72,12 @@ protected function trigger(?string $class, EventInterface $event, bool $once = f * * @see Events::on() * @param class-string|callable $event - * @param callable|bool|null $fn + * @param callable|null $fn * @param bool $append * @return void * @throws InvalidArgumentException */ - public function on(string|callable $event, callable|bool|null $fn = null, bool $append = true) + public function on(string|callable $event, ?callable $fn = null, bool $append = true) { // Unlike trigger, using dynamic class names here is OK. A user is not // surprised (hopefully) that they only receive events appropriate for diff --git a/src/Events.php b/src/Events.php index f36efa4..0fad32e 100644 --- a/src/Events.php +++ b/src/Events.php @@ -153,18 +153,15 @@ public static function trigger($sender, EventInterface $event, bool $once = fals * * @param class-string|object $sender * @param class-string|callable $event - * @param callable|bool|null $fn + * @param callable|null $fn * @param bool $append * @return void * @throws InvalidArgumentException */ - public static function on(string|object $sender, string|callable $event, callable|bool|null $fn = null, bool $append = true) + public static function on(string|object $sender, string|callable $event, ?callable $fn = null, bool $append = true) { - // If no handler is given, assume the second parameter is handler. // Using some cheeky reflection we can extract the event type. - if ($fn === null or is_bool($fn)) { - $append = $fn ?? $append; - + if ($fn === null) { try { $fn = $event; $event = null; From 903a1ac016b7bf85912c44f28b04cdf803878c1a Mon Sep 17 00:00:00 2001 From: Gwilyn Date: Fri, 17 Jul 2026 10:07:17 +1000 Subject: [PATCH 07/22] Bump minimum php to 8.2. --- composer.json | 7 +- composer.lock | 463 +++++++++++++++++++++++++++++--------------------- phpcs.xml | 2 +- phpstan.neon | 4 +- 4 files changed, 281 insertions(+), 195 deletions(-) diff --git a/composer.json b/composer.json index 8e6264c..69d2910 100644 --- a/composer.json +++ b/composer.json @@ -11,9 +11,14 @@ "email": "info@karmabunny.com.au" } ], + "config": { + "platform": { + "php": "8.2" + } + }, "require": { "symfony/polyfill-php73": "*", - "php": "^8.1", + "php": "^8.2", "symfony/polyfill-php81": "^1.26", "karmabunny/interfaces": "^1.2" }, diff --git a/composer.lock b/composer.lock index 07fb5aa..32c7097 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "69465ea33744748216e3131da697fc40", + "content-hash": "318b4af6611bdd35902e72128cabf2c0", "packages": [ { "name": "karmabunny/interfaces", @@ -59,29 +59,26 @@ }, { "name": "symfony/polyfill-php73", - "version": "v1.28.0", + "version": "v1.37.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "fe2f306d1d9d346a7fee353d0d5012e401e984b5" + "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fe2f306d1d9d346a7fee353d0d5012e401e984b5", - "reference": "fe2f306d1d9d346a7fee353d0d5012e401e984b5", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/0f68c03565dcaaf25a890667542e8bd75fe7e5bb", + "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -118,7 +115,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-php73/tree/v1.37.0" }, "funding": [ { @@ -129,38 +126,39 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-php81", - "version": "v1.28.0", + "version": "v1.38.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "7581cd600fa9fd681b797d00b02f068e2f13263b" + "reference": "6bfb9c766cacffbc8e118cb87217d08ed84e5cd7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/7581cd600fa9fd681b797d00b02f068e2f13263b", - "reference": "7581cd600fa9fd681b797d00b02f068e2f13263b", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/6bfb9c766cacffbc8e118cb87217d08ed84e5cd7", + "reference": "6bfb9c766cacffbc8e118cb87217d08ed84e5cd7", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -197,7 +195,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-php81/tree/v1.38.1" }, "funding": [ { @@ -208,12 +206,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2026-05-26T12:45:58+00:00" } ], "packages-dev": [ @@ -289,16 +291,16 @@ }, { "name": "myclabs/deep-copy", - "version": "1.11.1", + "version": "1.13.4", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c" + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", - "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a", "shasum": "" }, "require": { @@ -306,11 +308,12 @@ }, "conflict": { "doctrine/collections": "<1.6.8", - "doctrine/common": "<2.13.3 || >=3,<3.2.2" + "doctrine/common": "<2.13.3 || >=3 <3.2.2" }, "require-dev": { "doctrine/collections": "^1.6.8", "doctrine/common": "^2.13.3 || ^3.2.2", + "phpspec/prophecy": "^1.10", "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" }, "type": "library", @@ -336,7 +339,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1" + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4" }, "funding": [ { @@ -344,29 +347,30 @@ "type": "tidelift" } ], - "time": "2023-03-08T13:26:56+00:00" + "time": "2025-08-01T08:46:24+00:00" }, { "name": "nikic/php-parser", - "version": "v4.17.1", + "version": "v5.8.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d" + "reference": "044a6a392ff8ad0d61f14370a5fbbd0a0107152f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", - "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/044a6a392ff8ad0d61f14370a5fbbd0a0107152f", + "reference": "044a6a392ff8ad0d61f14370a5fbbd0a0107152f", "shasum": "" }, "require": { + "ext-json": "*", "ext-tokenizer": "*", - "php": ">=7.0" + "php": ">=7.4" }, "require-dev": { "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + "phpunit/phpunit": "^9.0" }, "bin": [ "bin/php-parse" @@ -374,7 +378,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.9-dev" + "dev-master": "5.x-dev" } }, "autoload": { @@ -398,26 +402,27 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.17.1" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.8.0" }, - "time": "2023-08-13T19:53:39+00:00" + "time": "2026-07-04T14:30:18+00:00" }, { "name": "phar-io/manifest", - "version": "2.0.3", + "version": "2.0.4", "source": { "type": "git", "url": "https://github.com/phar-io/manifest.git", - "reference": "97803eca37d319dfa7826cc2437fc020857acb53" + "reference": "54750ef60c58e43759730615a392c31c80e23176" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", - "reference": "97803eca37d319dfa7826cc2437fc020857acb53", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", "shasum": "" }, "require": { "ext-dom": "*", + "ext-libxml": "*", "ext-phar": "*", "ext-xmlwriter": "*", "phar-io/version": "^3.0.1", @@ -458,9 +463,15 @@ "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", "support": { "issues": "https://github.com/phar-io/manifest/issues", - "source": "https://github.com/phar-io/manifest/tree/2.0.3" + "source": "https://github.com/phar-io/manifest/tree/2.0.4" }, - "time": "2021-07-20T11:28:43+00:00" + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" }, { "name": "phar-io/version", @@ -577,16 +588,11 @@ }, { "name": "phpstan/phpstan", - "version": "2.1.13", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpstan.git", - "reference": "e55e03e6d4ac49cd1240907e5b08e5cd378572a9" - }, + "version": "2.2.5", "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e55e03e6d4ac49cd1240907e5b08e5cd378572a9", - "reference": "e55e03e6d4ac49cd1240907e5b08e5cd378572a9", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/909c1e5fef7989ac0d0c1c5c42e32a5c4f6198a0", + "reference": "909c1e5fef7989ac0d0c1c5c42e32a5c4f6198a0", "shasum": "" }, "require": { @@ -609,6 +615,17 @@ "license": [ "MIT" ], + "authors": [ + { + "name": "Ondřej Mirtes" + }, + { + "name": "Markus Staab" + }, + { + "name": "Vincent Langlet" + } + ], "description": "PHPStan - PHP Static Analysis Tool", "keywords": [ "dev", @@ -631,39 +648,39 @@ "type": "github" } ], - "time": "2025-04-27T12:28:25+00:00" + "time": "2026-07-05T06:31:06+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "9.2.29", + "version": "9.2.32", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76" + "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6a3a87ac2bbe33b25042753df8195ba4aa534c76", - "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/85402a822d1ecf1db1096959413d35e1c37cf1a5", + "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.15", + "nikic/php-parser": "^4.19.1 || ^5.1.0", "php": ">=7.3", - "phpunit/php-file-iterator": "^3.0.3", - "phpunit/php-text-template": "^2.0.2", - "sebastian/code-unit-reverse-lookup": "^2.0.2", - "sebastian/complexity": "^2.0", - "sebastian/environment": "^5.1.2", - "sebastian/lines-of-code": "^1.0.3", - "sebastian/version": "^3.0.1", - "theseer/tokenizer": "^1.2.0" + "phpunit/php-file-iterator": "^3.0.6", + "phpunit/php-text-template": "^2.0.4", + "sebastian/code-unit-reverse-lookup": "^2.0.3", + "sebastian/complexity": "^2.0.3", + "sebastian/environment": "^5.1.5", + "sebastian/lines-of-code": "^1.0.4", + "sebastian/version": "^3.0.2", + "theseer/tokenizer": "^1.2.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^9.6" }, "suggest": { "ext-pcov": "PHP extension that provides line coverage", @@ -672,7 +689,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.2-dev" + "dev-main": "9.2.x-dev" } }, "autoload": { @@ -701,7 +718,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.29" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.32" }, "funding": [ { @@ -709,7 +726,7 @@ "type": "github" } ], - "time": "2023-09-19T04:57:46+00:00" + "time": "2024-08-22T04:23:01+00:00" }, { "name": "phpunit/php-file-iterator", @@ -954,45 +971,45 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.13", + "version": "9.6.35", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be" + "reference": "0edba2f3a0c48df3553cb9b640810b30df60302b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f3d767f7f9e191eab4189abe41ab37797e30b1be", - "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/0edba2f3a0c48df3553cb9b640810b30df60302b", + "reference": "0edba2f3a0c48df3553cb9b640810b30df60302b", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.3.1 || ^2", + "doctrine/instantiator": "^1.5.0 || ^2", "ext-dom": "*", + "ext-filter": "*", "ext-json": "*", "ext-libxml": "*", "ext-mbstring": "*", - "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.10.1", - "phar-io/manifest": "^2.0.3", - "phar-io/version": "^3.0.2", + "myclabs/deep-copy": "^1.13.4", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", "php": ">=7.3", - "phpunit/php-code-coverage": "^9.2.28", - "phpunit/php-file-iterator": "^3.0.5", + "phpunit/php-code-coverage": "^9.2.32", + "phpunit/php-file-iterator": "^3.0.6", "phpunit/php-invoker": "^3.1.1", - "phpunit/php-text-template": "^2.0.3", - "phpunit/php-timer": "^5.0.2", - "sebastian/cli-parser": "^1.0.1", - "sebastian/code-unit": "^1.0.6", - "sebastian/comparator": "^4.0.8", - "sebastian/diff": "^4.0.3", - "sebastian/environment": "^5.1.3", - "sebastian/exporter": "^4.0.5", - "sebastian/global-state": "^5.0.1", - "sebastian/object-enumerator": "^4.0.3", - "sebastian/resource-operations": "^3.0.3", - "sebastian/type": "^3.2", + "phpunit/php-text-template": "^2.0.4", + "phpunit/php-timer": "^5.0.3", + "sebastian/cli-parser": "^1.0.2", + "sebastian/code-unit": "^1.0.8", + "sebastian/comparator": "^4.0.10", + "sebastian/diff": "^4.0.6", + "sebastian/environment": "^5.1.5", + "sebastian/exporter": "^4.0.8", + "sebastian/global-state": "^5.0.8", + "sebastian/object-enumerator": "^4.0.4", + "sebastian/resource-operations": "^3.0.4", + "sebastian/type": "^3.2.1", "sebastian/version": "^3.0.2" }, "suggest": { @@ -1037,36 +1054,28 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.13" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.35" }, "funding": [ { - "url": "https://phpunit.de/sponsors.html", - "type": "custom" - }, - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", - "type": "tidelift" + "url": "https://phpunit.de/sponsoring.html", + "type": "other" } ], - "time": "2023-09-19T05:39:22+00:00" + "time": "2026-07-06T14:48:07+00:00" }, { "name": "sebastian/cli-parser", - "version": "1.0.1", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" + "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b", + "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b", "shasum": "" }, "require": { @@ -1101,7 +1110,7 @@ "homepage": "https://github.com/sebastianbergmann/cli-parser", "support": { "issues": "https://github.com/sebastianbergmann/cli-parser/issues", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.2" }, "funding": [ { @@ -1109,7 +1118,7 @@ "type": "github" } ], - "time": "2020-09-28T06:08:49+00:00" + "time": "2024-03-02T06:27:43+00:00" }, { "name": "sebastian/code-unit", @@ -1224,16 +1233,16 @@ }, { "name": "sebastian/comparator", - "version": "4.0.8", + "version": "4.0.10", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "fa0f136dd2334583309d32b62544682ee972b51a" + "reference": "e4df00b9b3571187db2831ae9aada2c6efbd715d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", - "reference": "fa0f136dd2334583309d32b62544682ee972b51a", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/e4df00b9b3571187db2831ae9aada2c6efbd715d", + "reference": "e4df00b9b3571187db2831ae9aada2c6efbd715d", "shasum": "" }, "require": { @@ -1286,32 +1295,44 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", - "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" + "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.10" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator", + "type": "tidelift" } ], - "time": "2022-09-14T12:41:17+00:00" + "time": "2026-01-24T09:22:56+00:00" }, { "name": "sebastian/complexity", - "version": "2.0.2", + "version": "2.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" + "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a", + "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a", "shasum": "" }, "require": { - "nikic/php-parser": "^4.7", + "nikic/php-parser": "^4.18 || ^5.0", "php": ">=7.3" }, "require-dev": { @@ -1343,7 +1364,7 @@ "homepage": "https://github.com/sebastianbergmann/complexity", "support": { "issues": "https://github.com/sebastianbergmann/complexity/issues", - "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" + "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3" }, "funding": [ { @@ -1351,20 +1372,20 @@ "type": "github" } ], - "time": "2020-10-26T15:52:27+00:00" + "time": "2023-12-22T06:19:30+00:00" }, { "name": "sebastian/diff", - "version": "4.0.5", + "version": "4.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131" + "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131", - "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc", + "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc", "shasum": "" }, "require": { @@ -1409,7 +1430,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5" + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.6" }, "funding": [ { @@ -1417,7 +1438,7 @@ "type": "github" } ], - "time": "2023-05-07T05:35:17+00:00" + "time": "2024-03-02T06:30:58+00:00" }, { "name": "sebastian/environment", @@ -1484,16 +1505,16 @@ }, { "name": "sebastian/exporter", - "version": "4.0.5", + "version": "4.0.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d" + "reference": "14c6ba52f95a36c3d27c835d65efc7123c446e8c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", - "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/14c6ba52f95a36c3d27c835d65efc7123c446e8c", + "reference": "14c6ba52f95a36c3d27c835d65efc7123c446e8c", "shasum": "" }, "require": { @@ -1549,28 +1570,40 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5" + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.8" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/exporter", + "type": "tidelift" } ], - "time": "2022-09-14T06:03:37+00:00" + "time": "2025-09-24T06:03:27+00:00" }, { "name": "sebastian/global-state", - "version": "5.0.6", + "version": "5.0.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "bde739e7565280bda77be70044ac1047bc007e34" + "reference": "b6781316bdcd28260904e7cc18ec983d0d2ef4f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34", - "reference": "bde739e7565280bda77be70044ac1047bc007e34", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/b6781316bdcd28260904e7cc18ec983d0d2ef4f6", + "reference": "b6781316bdcd28260904e7cc18ec983d0d2ef4f6", "shasum": "" }, "require": { @@ -1613,32 +1646,44 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6" + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.8" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/global-state", + "type": "tidelift" } ], - "time": "2023-08-02T09:26:13+00:00" + "time": "2025-08-10T07:10:35+00:00" }, { "name": "sebastian/lines-of-code", - "version": "1.0.3", + "version": "1.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" + "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5", + "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5", "shasum": "" }, "require": { - "nikic/php-parser": "^4.6", + "nikic/php-parser": "^4.18 || ^5.0", "php": ">=7.3" }, "require-dev": { @@ -1670,7 +1715,7 @@ "homepage": "https://github.com/sebastianbergmann/lines-of-code", "support": { "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4" }, "funding": [ { @@ -1678,7 +1723,7 @@ "type": "github" } ], - "time": "2020-11-28T06:42:11+00:00" + "time": "2023-12-22T06:20:34+00:00" }, { "name": "sebastian/object-enumerator", @@ -1794,16 +1839,16 @@ }, { "name": "sebastian/recursion-context", - "version": "4.0.5", + "version": "4.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" + "reference": "539c6691e0623af6dc6f9c20384c120f963465a0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", - "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/539c6691e0623af6dc6f9c20384c120f963465a0", + "reference": "539c6691e0623af6dc6f9c20384c120f963465a0", "shasum": "" }, "require": { @@ -1845,28 +1890,40 @@ "homepage": "https://github.com/sebastianbergmann/recursion-context", "support": { "issues": "https://github.com/sebastianbergmann/recursion-context/issues", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" + "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.6" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context", + "type": "tidelift" } ], - "time": "2023-02-03T06:07:39+00:00" + "time": "2025-08-10T06:57:39+00:00" }, { "name": "sebastian/resource-operations", - "version": "3.0.3", + "version": "3.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" + "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e", + "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e", "shasum": "" }, "require": { @@ -1878,7 +1935,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-main": "3.0-dev" } }, "autoload": { @@ -1899,8 +1956,7 @@ "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", "support": { - "issues": "https://github.com/sebastianbergmann/resource-operations/issues", - "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.4" }, "funding": [ { @@ -1908,7 +1964,7 @@ "type": "github" } ], - "time": "2020-09-28T06:45:17+00:00" + "time": "2024-03-14T16:00:52+00:00" }, { "name": "sebastian/type", @@ -2021,16 +2077,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.7.2", + "version": "3.13.5", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879" + "reference": "0ca86845ce43291e8f5692c7356fccf3bcf02bf4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/ed8e00df0a83aa96acf703f8c2979ff33341f879", - "reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/0ca86845ce43291e8f5692c7356fccf3bcf02bf4", + "reference": "0ca86845ce43291e8f5692c7356fccf3bcf02bf4", "shasum": "" }, "require": { @@ -2040,18 +2096,13 @@ "php": ">=5.4.0" }, "require-dev": { - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" }, "bin": [ - "bin/phpcs", - "bin/phpcbf" + "bin/phpcbf", + "bin/phpcs" ], "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" @@ -2059,35 +2110,62 @@ "authors": [ { "name": "Greg Sherwood", - "role": "lead" + "role": "Former lead" + }, + { + "name": "Juliette Reinders Folmer", + "role": "Current lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" } ], "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", "keywords": [ "phpcs", "standards", "static analysis" ], "support": { - "issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues", - "source": "https://github.com/squizlabs/PHP_CodeSniffer", - "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" + "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", + "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", + "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" }, - "time": "2023-02-22T23:07:41+00:00" + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + }, + { + "url": "https://thanks.dev/u/gh/phpcsstandards", + "type": "thanks_dev" + } + ], + "time": "2025-11-04T16:30:35+00:00" }, { "name": "theseer/tokenizer", - "version": "1.2.1", + "version": "1.3.1", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" + "reference": "b7489ce515e168639d17feec34b8847c326b0b3c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", - "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b7489ce515e168639d17feec34b8847c326b0b3c", + "reference": "b7489ce515e168639d17feec34b8847c326b0b3c", "shasum": "" }, "require": { @@ -2116,7 +2194,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.2.1" + "source": "https://github.com/theseer/tokenizer/tree/1.3.1" }, "funding": [ { @@ -2124,7 +2202,7 @@ "type": "github" } ], - "time": "2021-07-28T10:34:58+00:00" + "time": "2025-11-17T20:03:58+00:00" } ], "aliases": [], @@ -2133,8 +2211,11 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "^8.1" + "php": "^8.2" }, "platform-dev": {}, + "platform-overrides": { + "php": "8.2" + }, "plugin-api-version": "2.6.0" } diff --git a/phpcs.xml b/phpcs.xml index c62e534..297154d 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -8,7 +8,7 @@ src - + diff --git a/phpstan.neon b/phpstan.neon index b1dbe47..1549053 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,8 +1,8 @@ parameters: level: 5 phpVersion: - min: 80100 - max: 80400 + min: 80200 + max: 80500 paths: - src ignoreErrors: From 0b9f65c5db6e5ee19f8b1bdc71900ba043ba211f Mon Sep 17 00:00:00 2001 From: Gwilyn Date: Fri, 17 Jul 2026 12:16:11 +1000 Subject: [PATCH 08/22] Fix event append tests. --- tests/EventTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/EventTest.php b/tests/EventTest.php index cbf43da..f21cd60 100644 --- a/tests/EventTest.php +++ b/tests/EventTest.php @@ -98,7 +98,7 @@ public function testPrepend() Events::on(RootEmitter::class, function(TestEvent $event) { $this->assertNull($event->sender); return 'two'; - }, false); + }, append: false); // Test parent class listener. Events::on(RootEmitter::class, TestEvent::class, function(Event $event) { @@ -131,15 +131,15 @@ public function testHandled() Events::on(RootEmitter::class, function(TestEvent $event) { $event->handled = true; return 'three'; - }, false); + }, append: false); Events::on(RootEmitter::class, function(TestEvent $event) { return 'four'; - }, false); + }, append: false); Events::on(RootEmitter::class, function(TestEvent $event) { return 'five'; - }, true); + }, append: true); $event = new TestEvent(); $actual = Events::trigger(RootEmitter::class, $event); From c39bc6c0c90d18a68cbc1eefbc49f5deba94fcdc Mon Sep 17 00:00:00 2001 From: Gwilyn Date: Fri, 17 Jul 2026 12:18:57 +1000 Subject: [PATCH 09/22] Deprecate the wrap helper. --- src/Wrap.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Wrap.php b/src/Wrap.php index d37aa9e..093a16f 100644 --- a/src/Wrap.php +++ b/src/Wrap.php @@ -3,7 +3,6 @@ namespace karmabunny\kb; use ArrayAccess; -use Closure; use InvalidArgumentException; /** @@ -38,6 +37,7 @@ * $mapped = array_map(Wrap::construct(Thing::class), $results); * ``` * + * @deprecated don't use this. * @package karmabunny/kb */ class Wrap From d11fe651d8864260505cf9636f7362e46e5985f0 Mon Sep 17 00:00:00 2001 From: Gwilyn Date: Fri, 17 Jul 2026 12:22:03 +1000 Subject: [PATCH 10/22] Drop support for Serializable interface. --- src/Collection.php | 2 -- src/SerializeTrait.php | 31 +------------------------------ 2 files changed, 1 insertion(+), 32 deletions(-) diff --git a/src/Collection.php b/src/Collection.php index 63844ce..f62156c 100644 --- a/src/Collection.php +++ b/src/Collection.php @@ -12,7 +12,6 @@ use JsonSerializable; use karmabunny\interfaces\ArrayableInterface; use ReturnTypeWillChange; -use Serializable; use Traversable; /** @@ -42,7 +41,6 @@ abstract class Collection extends DataObject implements ArrayAccess, IteratorAggregate, - Serializable, JsonSerializable, ArrayableInterface, DirtyObjectInterface diff --git a/src/SerializeTrait.php b/src/SerializeTrait.php index cc2c2fc..78957c9 100644 --- a/src/SerializeTrait.php +++ b/src/SerializeTrait.php @@ -7,7 +7,6 @@ namespace karmabunny\kb; use ReflectionProperty; -use ReturnTypeWillChange; /** * Implements a PHP serialiser. @@ -18,13 +17,6 @@ * * You can extend, or restrict, serialization per class by overriding * the `getSerializedProperties()` method. - * - * This provides compatibility with the `Serializable` interface. Modern - * PHP (7.4+) will use the magic `__serialize()/__unserialize()` methods if - * available, but still prefers the "Serializable" methods. - * - * When overriding these methods, just override the magic ones and let this - * trait wrap them to comply with the `Serializable` interface. */ trait SerializeTrait { @@ -55,25 +47,6 @@ protected function getSerializedProperties(): array /** @inheritdoc */ - #[ReturnTypeWillChange] - public function serialize() - { - $serialized = $this->__serialize(); - return serialize($serialized); - } - - - /** @inheritdoc */ - #[ReturnTypeWillChange] - public function unserialize($serialized) - { - $serialized = unserialize($serialized); - $this->__unserialize($serialized); - } - - - /** @inheritdoc */ - // phpcs:ignore public function __serialize(): array { if ($this instanceof NotSerializable) { @@ -86,9 +59,7 @@ public function __serialize(): array /** @inheritdoc */ - #[ReturnTypeWillChange] - // phpcs:ignore - public function __unserialize(array $serialized) + public function __unserialize(array $serialized): void { if ($this instanceof DataObject) { $this->update($serialized); From f8e177a5b2cf52f6403520d101e80c60a77d3d19 Mon Sep 17 00:00:00 2001 From: Gwilyn Date: Fri, 17 Jul 2026 12:23:25 +1000 Subject: [PATCH 11/22] Remove ReturnTypeWillChange. --- src/ArrayAccessTrait.php | 16 +++++++--------- src/Collection.php | 4 +--- src/ToJsonTrait.php | 8 ++++---- src/VirtualArrayTrait.php | 9 ++++----- 4 files changed, 16 insertions(+), 21 deletions(-) diff --git a/src/ArrayAccessTrait.php b/src/ArrayAccessTrait.php index fc38892..f85ced5 100644 --- a/src/ArrayAccessTrait.php +++ b/src/ArrayAccessTrait.php @@ -6,35 +6,33 @@ namespace karmabunny\kb; -use ReturnTypeWillChange; +/** + * @mixin \ArrayAccess + */ trait ArrayAccessTrait { - #[ReturnTypeWillChange] - public function offsetExists($offset) + public function offsetExists(mixed $offset): bool { return isset($this->$offset); } - #[ReturnTypeWillChange] - public function offsetGet($offset) + public function offsetGet(mixed $offset): mixed { return $this->$offset ?? null; } - #[ReturnTypeWillChange] - public function offsetSet($offset, $value) + public function offsetSet(mixed $offset, mixed $value): void { $this->$offset = $value; } - #[ReturnTypeWillChange] - public function offsetUnset($offset) + public function offsetUnset(mixed $offset): void { unset($this->$offset); } diff --git a/src/Collection.php b/src/Collection.php index f62156c..71ea433 100644 --- a/src/Collection.php +++ b/src/Collection.php @@ -11,7 +11,6 @@ use IteratorAggregate; use JsonSerializable; use karmabunny\interfaces\ArrayableInterface; -use ReturnTypeWillChange; use Traversable; /** @@ -61,8 +60,7 @@ public function getIterator(): Traversable /** @inheritdoc */ - #[ReturnTypeWillChange] - public function jsonSerialize() + public function jsonSerialize(): array { return $this->getSerializedProperties(); } diff --git a/src/ToJsonTrait.php b/src/ToJsonTrait.php index 6177a1e..bad5d40 100755 --- a/src/ToJsonTrait.php +++ b/src/ToJsonTrait.php @@ -1,7 +1,8 @@ toJson(); } diff --git a/src/VirtualArrayTrait.php b/src/VirtualArrayTrait.php index dd6a35c..f615742 100644 --- a/src/VirtualArrayTrait.php +++ b/src/VirtualArrayTrait.php @@ -7,7 +7,6 @@ namespace karmabunny\kb; use ArrayAccess; -use ReturnTypeWillChange; /** * @@ -23,8 +22,8 @@ trait VirtualArrayTrait public abstract function fields(): array; - #[ReturnTypeWillChange] - public function offsetExists($offset) + /** @inheritdoc */ + public function offsetExists(mixed $offset): bool { if (!is_numeric($offset)) { $fields = $this->fields(); @@ -40,8 +39,8 @@ public function offsetExists($offset) } - #[ReturnTypeWillChange] - public function offsetGet($offset) + /** @inheritdoc */ + public function offsetGet(mixed $offset): mixed { if (!is_numeric($offset)) { $fields = $this->fields(); From 7d9c8aeaf01604bdf57105b655f3f47467023373 Mon Sep 17 00:00:00 2001 From: Gwilyn Date: Fri, 17 Jul 2026 12:26:43 +1000 Subject: [PATCH 12/22] Add default empty job rules, rework validate/execute a bit. --- src/Job.php | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/Job.php b/src/Job.php index 0326da6..ea07bc9 100644 --- a/src/Job.php +++ b/src/Job.php @@ -42,13 +42,17 @@ abstract class Job implements * Create and validate a job with this config. * * @param array $config + * @param bool $validate * @return void */ - public function __construct(array $config) + public function __construct(array $config = [], bool $validate = true) { $this->update($config); $this->start = time(); - $this->validate(); + + if ($config and $validate) { + $this->validate(); + } } @@ -84,6 +88,13 @@ public function getValidator(): RulesValidatorInterface } + /** @inheritdoc */ + public function rules(?string $scenario = null): array + { + return []; + } + + /** * Get the current stats. * @@ -115,9 +126,10 @@ public function stats(): array */ public static function execute(array $config = []) { - $class = static::class; - - $job = new $class($config); + // @phpstan-ignore-next-line + $job = new static(); + $job->update($config); + $job->validate(); $job->addLogger(function($message) { echo Log::stringify($message), PHP_EOL; From 0ca42792a46f748956e761e53c7db86264b17961 Mon Sep 17 00:00:00 2001 From: Gwilyn Date: Fri, 17 Jul 2026 12:27:46 +1000 Subject: [PATCH 13/22] Deprecate isStaticCallable(). --- src/Arrays.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Arrays.php b/src/Arrays.php index 9f08b6b..816cc85 100644 --- a/src/Arrays.php +++ b/src/Arrays.php @@ -906,7 +906,6 @@ public static function explodeKeys(array $array, string $glue = '.', string|int } // A root index key is a bit of an edge-case. - // @phpstan-ignore-next-line : Doesn't like all the reference business. if ($index !== '' and isset($output[''])) { $output = [ $index => $output[''] ] + $output; unset($output['']); From 04c3ffae35960fda681a3954f89d8fb7a34eaf6a Mon Sep 17 00:00:00 2001 From: Gwilyn Date: Fri, 17 Jul 2026 12:28:14 +1000 Subject: [PATCH 14/22] Remove dead phpstan ignores. --- src/CsvExport.php | 2 -- src/Reflect.php | 1 - 2 files changed, 3 deletions(-) diff --git a/src/CsvExport.php b/src/CsvExport.php index 29f63c0..c840728 100644 --- a/src/CsvExport.php +++ b/src/CsvExport.php @@ -235,8 +235,6 @@ private function _format(string $attribute, $value): string try { $value = @(string) $value; } - // We're told that __toString() shouldn't throw, but that doesn't mean it can't. - // @phpstan-ignore-next-line catch (Throwable $exception) { $value = 'ERR'; } diff --git a/src/Reflect.php b/src/Reflect.php index c8fefd2..1f73751 100644 --- a/src/Reflect.php +++ b/src/Reflect.php @@ -90,7 +90,6 @@ public static function loadClasses(string $path, ?string $filter = null): Genera if (!class_exists($full_class, false)) continue; // All classes must subtype the filter. - // @phpstan-ignore-next-line : phpstan doesn't like subclass checks. if ($filter and !is_subclass_of($full_class, $filter)) continue; yield $full_class; } From 8d21585ee1e8064e644dca27552827ca713c8bfe Mon Sep 17 00:00:00 2001 From: Gwilyn Date: Fri, 17 Jul 2026 12:33:41 +1000 Subject: [PATCH 15/22] Update method signatures to match strong type interfaces. --- src/BaseRule.php | 10 +++++----- src/CallbackRule.php | 6 +++--- src/DataObject.php | 2 +- src/DocValidator.php | 5 +++-- src/DocValidatorTrait.php | 6 ++++-- src/Inflector.php | 2 +- src/Job.php | 2 +- src/LoggerTrait.php | 20 ++++++++++---------- src/RulesClassValidator.php | 2 +- src/RulesStaticValidator.php | 2 +- src/RulesValidatorTrait.php | 6 ++++-- src/Secrets.php | 2 +- src/SortFieldsTrait.php | 6 ++++-- src/ToJsonTrait.php | 3 +++ src/UpdateStrictTrait.php | 4 +++- src/UpdateTidyTrait.php | 5 ++++- src/UpdateTrait.php | 5 ++++- src/ValidErrorsTrait.php | 5 ++++- src/VirtualArrayTrait.php | 1 + src/VirtualMethodsTrait.php | 2 +- src/rules/AllInArrayRule.php | 4 ++-- src/rules/AllMatchRule.php | 2 +- src/rules/AllUniqueRule.php | 2 +- src/rules/BinaryRule.php | 2 +- src/rules/DateRangeRule.php | 4 ++-- src/rules/EmailRule.php | 2 +- src/rules/InArrayRule.php | 4 ++-- src/rules/Ipv4AddrOrCidrRule.php | 2 +- src/rules/Ipv4AddrRule.php | 2 +- src/rules/Ipv4CidrRule.php | 2 +- src/rules/LengthRule.php | 4 ++-- src/rules/MysqlDateRule.php | 2 +- src/rules/MysqlDateTimeRule.php | 2 +- src/rules/MysqlTimeRule.php | 2 +- src/rules/NumericRule.php | 2 +- src/rules/OneRequiredRule.php | 4 ++-- src/rules/PasswordRule.php | 4 ++-- src/rules/PhoneRule.php | 4 ++-- src/rules/PositiveIntRule.php | 2 +- src/rules/ProseTextRule.php | 2 +- src/rules/RangeRule.php | 4 ++-- src/rules/RegexRule.php | 4 ++-- src/rules/RequiredRule.php | 2 +- 43 files changed, 91 insertions(+), 69 deletions(-) diff --git a/src/BaseRule.php b/src/BaseRule.php index 839ebb8..86683b5 100644 --- a/src/BaseRule.php +++ b/src/BaseRule.php @@ -33,7 +33,7 @@ abstract class BaseRule implements RuleInterface /** @inheritdoc */ - public function parse(array $ruleset) + public function parse(array $ruleset): void { $this->fields = []; @@ -69,7 +69,7 @@ public function fields(): array /** @inheritdoc */ - public function validate($data) + public function validate(array|object $data): void { if (is_object($data) and !$data instanceof ArrayAccess) { $data = new ArrayObject($data, ArrayObject::STD_PROP_LIST | ArrayObject::ARRAY_AS_PROPS); @@ -119,7 +119,7 @@ public function validate($data) * @param mixed $value * @return void */ - public function validateOne(string $field, $value) + public function validateOne(string $field, mixed $value): void { } @@ -130,7 +130,7 @@ public function validateOne(string $field, $value) * @param array|object $data * @return array */ - public function getFieldValues($data): array + public function getFieldValues(array|object $data): array { if (is_object($data) and !$data instanceof ArrayAccess) { $data = new ArrayObject($data, ArrayObject::STD_PROP_LIST | ArrayObject::ARRAY_AS_PROPS); @@ -159,7 +159,7 @@ public function getFieldValues($data): array * @param string $field * @return bool */ - public static function isEmpty($data, string $field): bool + public static function isEmpty(array|ArrayAccess $data, string $field): bool { $value = $data[$field] ?? null; diff --git a/src/CallbackRule.php b/src/CallbackRule.php index 885ae23..efe76d4 100644 --- a/src/CallbackRule.php +++ b/src/CallbackRule.php @@ -29,7 +29,7 @@ class CallbackRule extends BaseRule /** @inheritdoc */ - public function parse(array $ruleset) + public function parse(array $ruleset): void { parent::parse($ruleset); @@ -44,7 +44,7 @@ public function parse(array $ruleset) /** @inheritdoc */ - public function validate($data) + public function validate(array|object $data): void { if (!$this->callable or empty($this->fields)) { return; @@ -61,7 +61,7 @@ public function validate($data) /** @inheritdoc */ - public function validateOne(string $field, $value) + public function validateOne(string $field, mixed $value): void { if (!$this->callable) { return; diff --git a/src/DataObject.php b/src/DataObject.php index 9a6a0b3..f84e792 100644 --- a/src/DataObject.php +++ b/src/DataObject.php @@ -28,7 +28,7 @@ abstract class DataObject implements ConfigurableInterface /** * @param iterable $config */ - function __construct($config = []) + function __construct(iterable $config = []) { // This makes things not break. Something about references. if (!is_array($config)) { diff --git a/src/DocValidator.php b/src/DocValidator.php index 6a446a0..53dbd33 100644 --- a/src/DocValidator.php +++ b/src/DocValidator.php @@ -6,8 +6,8 @@ namespace karmabunny\kb; -use Exception; use Generator; +use karmabunny\interfaces\ValidatorInterface; use ReflectionClass; use ReflectionProperty; @@ -29,7 +29,8 @@ * ``` * @package karmabunny\kb */ -class DocValidator implements Validator { +class DocValidator implements ValidatorInterface +{ /** @var object */ protected $target; diff --git a/src/DocValidatorTrait.php b/src/DocValidatorTrait.php index a71671c..89dc900 100644 --- a/src/DocValidatorTrait.php +++ b/src/DocValidatorTrait.php @@ -7,12 +7,14 @@ namespace karmabunny\kb; use Exception; +use karmabunny\interfaces\ValidatesInterface; /** * Use '@var' comments to validate object properties. * * @see DocValidator * + * @mixin ValidatesInterface * @package karmabunny\kb */ trait DocValidatorTrait { @@ -28,7 +30,7 @@ trait DocValidatorTrait { * @return void * @throws ValidationException */ - public function validate(?string $scenario = null) + public function validate(?string $scenario = null): void { $errors = $this->valid($scenario); if ($errors !== true) { @@ -44,7 +46,7 @@ public function validate(?string $scenario = null) * @return array|true True if valid, errors array if invalid. * @throws Exception */ - public function valid(?string $scenario = null) + public function valid(?string $scenario = null): array|true { $valid = new DocValidator($this); if (!$valid->validate()) { diff --git a/src/Inflector.php b/src/Inflector.php index 9baef63..a370e4c 100644 --- a/src/Inflector.php +++ b/src/Inflector.php @@ -43,7 +43,7 @@ public function __construct($config = null) /** @inheritdoc */ - public function update($config) + public function update(iterable $config): void { parent::update($config); $this->uncountable = array_combine($this->uncountable, $this->uncountable); diff --git a/src/Job.php b/src/Job.php index ea07bc9..c4d6694 100644 --- a/src/Job.php +++ b/src/Job.php @@ -57,7 +57,7 @@ public function __construct(array $config = [], bool $validate = true) /** @inheritdoc */ - public function update($config) + public function update(iterable $config): void { if (!is_array($config)) { $config = iterator_to_array($config, true); diff --git a/src/LoggerTrait.php b/src/LoggerTrait.php index 10762a5..c94ba61 100644 --- a/src/LoggerTrait.php +++ b/src/LoggerTrait.php @@ -47,11 +47,11 @@ public function clearLoggers() * ``` * * @param callable|LogSinkInterface $logger (message, level, category, timestamp) - * @param string|array|null $category filter by category * @param int|null $level filter by level + * @param string|array|null $category filter by category * @return int */ - public function addLogger($logger, ?int $level = null, $category = null): int + public function addLogger(callable|LogSinkInterface $logger, ?int $level = null, string|array|null $category = null): int { if ( $logger === $this @@ -78,11 +78,11 @@ public function addLogger($logger, ?int $level = null, $category = null): int * * @deprecated Use addLogger() instead * @param callable|LogSinkInterface $logger - * @param string|array|null $category filter by category * @param int|null $level filter by level + * @param string|array|null $category filter by category * @return void */ - public function attach($logger, ?int $level = null, $category = null) + public function attach(callable|LogSinkInterface $logger, ?int $level = null, string|array|null $category = null): void { $this->addLogger($logger, $level, $category); } @@ -93,18 +93,18 @@ public function attach($logger, ?int $level = null, $category = null) * * @param mixed $message * @param int $level default: LEVEL_INFO - * @param string|null $_category default: class name (static) - * @param int|float|null $_timestamp default: now + * @param string|null $category default: class name (static) + * @param float|null $timestamp default: now * @return void */ - public function log($message, ?int $level = null, ?string $_category = null, $_timestamp = null) + public function log(mixed $message, ?int $level = null, ?string $category = null, ?float $timestamp = null): void { if ($level === null) $level = Log::LEVEL_INFO; - if ($_category === null) $_category = static::class; - if ($_timestamp === null) $_timestamp = microtime(true); + if ($category === null) $category = static::class; + if ($timestamp === null) $timestamp = microtime(true); foreach ($this->loggers as $logger) { - $logger($message, $level, $_category, $_timestamp); + $logger($message, $level, $category, $timestamp); } } } diff --git a/src/RulesClassValidator.php b/src/RulesClassValidator.php index 0ed62a0..0fc2a7b 100644 --- a/src/RulesClassValidator.php +++ b/src/RulesClassValidator.php @@ -189,7 +189,7 @@ public function refreshRules() /** @inheritdoc */ - public function setRules(array $rules) + public function setRules(array $rules): void { $this->original_rules = $rules; diff --git a/src/RulesStaticValidator.php b/src/RulesStaticValidator.php index 3761667..472d418 100644 --- a/src/RulesStaticValidator.php +++ b/src/RulesStaticValidator.php @@ -164,7 +164,7 @@ public function setData($data) * @param array $rules * @return void */ - public function setRules(array $rules) + public function setRules(array $rules): void { $this->rules = $rules; } diff --git a/src/RulesValidatorTrait.php b/src/RulesValidatorTrait.php index e51d141..a9ff74d 100644 --- a/src/RulesValidatorTrait.php +++ b/src/RulesValidatorTrait.php @@ -8,6 +8,7 @@ use Exception; use karmabunny\interfaces\RulesValidatorInterface; +use karmabunny\interfaces\ValidatesInterface; /** * Use validator functions to validate properties. @@ -16,6 +17,7 @@ * @see RulesClassValidator * @see Validity * + * @mixin ValidatesInterface * @package karmabunny\kb */ trait RulesValidatorTrait @@ -102,7 +104,7 @@ public function getValidator(): RulesValidatorInterface * @throws Exception * @throws ValidationException */ - public function validate(?string $scenario = null) + public function validate(?string $scenario = null): void { $errors = $this->valid($scenario); if ($errors !== true) { @@ -118,7 +120,7 @@ public function validate(?string $scenario = null) * @return array|true True if valid, errors array if invalid. * @throws Exception */ - public function valid(?string $scenario = null) + public function valid(?string $scenario = null): array|true { $valid = $this->getValidator(); diff --git a/src/Secrets.php b/src/Secrets.php index 28efd42..6257b1e 100644 --- a/src/Secrets.php +++ b/src/Secrets.php @@ -136,7 +136,7 @@ public static function create(array $config = []) /** @inheritdoc */ - public function update($config) + public function update(iterable $config): void { parent::update($config); $this->key_pattern = $this->buildPattern($this->key_rules); diff --git a/src/SortFieldsTrait.php b/src/SortFieldsTrait.php index 850dbb6..b183cf8 100644 --- a/src/SortFieldsTrait.php +++ b/src/SortFieldsTrait.php @@ -6,6 +6,8 @@ namespace karmabunny\kb; +use karmabunny\interfaces\SortableInterface; + /** * A simple sorter for object. * @@ -16,9 +18,9 @@ * * All comparisons are done with the spaceship operator. * - * @see Sortable * @see Arrays::sort * + * @mixin SortableInterface * @package karmabunny\kb */ trait SortFieldsTrait @@ -48,7 +50,7 @@ public abstract function getSortKey(): string; * @param string $mode * @return int */ - public function compare($other, $mode = 'default'): int + public function compare(mixed $other, string $mode = 'default'): int { if ($other instanceof static) { // Our default sort key. diff --git a/src/ToJsonTrait.php b/src/ToJsonTrait.php index bad5d40..afb6099 100755 --- a/src/ToJsonTrait.php +++ b/src/ToJsonTrait.php @@ -8,6 +8,9 @@ * JSON builders for models. * * This builds on the 'Arrayable' interface. + * + * @mixin ArrayableInterface + * @mixin JsonSerializable */ trait ToJsonTrait { diff --git a/src/UpdateStrictTrait.php b/src/UpdateStrictTrait.php index bb9f7dc..cdc6292 100644 --- a/src/UpdateStrictTrait.php +++ b/src/UpdateStrictTrait.php @@ -7,6 +7,7 @@ namespace karmabunny\kb; use InvalidArgumentException; +use karmabunny\interfaces\ConfigurableInterface; /** * This modifies the behaviour of a DataObject/Collection so that only @@ -15,6 +16,7 @@ * This extends the behaviour of {@see UpdateTidyTrait}, where it will throw * errors if a field is missing instead of silently ignoring it. * + * @mixin ConfigurableInterface * @package karmabunny\kb */ trait UpdateStrictTrait @@ -26,7 +28,7 @@ trait UpdateStrictTrait * @param iterable $config * @return void */ - public function update($config) + public function update(iterable $config): void { $fields = array_fill_keys(static::getProperties(), true); diff --git a/src/UpdateTidyTrait.php b/src/UpdateTidyTrait.php index d97564d..1f3b9e6 100644 --- a/src/UpdateTidyTrait.php +++ b/src/UpdateTidyTrait.php @@ -6,12 +6,15 @@ namespace karmabunny\kb; +use karmabunny\interfaces\ConfigurableInterface; + /** * This is functional the same as {@see UpdateTrait} only it uses the * `getProperties()` helper to determine which fields belong to the class. * * To raise errors on unknown fields {@see UpdateStrictTrait}. * + * @mixin ConfigurableInterface * @package karmabunny\kb */ trait UpdateTidyTrait @@ -23,7 +26,7 @@ trait UpdateTidyTrait * @param iterable $config * @return void */ - public function update($config) + public function update(iterable $config): void { $fields = array_fill_keys(static::getProperties(), true); diff --git a/src/UpdateTrait.php b/src/UpdateTrait.php index f16098f..8bc62d6 100644 --- a/src/UpdateTrait.php +++ b/src/UpdateTrait.php @@ -6,6 +6,8 @@ namespace karmabunny\kb; +use karmabunny\interfaces\ConfigurableInterface; + /** * This implements basic `update()` behaviour for an object. * @@ -14,6 +16,7 @@ * * To raise errors on unknown fields {@see UpdateStrictTrait}. * + * @mixin ConfigurableInterface * @package karmabunny\kb */ trait UpdateTrait @@ -23,7 +26,7 @@ trait UpdateTrait * @param iterable $config * @return void */ - public function update($config) + public function update(iterable $config): void { foreach ($config as $key => $item) { if (!property_exists($this, $key)) continue; diff --git a/src/ValidErrorsTrait.php b/src/ValidErrorsTrait.php index 66c8980..fffe2f1 100644 --- a/src/ValidErrorsTrait.php +++ b/src/ValidErrorsTrait.php @@ -2,10 +2,13 @@ namespace karmabunny\kb; +use karmabunny\interfaces\ValidatesInterface; + /** * This extends the Validates interface with a `valid()` method that returns a * boolean. The errors are stored in the model. * + * @mixin ValidatesInterface * @package karmabunny\kb */ trait ValidErrorsTrait @@ -25,7 +28,7 @@ trait ValidErrorsTrait * @param string|null $scenario * @throws ValidationException */ - public abstract function validate(?string $scenario = null); + public abstract function validate(?string $scenario = null): void; /** diff --git a/src/VirtualArrayTrait.php b/src/VirtualArrayTrait.php index f615742..97058fa 100644 --- a/src/VirtualArrayTrait.php +++ b/src/VirtualArrayTrait.php @@ -10,6 +10,7 @@ /** * + * @mixin ArrayAccess */ trait VirtualArrayTrait { diff --git a/src/VirtualMethodsTrait.php b/src/VirtualMethodsTrait.php index f4502ea..907d19f 100644 --- a/src/VirtualMethodsTrait.php +++ b/src/VirtualMethodsTrait.php @@ -17,7 +17,7 @@ trait VirtualMethodsTrait * @param mixed $name * @return mixed */ - public function __get($name) + public function __get(mixed $name): mixed { // TODO Test this. if ($value = parent::__get($name)) return $value; diff --git a/src/rules/AllInArrayRule.php b/src/rules/AllInArrayRule.php index 273813d..eb66dfb 100644 --- a/src/rules/AllInArrayRule.php +++ b/src/rules/AllInArrayRule.php @@ -23,7 +23,7 @@ class AllInArrayRule extends BaseRule /** @inheritdoc */ - public function parse(array $ruleset) + public function parse(array $ruleset): void { parent::parse($ruleset); @@ -36,7 +36,7 @@ public function parse(array $ruleset) /** @inheritdoc */ - public function validateOne(string $field, $value) + public function validateOne(string $field, mixed $value): void { if (empty($this->allowed)) { return; diff --git a/src/rules/AllMatchRule.php b/src/rules/AllMatchRule.php index fe4227c..93e3b9a 100644 --- a/src/rules/AllMatchRule.php +++ b/src/rules/AllMatchRule.php @@ -18,7 +18,7 @@ class AllMatchRule extends BaseRule { /** @inheritdoc */ - public function validate($data) + public function validate(array|object $data): void { $values = $this->getFieldValues($data); $unique = array_unique($values); diff --git a/src/rules/AllUniqueRule.php b/src/rules/AllUniqueRule.php index 421e91d..cd9dcd0 100644 --- a/src/rules/AllUniqueRule.php +++ b/src/rules/AllUniqueRule.php @@ -18,7 +18,7 @@ class AllUniqueRule extends BaseRule { /** @inheritdoc */ - public function validate($data) + public function validate(array|object $data): void { $values = $this->getFieldValues($data); $unique = array_unique($values); diff --git a/src/rules/BinaryRule.php b/src/rules/BinaryRule.php index bdf61a0..fed0d4e 100644 --- a/src/rules/BinaryRule.php +++ b/src/rules/BinaryRule.php @@ -18,7 +18,7 @@ class BinaryRule extends BaseRule { /** @inheritdoc */ - public function validateOne(string $field, $value) + public function validateOne(string $field, mixed $value): void { if ($value !== '1' and $value !== 1 and $value !== '0' and $value !== 0) { throw new ValidationException('Value must be a "1" or "0"'); diff --git a/src/rules/DateRangeRule.php b/src/rules/DateRangeRule.php index e5639ea..f12fa36 100644 --- a/src/rules/DateRangeRule.php +++ b/src/rules/DateRangeRule.php @@ -26,7 +26,7 @@ class DateRangeRule extends BaseRule /** @inheritdoc */ - public function parse(array $ruleset) + public function parse(array $ruleset): void { parent::parse($ruleset); @@ -44,7 +44,7 @@ public function parse(array $ruleset) /** @inheritdoc */ - public function validate($data) + public function validate(array|object $data): void { if (count($this->fields) != 2) { return; diff --git a/src/rules/EmailRule.php b/src/rules/EmailRule.php index 8cbe3af..3560788 100644 --- a/src/rules/EmailRule.php +++ b/src/rules/EmailRule.php @@ -21,7 +21,7 @@ class EmailRule extends BaseRule { /** @inheritdoc */ - public function validateOne(string $field, $value) + public function validateOne(string $field, mixed $value): void { $regex = '/^[^@]+@[^@.]+\.[^@]+$/iD'; diff --git a/src/rules/InArrayRule.php b/src/rules/InArrayRule.php index bb50556..e5f7280 100644 --- a/src/rules/InArrayRule.php +++ b/src/rules/InArrayRule.php @@ -23,7 +23,7 @@ class InArrayRule extends BaseRule /** @inheritdoc */ - public function parse(array $ruleset) + public function parse(array $ruleset): void { parent::parse($ruleset); @@ -36,7 +36,7 @@ public function parse(array $ruleset) /** @inheritdoc */ - public function validateOne(string $field, $value) + public function validateOne(string $field, mixed $value): void { if (empty($this->allowed)) { return; diff --git a/src/rules/Ipv4AddrOrCidrRule.php b/src/rules/Ipv4AddrOrCidrRule.php index 5a90b44..484fcca 100644 --- a/src/rules/Ipv4AddrOrCidrRule.php +++ b/src/rules/Ipv4AddrOrCidrRule.php @@ -17,7 +17,7 @@ class Ipv4AddrOrCidrRule extends BaseRule { /** @inheritdoc */ - public function validateOne(string $field, $value) + public function validateOne(string $field, mixed $value): void { if (strpos($value, '/') === false) { $rule = new Ipv4AddrRule(); diff --git a/src/rules/Ipv4AddrRule.php b/src/rules/Ipv4AddrRule.php index cca2ef0..57ed388 100644 --- a/src/rules/Ipv4AddrRule.php +++ b/src/rules/Ipv4AddrRule.php @@ -18,7 +18,7 @@ class Ipv4AddrRule extends BaseRule { /** @inheritdoc */ - public function validateOne(string $field, $value) + public function validateOne(string $field, mixed $value): void { if (!preg_match('/^[0-9]+(?:\.[0-9]+){3}$/', $value)) { throw new ValidationException('Invalid IP address'); diff --git a/src/rules/Ipv4CidrRule.php b/src/rules/Ipv4CidrRule.php index 69dfc45..9ce3996 100644 --- a/src/rules/Ipv4CidrRule.php +++ b/src/rules/Ipv4CidrRule.php @@ -18,7 +18,7 @@ class Ipv4CidrRule extends BaseRule { /** @inheritdoc */ - public function validateOne(string $field, $value) + public function validateOne(string $field, mixed $value): void { if (strpos($value, '/') === false) { throw new ValidationException('Invalid CIDR block'); diff --git a/src/rules/LengthRule.php b/src/rules/LengthRule.php index 3399549..0f14883 100644 --- a/src/rules/LengthRule.php +++ b/src/rules/LengthRule.php @@ -30,7 +30,7 @@ class LengthRule extends BaseRule /** @inheritdoc */ - public function parse(array $ruleset) + public function parse(array $ruleset): void { parent::parse($ruleset); @@ -40,7 +40,7 @@ public function parse(array $ruleset) /** @inheritdoc */ - public function validateOne(string $field, $value) + public function validateOne(string $field, mixed $value): void { $len = mb_strlen($value); diff --git a/src/rules/MysqlDateRule.php b/src/rules/MysqlDateRule.php index f9a9ef0..b3b5c6d 100644 --- a/src/rules/MysqlDateRule.php +++ b/src/rules/MysqlDateRule.php @@ -25,7 +25,7 @@ public static function getName(): string /** @inheritdoc */ - public function validateOne(string $field, $value) + public function validateOne(string $field, mixed $value): void { $matches = null; if (!preg_match('/^([0-9]{4})-([0-9]{2})-([0-9]{2})$/', $value, $matches)) { diff --git a/src/rules/MysqlDateTimeRule.php b/src/rules/MysqlDateTimeRule.php index 7a78069..e6fa88b 100644 --- a/src/rules/MysqlDateTimeRule.php +++ b/src/rules/MysqlDateTimeRule.php @@ -25,7 +25,7 @@ public static function getName(): string /** @inheritdoc */ - public function validateOne(string $field, $value) + public function validateOne(string $field, mixed $value): void { $matches = null; if (!preg_match('/^([0-9]{4}-[0-9]{2}-[0-9]{2}) ([0-9]{2}:[0-9]{2}:[0-9]{2})$/', $value, $matches)) { diff --git a/src/rules/MysqlTimeRule.php b/src/rules/MysqlTimeRule.php index 46283b8..b05caff 100644 --- a/src/rules/MysqlTimeRule.php +++ b/src/rules/MysqlTimeRule.php @@ -25,7 +25,7 @@ public static function getName(): string /** @inheritdoc */ - public function validateOne(string $field, $value) + public function validateOne(string $field, mixed $value): void { $matches = null; if (!preg_match('/^([0-9]{2}):([0-9]{2}):([0-9]{2})$/', $value, $matches)) { diff --git a/src/rules/NumericRule.php b/src/rules/NumericRule.php index 8ce04b6..80ff61f 100644 --- a/src/rules/NumericRule.php +++ b/src/rules/NumericRule.php @@ -18,7 +18,7 @@ class NumericRule extends BaseRule { /** @inheritdoc */ - public function validateOne(string $field, $value) + public function validateOne(string $field, mixed $value): void { if (!is_numeric($value)) { throw new ValidationException('Value must be a number'); diff --git a/src/rules/OneRequiredRule.php b/src/rules/OneRequiredRule.php index 1d4019a..f08e35b 100644 --- a/src/rules/OneRequiredRule.php +++ b/src/rules/OneRequiredRule.php @@ -19,7 +19,7 @@ class OneRequiredRule extends BaseRule /** @var string|null */ public $group; - public function parse(array $ruleset) + public function parse(array $ruleset): void { parent::parse($ruleset); @@ -28,7 +28,7 @@ public function parse(array $ruleset) /** @inheritdoc */ - public function validate($data) + public function validate(array|object $data): void { $values = $this->getFieldValues($data); diff --git a/src/rules/PasswordRule.php b/src/rules/PasswordRule.php index c28a8ae..6157592 100644 --- a/src/rules/PasswordRule.php +++ b/src/rules/PasswordRule.php @@ -22,7 +22,7 @@ class PasswordRule extends BaseRule /** @inheritdoc */ - public function parse(array $ruleset) + public function parse(array $ruleset): void { parent::parse($ruleset); @@ -33,7 +33,7 @@ public function parse(array $ruleset) /** @inheritdoc */ - public function validateOne(string $field, $value) + public function validateOne(string $field, mixed $value): void { $errors = []; diff --git a/src/rules/PhoneRule.php b/src/rules/PhoneRule.php index b5cc141..5d6cc2e 100644 --- a/src/rules/PhoneRule.php +++ b/src/rules/PhoneRule.php @@ -21,7 +21,7 @@ class PhoneRule extends BaseRule /** @inheritdoc */ - public function parse(array $ruleset) + public function parse(array $ruleset): void { parent::parse($ruleset); @@ -32,7 +32,7 @@ public function parse(array $ruleset) /** @inheritdoc */ - public function validateOne(string $field, $value) + public function validateOne(string $field, mixed $value): void { // Allow international numbers starting with + and country code, e.g. +61 for Australia $clean = preg_replace('/^\+[0-9]+ */', '', $value); diff --git a/src/rules/PositiveIntRule.php b/src/rules/PositiveIntRule.php index e2420b4..922319b 100644 --- a/src/rules/PositiveIntRule.php +++ b/src/rules/PositiveIntRule.php @@ -18,7 +18,7 @@ class PositiveIntRule extends BaseRule { /** @inheritdoc */ - public function validateOne(string $field, $value) + public function validateOne(string $field, mixed $value): void { if (preg_match('/[^0-9]/', $value)) { throw new ValidationException("Value must be a whole number that is greater than zero"); diff --git a/src/rules/ProseTextRule.php b/src/rules/ProseTextRule.php index 4424eeb..47a7295 100644 --- a/src/rules/ProseTextRule.php +++ b/src/rules/ProseTextRule.php @@ -23,7 +23,7 @@ class ProseTextRule extends BaseRule /** @inheritdoc */ - public function validateOne(string $field, $value) + public function validateOne(string $field, mixed $value): void { // pL = letters, pN = numbers if (preg_match('/[^-\pL\pN \'"\/!?@#$%&():;.,]/u', (string) $value)) { diff --git a/src/rules/RangeRule.php b/src/rules/RangeRule.php index 5a534e8..d793ff5 100644 --- a/src/rules/RangeRule.php +++ b/src/rules/RangeRule.php @@ -24,7 +24,7 @@ class RangeRule extends BaseRule /** @inheritdoc */ - public function parse(array $ruleset) + public function parse(array $ruleset): void { parent::parse($ruleset); @@ -44,7 +44,7 @@ public function parse(array $ruleset) /** @inheritdoc */ - public function validateOne(string $field, $value) + public function validateOne(string $field, mixed $value): void { if (!is_numeric($value)) { throw new ValidationException('Value must be a number'); diff --git a/src/rules/RegexRule.php b/src/rules/RegexRule.php index c6698b2..045b81a 100644 --- a/src/rules/RegexRule.php +++ b/src/rules/RegexRule.php @@ -22,7 +22,7 @@ class RegexRule extends BaseRule /** @inheritdoc */ - public function parse(array $ruleset) + public function parse(array $ruleset): void { parent::parse($ruleset); @@ -35,7 +35,7 @@ public function parse(array $ruleset) /** @inheritdoc */ - public function validateOne(string $field, $value) + public function validateOne(string $field, mixed $value): void { if (!$this->pattern) { return; diff --git a/src/rules/RequiredRule.php b/src/rules/RequiredRule.php index 7bfef71..ded4f73 100644 --- a/src/rules/RequiredRule.php +++ b/src/rules/RequiredRule.php @@ -22,7 +22,7 @@ class RequiredRule extends BaseRule { /** @inheritdoc */ - public function validate($data) + public function validate(array|object $data): void { if (empty($this->fields)) { return; From db6a17a7703a42b0c7de994612b59624d3758d02 Mon Sep 17 00:00:00 2001 From: Gwilyn Date: Fri, 17 Jul 2026 13:32:32 +1000 Subject: [PATCH 16/22] Add more strong types. --- src/BaseRule.php | 2 +- src/Buffer.php | 6 +-- src/CachedHelperTrait.php | 6 +-- src/CallbackRule.php | 6 +-- src/ConfigureTrait.php | 2 +- src/CountryNames.php | 8 ++-- src/CountryZones.php | 2 +- src/CsvExport.php | 20 ++++----- src/CsvImport.php | 34 +++++++------- src/DirtyChecksums.php | 14 +++--- src/DocType.php | 14 +++--- src/DocValidator.php | 8 ++-- src/Enc.php | 22 +++++----- src/Encrypt.php | 2 +- src/Env.php | 10 ++--- src/Event.php | 4 +- src/EventableTrait.php | 2 +- src/Events.php | 4 +- src/Generate.php | 18 ++++---- src/HttpStatus.php | 2 + src/Inflector.php | 27 ++++++------ src/Job.php | 10 ++--- src/Log.php | 15 ++++--- src/LoggerTrait.php | 2 +- src/RulesClassValidator.php | 28 ++++++------ src/RulesStaticValidator.php | 54 +++++++++++------------ src/Secrets.php | 24 +++++----- src/Security.php | 14 +++--- src/Shell.php | 8 ++-- src/ShellOptions.php | 22 +++++----- src/ShellOutput.php | 18 ++++---- src/Text.php | 32 +++++++------- src/Time.php | 48 ++++++++++---------- src/TimeZones.php | 2 +- src/Url.php | 40 ++++++++--------- src/UrlDecodeException.php | 4 +- src/Uuid.php | 4 +- src/ValidationException.php | 4 +- src/Validity.php | 83 +++++++++++++++++++---------------- src/Wrap.php | 10 ++--- src/XMLException.php | 2 +- src/rules/AllInArrayRule.php | 2 +- src/rules/DateRangeRule.php | 6 +-- src/rules/InArrayRule.php | 2 +- src/rules/LengthRule.php | 4 +- src/rules/OneRequiredRule.php | 2 +- src/rules/PasswordRule.php | 2 +- src/rules/PhoneRule.php | 2 +- src/rules/RangeRule.php | 4 +- src/rules/RegexRule.php | 2 +- 50 files changed, 335 insertions(+), 328 deletions(-) diff --git a/src/BaseRule.php b/src/BaseRule.php index 86683b5..d546236 100644 --- a/src/BaseRule.php +++ b/src/BaseRule.php @@ -29,7 +29,7 @@ abstract class BaseRule implements RuleInterface { /** @var string[] */ - public $fields = []; + public array $fields = []; /** @inheritdoc */ diff --git a/src/Buffer.php b/src/Buffer.php index a43c12f..bac4bcc 100644 --- a/src/Buffer.php +++ b/src/Buffer.php @@ -103,7 +103,7 @@ public function flush(bool $send = true) * * @return void */ - public function discard() + public function discard(): void { if (!$this->level()) { return; @@ -225,7 +225,7 @@ public function end(bool $flush = true): void * * @return void */ - public static function closeAll() + public static function closeAll(): void { while (ob_get_level()) ob_end_clean(); } @@ -236,7 +236,7 @@ public static function closeAll() * * @return void */ - public static function flushAll() + public static function flushAll(): void { while (ob_get_level()) ob_end_flush(); } diff --git a/src/CachedHelperTrait.php b/src/CachedHelperTrait.php index 133c1a0..a259108 100644 --- a/src/CachedHelperTrait.php +++ b/src/CachedHelperTrait.php @@ -44,7 +44,7 @@ trait CachedHelperTrait * @param string|null $key * @return void */ - protected function clearCache(?string $key = null) + protected function clearCache(?string $key = null): void { if ($key) { unset($this->_cache[$key]); @@ -109,7 +109,7 @@ protected function getCachedIterable(string $id, $fn): array * @param callable $fn () => mixed * @return mixed function result */ - protected function getCachedValue(string $id, $fn) + protected function getCachedValue(string $id, $fn): mixed { if (!array_key_exists($id, $this->_cache)) { $this->_cache[$id] = $fn(); @@ -129,7 +129,7 @@ protected function getCachedValue(string $id, $fn) * @param mixed $fn (...$inputs) => mixed * @return mixed */ - protected function getCachedResult(array $inputs, $fn) + protected function getCachedResult(array $inputs, $fn): mixed { $key = sha1(serialize($inputs)); diff --git a/src/CallbackRule.php b/src/CallbackRule.php index efe76d4..0a19ee0 100644 --- a/src/CallbackRule.php +++ b/src/CallbackRule.php @@ -20,12 +20,12 @@ class CallbackRule extends BaseRule { /** @var callable|null */ - public $callable; + public mixed $callable = null; /** @var array */ - public $args = []; + public array $args = []; - public $multi = false; + public bool $multi = false; /** @inheritdoc */ diff --git a/src/ConfigureTrait.php b/src/ConfigureTrait.php index 374a047..e3ca7f7 100644 --- a/src/ConfigureTrait.php +++ b/src/ConfigureTrait.php @@ -43,7 +43,7 @@ trait ConfigureTrait * @return object * @throws InvalidArgumentException */ - public static function configure($config, ?string $assert = null, bool $init = true) + public static function configure($config, ?string $assert = null, bool $init = true): object { return Configure::configure($config, $assert, $init); } diff --git a/src/CountryNames.php b/src/CountryNames.php index 65086f3..092c481 100644 --- a/src/CountryNames.php +++ b/src/CountryNames.php @@ -299,7 +299,7 @@ public static function getAlpha3(): array * @param string $code alpha-2 * @return string|null alpha-3 */ - public static function getAlpha3From2(string $code) + public static function getAlpha3From2(string $code): ?string { $code = strtoupper(trim($code)); if (strlen($code) == 3) return $code; @@ -313,7 +313,7 @@ public static function getAlpha3From2(string $code) * @param string $code alpha-3 * @return string|null alpha-2 */ - public static function getAlpha2From3(string $code) + public static function getAlpha2From3(string $code): ?string { $code = strtoupper(trim($code)); if (strlen($code) == 2) return $code; @@ -329,7 +329,7 @@ public static function getAlpha2From3(string $code) * @param string $language default 'en' * @return string|null */ - public static function getCountryCode(string $country_name, string $language = 'en') + public static function getCountryCode(string $country_name, string $language = 'en'): ?string { if (strlen($language) != 2) return null; $language = strtoupper($language); @@ -369,7 +369,7 @@ public static function getCountryCode(string $country_name, string $language = ' * @param string $language default 'en' * @return string|null */ - public static function getCountryName(string $country_code, string $language = 'en') + public static function getCountryName(string $country_code, string $language = 'en'): ?string { if (strlen($language) != 2) return null; $language = strtoupper($language); diff --git a/src/CountryZones.php b/src/CountryZones.php index 11ebdb4..58e0fb1 100644 --- a/src/CountryZones.php +++ b/src/CountryZones.php @@ -80,7 +80,7 @@ public static function getZones(string $country): array * @param bool $alpha3 * @return null|string */ - public static function lookup(string $zone, $alpha3 = false): ?string + public static function lookup(string $zone, bool $alpha3 = false): ?string { $map = self::getMap(); $zone = $map[$zone] ?? null; diff --git a/src/CsvExport.php b/src/CsvExport.php index c840728..7b6fa52 100644 --- a/src/CsvExport.php +++ b/src/CsvExport.php @@ -27,34 +27,34 @@ class CsvExport const DIRTY_CHARS = ' "\r\n\t'; /** @var resource */ - public $handle; + public mixed $handle; /** @var array */ - public $formatters = []; + public array $formatters = []; /** @var string Only supported in PHP 8.1+ */ - public $break = "\n"; + public string $break = "\n"; /** @var string */ - public $delimiter = ','; + public string $delimiter = ','; /** @var string */ - public $null = '\N'; + public string $null = '\N'; /** @var string */ - public $enclosure = '"'; + public string $enclosure = '"'; /** @var string */ - public $escape = '\\'; + public string $escape = '\\'; /** @var array|null */ - public $headers = null; + public array|null $headers = null; /** @var string */ - private $dirty_re; + private string $dirty_re; /** @var bool */ - private $_own_handles = false; + private bool $_own_handles = false; /** * Configure the CSV output format. diff --git a/src/CsvImport.php b/src/CsvImport.php index e06fe49..9cc25c5 100644 --- a/src/CsvImport.php +++ b/src/CsvImport.php @@ -24,31 +24,31 @@ class CsvImport implements IteratorAggregate const MAX_MEMORY = 5 * 1024 * 1024; /** @var string */ - public $break = "\n"; + public string $break = "\n"; /** @var string */ - public $delimiter = ','; + public string $delimiter = ','; /** @var string */ - public $null = '\N'; + public string $null = '\N'; /** @var string */ - public $enclosure = '"'; + public string $enclosure = '"'; /** @var string */ - public $escape = '\\'; + public string $escape = '\\'; /** @var array|null */ - public $headers = null; + public array|null $headers = null; /** @var bool This importer manages it's own handles. */ - private $_own_handles = false; + private bool $_own_handles = false; /** @var string */ - private $_escape_re; + private string $_escape_re; /** @var resource|null */ - private $handle; + private mixed $handle = null; /** * Configure the CSV output format. @@ -82,14 +82,14 @@ public function __construct($handle, $config = []) * * @param string $filename * @param array $config - * @return null|CsvImport + * @return null|self */ - public static function fromFile(string $filename, $config = []) + public static function fromFile(string $filename, $config = []): ?self { $handle = @fopen($filename, 'r'); if ($handle === false) return null; - $importer = new CsvImport($handle, $config); + $importer = new self($handle, $config); $importer->_own_handles = true; return $importer; } @@ -100,9 +100,9 @@ public static function fromFile(string $filename, $config = []) * * @param string $csv * @param array $config - * @return null|CsvImport + * @return null|self */ - public static function fromString(string $csv, $config = []) + public static function fromString(string $csv, $config = []): ?self { $handle = @fopen('php://temp/maxmemory:' . self::MAX_MEMORY, 'r+'); if ($handle === false) return null; @@ -110,7 +110,7 @@ public static function fromString(string $csv, $config = []) fputs($handle, $csv); rewind($handle); - $importer = new CsvImport($handle, $config); + $importer = new self($handle, $config); $importer->_own_handles = true; return $importer; } @@ -149,7 +149,7 @@ public function getHeaders(): array * * @return null|array An associated array or null if EOF. */ - public function getLine() + public function getLine(): ?array { // Load in headers from the first row. $this->getHeaders(); @@ -186,7 +186,7 @@ public function getIterator(): Traversable * * @return null|array row values or null if EOF. */ - private function _getcsv() + private function _getcsv(): ?array { if ($this->handle === null) return null; diff --git a/src/DirtyChecksums.php b/src/DirtyChecksums.php index d69818c..4fc4c7d 100644 --- a/src/DirtyChecksums.php +++ b/src/DirtyChecksums.php @@ -19,10 +19,10 @@ class DirtyChecksums implements NotSerializable { /** @var string[] [ name => sha ] */ - public $checksums = []; + public array $checksums = []; /** @var object */ - public $target; + public object $target; /** @@ -47,7 +47,7 @@ public function __construct($target) * @param mixed $value * @return string */ - protected function getChecksum($value): string + protected function getChecksum(mixed $value): string { if ( $value === null @@ -94,7 +94,7 @@ protected function getProperties(): Traversable * * @return void */ - public function reset() + public function reset(): void { $this->checksums = []; } @@ -107,7 +107,7 @@ public function reset() * * @return void */ - public function update() + public function update(): void { foreach ($this->getProperties() as $name => $value) { $this->checksums[$name] = $this->getChecksum($value); @@ -135,7 +135,7 @@ public function updateField(string $name) * @param string $name * @return void */ - public function markDirty(string $name) + public function markDirty(string $name): void { if (property_exists($this->target, $name)) { $this->checksums[$name] = 'DIRTY'; @@ -149,7 +149,7 @@ public function markDirty(string $name) * @param string $name * @return bool */ - public function isDirty(string $name) + public function isDirty(string $name): bool { // Don't know about this one. Not dirty. if (!property_exists($this->target, $name)) { diff --git a/src/DocType.php b/src/DocType.php index 2ad6956..1abe15c 100644 --- a/src/DocType.php +++ b/src/DocType.php @@ -19,16 +19,16 @@ class DocType extends Collection { /** @var string */ - public $name; + public string $name; /** @var string */ - public $comment; + public string $comment; /** @var mixed */ - public $value; + public mixed $value; /** @var string[]|null */ - private $_doc_types; + private array|null $_doc_types = null; /** @@ -62,7 +62,7 @@ public function getValueType(): string * @param mixed $value * @return string */ - public static function parseValueType($value): string + public static function parseValueType(mixed $value): string { if (is_array($value)) { $value = Arrays::first($value); @@ -103,9 +103,9 @@ public static function parseValueType($value): string * Returns an array of all type strings. * * @param string $comment - * @return string[]|null Null if missing/invalid. + * @return string[] empty if missing/invalid. */ - public static function parseCommentTypes(string $comment) + public static function parseCommentTypes(string $comment): array { if (!$comment) return []; diff --git a/src/DocValidator.php b/src/DocValidator.php index 53dbd33..9fbcfb9 100644 --- a/src/DocValidator.php +++ b/src/DocValidator.php @@ -47,7 +47,7 @@ class DocValidator implements ValidatorInterface * * @param object $target Object to validate. */ - public function __construct($target) + public function __construct(object $target) { $this->target = $target; $this->errors = []; @@ -167,7 +167,7 @@ public function checkTypes(DocType $type): bool * @param object $target * @return Generator */ - public static function getDocTypes($target): Generator + public static function getDocTypes(object $target): Generator { $class = new ReflectionClass($target); $properties = $class->getProperties(ReflectionProperty::IS_PUBLIC); @@ -197,7 +197,7 @@ public static function getDocTypes($target): Generator * @param mixed $value real value * @return bool True if valid. */ - protected function isValid(string $expected, $value): bool + protected function isValid(string $expected, mixed $value): bool { if ($value === null and $expected === 'null') { return true; @@ -309,7 +309,7 @@ protected function isValidArray(string $expected, array $values): bool * @param string $name * @return string|null null if not found. */ - protected function lookupClass(string $name) + protected function lookupClass(string $name): ?string { if (!trim($name)) return null; diff --git a/src/Enc.php b/src/Enc.php index cceb067..7fd27bc 100644 --- a/src/Enc.php +++ b/src/Enc.php @@ -20,11 +20,11 @@ class Enc * Funky stuff is anything in the ASCII control plane (0x00 - 0x1F) * Except tab, line feed, carriage return **/ - public static function cleanfunky($value) + public static function cleanfunky(mixed $value): string { if (is_array($value)) return ''; if (is_object($value)) return ''; - return preg_replace('![\x00-\x08\x0B\x0C\x0E-\x1F]!', '', (string) $value); + return preg_replace('![\x00-\x08\x0B\x0C\x0E-\x1F]!', '', (string) $value) ?: ''; } /** @@ -35,7 +35,7 @@ public static function cleanfunky($value) * @example $html = Enc::html('A & B'); // returns A & B * @example $bad_html = Enc::html('A & B'); // don't do this; returns A &amp; B */ - public static function html($value) + public static function html(mixed $value): string { return htmlspecialchars(self::cleanfunky($value), ENT_COMPAT, 'UTF-8'); } @@ -47,9 +47,9 @@ public static function html($value) * @example $html = Enc::html('A & B'); // returns A & B * @example $html = Enc::html('A & B'); // this is fine; returns A & B */ - public static function htmlNoDup($value) + public static function htmlNoDup(mixed $value): string { - return htmlspecialchars(self::cleanfunky($value), ENT_COMPAT, 'UTF-8', false); + return htmlspecialchars(self::cleanfunky($value), ENT_COMPAT, 'UTF-8', false) ?: ''; } /** @@ -57,7 +57,7 @@ public static function htmlNoDup($value) * * @param string $value The value to encode **/ - public static function xml($value) + public static function xml(mixed $value): string { $value = self::cleanfunky($value); $value = preg_replace('/[\s\r\n][\s\r\n]+/', "\n", $value); @@ -69,7 +69,7 @@ public static function xml($value) * * @param string $value The value to encode **/ - public static function url($value) + public static function url(mixed $value): string { return urlencode(self::cleanfunky($value)); } @@ -79,7 +79,7 @@ public static function url($value) * * @param string $value The value to encode **/ - public static function id($value) + public static function id(mixed $value): string { $value = self::cleanfunky($value); $value = trim($value); @@ -112,7 +112,7 @@ public static function js($value) * * @param string $value The value to encode **/ - public static function httpfield($value) + public static function httpfield(mixed $value): string { $value = self::cleanfunky($value); $value = str_replace(' ', '_', $value); @@ -131,7 +131,7 @@ public static function httpfield($value) * @param string $value The value to encode * @return string */ - public static function urlname($value, $delimiter = '-') + public static function urlname(mixed $value, string $delimiter = '-'): string { $value = self::cleanfunky($value); $value = strtolower(trim($value, "&_- \t\n\r\0\x0B")); @@ -162,7 +162,7 @@ public static function urlname($value, $delimiter = '-') * @param string $from What format the date was in origanally. * @return string|null JavaScript snippet for the given date or NULL if the input value is invalid **/ - public static function jsdate($value, $from = 'mysql') + public static function jsdate(mixed $value, string $from = 'mysql'): ?string { $day = null; $month = null; diff --git a/src/Encrypt.php b/src/Encrypt.php index 2d42fbd..55c4562 100644 --- a/src/Encrypt.php +++ b/src/Encrypt.php @@ -16,7 +16,7 @@ class Encrypt implements EncryptInterface { /** @var array */ - protected $config; + protected array $config; /** diff --git a/src/Env.php b/src/Env.php index 6c77665..5744df8 100644 --- a/src/Env.php +++ b/src/Env.php @@ -34,13 +34,13 @@ class Env ]; /** The key name to determine the current environment mode. */ - static $ENV_NAME = 'SITES_ENVIRONMENT'; + public static string $ENV_NAME = 'SITES_ENVIRONMENT'; /** The default environment, default 'DEV'. */ - static $DEFAULT = self::DEV; + public static string $DEFAULT = self::DEV; /** @var string[]|null */ - static $config; + public static ?array $config = null; /** @@ -52,7 +52,7 @@ class Env * @param array $config (ENV_NAME, DEFAULT) * @return void */ - public static function config(array $config) + public static function config(array $config): void { self::$ENV_NAME = $config['ENV_NAME'] ?? self::$ENV_NAME; self::$DEFAULT = $config['DEFAULT'] ?? self::$DEFAULT; @@ -148,7 +148,7 @@ protected static function load(): array * @param string $key * @return string|null */ - public static function get(string $key) + public static function get(string $key): ?string { $config = self::load(); return $config[$key] ?? null; diff --git a/src/Event.php b/src/Event.php index ee72881..98db447 100644 --- a/src/Event.php +++ b/src/Event.php @@ -17,9 +17,9 @@ abstract class Event extends DataObject implements EventInterface { /** @var object|null */ - public $sender; + public ?object $sender = null; /** @var bool */ - public $handled = false; + public bool $handled = false; } diff --git a/src/EventableTrait.php b/src/EventableTrait.php index 160bee8..1b14259 100644 --- a/src/EventableTrait.php +++ b/src/EventableTrait.php @@ -77,7 +77,7 @@ protected function trigger(?string $class, EventInterface $event, bool $once = f * @return void * @throws InvalidArgumentException */ - public function on(string|callable $event, ?callable $fn = null, bool $append = true) + public function on(string|callable $event, ?callable $fn = null, bool $append = true): void { // Unlike trigger, using dynamic class names here is OK. A user is not // surprised (hopefully) that they only receive events appropriate for diff --git a/src/Events.php b/src/Events.php index 0fad32e..1275b4f 100644 --- a/src/Events.php +++ b/src/Events.php @@ -75,7 +75,7 @@ class Events * @param bool $once Don't trigger if the event has already run at least once. * @return array[] event results. */ - public static function trigger($sender, EventInterface $event, bool $once = false): array + public static function trigger(string|object $sender, EventInterface $event, bool $once = false): array { // Events are ID'd by their full namespaced class name. if (is_object($sender)) { @@ -158,7 +158,7 @@ public static function trigger($sender, EventInterface $event, bool $once = fals * @return void * @throws InvalidArgumentException */ - public static function on(string|object $sender, string|callable $event, ?callable $fn = null, bool $append = true) + public static function on(string|object $sender, string|callable $event, ?callable $fn = null, bool $append = true): void { // Using some cheeky reflection we can extract the event type. if ($fn === null) { diff --git a/src/Generate.php b/src/Generate.php index ecb0f13..b179b74 100644 --- a/src/Generate.php +++ b/src/Generate.php @@ -15,16 +15,16 @@ class Generate { /** @var string */ - public $indent = ' '; + public string $indent = ' '; /** @var resource */ - protected $stream; + protected mixed $stream; /** @var bool */ - protected $close; + protected bool $close; /** @var int */ - protected $depth = 1; + protected int $depth = 1; /** @@ -32,7 +32,7 @@ class Generate * @param string|resource $target * @return void */ - public function __construct($target) + public function __construct(mixed $target) { if (is_string($target)) { $this->stream = fopen($target, 'w'); @@ -51,7 +51,7 @@ public function __construct($target) * * @return void */ - public function close() + public function close(): void { if ($this->close) { @fflush($this->stream); @@ -74,7 +74,7 @@ public function __destruct() * @param string $comment * @return void */ - public function comment(string $comment) + public function comment(string $comment): void { fwrite($this->stream, "// {$comment}\n"); } @@ -85,7 +85,7 @@ public function comment(string $comment) * @param array $array * @return void */ - public function write(array $array) + public function write(array $array): void { fwrite($this->stream, "return [\n"); @@ -103,7 +103,7 @@ public function write(array $array) * @param mixed $value * @return void */ - protected function writeItem($key, $value) + protected function writeItem(string|int|null $key, mixed $value): void { if ($key !== null and !is_int($key)) { $key = "'{$key}'"; diff --git a/src/HttpStatus.php b/src/HttpStatus.php index 43f0880..42e76a4 100644 --- a/src/HttpStatus.php +++ b/src/HttpStatus.php @@ -167,6 +167,8 @@ class HttpStatus /** * Status code strings. + * + * @var array */ const STRINGS = [ self::CONTINUE => 'Continue', diff --git a/src/Inflector.php b/src/Inflector.php index a370e4c..dabff1d 100644 --- a/src/Inflector.php +++ b/src/Inflector.php @@ -23,12 +23,13 @@ class Inflector extends DataObject implements InflectorInterface { - // Cached inflections - protected $_cache = []; + protected array $_cache = []; - // Uncountable and irregular words - public $uncountable = []; - public $irregular = []; + /** @var string[] */ + public array $uncountable = []; + + /** @var array */ + public array $irregular = []; /** @inheritdoc */ @@ -70,7 +71,7 @@ public function uncountable(string $word): bool * @param int $count number of things * @return string */ - public function singular($word, $count = 1): string + public function singular(string $word, int $count = 1): string { $key = "singular_{$word}_{$count}"; @@ -93,7 +94,7 @@ public function singular($word, $count = 1): string * @param int $count * @return string */ - public function plural($word, $count = 0): string + public function plural(string $word, int $count = 0): string { $key = "singular_{$word}_{$count}"; @@ -116,7 +117,7 @@ public function plural($word, $count = 0): string * @param int $count number of things * @return string */ - protected function _singular($word, $count = 1) + protected function _singular(string $word, int $count = 1): string { // Remove garbage $word = strtolower(trim($word)); @@ -163,7 +164,7 @@ protected function _singular($word, $count = 1) * @param int $count * @return string */ - protected function _plural($word, $count = 0) + protected function _plural(string $word, int $count = 0): string { // Remove garbage $word = strtolower(trim($word)); @@ -205,7 +206,7 @@ protected function _plural($word, $count = 0) * @param bool $first Upper case the first letter * @return string */ - public static function camelize($phrase, $first = true) + public static function camelize(string $phrase, bool $first = true): string { $phrase = self::humanize($phrase); $phrase = ucwords(preg_replace('/\s+/', ' ', $phrase)); @@ -225,7 +226,7 @@ public static function camelize($phrase, $first = true) * @param string $phrase * @return string */ - public static function underscore($phrase) + public static function underscore(string $phrase): string { $phrase = self::humanize($phrase); return preg_replace('/\s+/', '_', trim($phrase)); @@ -238,7 +239,7 @@ public static function underscore($phrase) * @param string $phrase * @return string */ - public static function kebab($phrase) + public static function kebab(string $phrase): string { $phrase = self::humanize($phrase); return preg_replace('/\s+/', '-', trim($phrase)); @@ -251,7 +252,7 @@ public static function kebab($phrase) * @param string $phrase * @return string */ - public static function humanize($phrase) + public static function humanize(string $phrase): string { // Convert from underscore + kebab. $phrase = trim(preg_replace('/[\s_-]+/', ' ', $phrase)); diff --git a/src/Job.php b/src/Job.php index c4d6694..bae1d24 100644 --- a/src/Job.php +++ b/src/Job.php @@ -29,13 +29,13 @@ abstract class Job implements use RulesValidatorTrait; /** @var string */ - public $id; + public string $id = ''; /** @var int Unix timestamp in seconds. */ - public $start; + public int $start = 0; /** @var array */ - public $config; + public array $config = []; /** @@ -122,9 +122,9 @@ public function stats(): array * Shorthand for creating, validating and running a job. * * @param array $config - * @return Job + * @return static */ - public static function execute(array $config = []) + public static function execute(array $config = []): static { // @phpstan-ignore-next-line $job = new static(); diff --git a/src/Log.php b/src/Log.php index 8c3eadf..6dbdb63 100644 --- a/src/Log.php +++ b/src/Log.php @@ -110,12 +110,12 @@ public static function level(string $name): int * $loggable->attach($parent, null, ['stats' => false, 'meta' => false]); * ``` * - * @param callable|Loggable $logger + * @param callable|LogSinkInterface $logger * @param int|null $level * @param string|array|null $category * @return callable */ - public static function filter($logger, $level = null, $category = null) + public static function filter(callable|LogSinkInterface $logger, ?int $level = null, string|array|null $category = null): callable { if ($level === null and $category === null) { return $logger; @@ -177,7 +177,7 @@ public static function filter($logger, $level = null, $category = null) * @param int $timestamp * @return void - echoes to stdout */ - public static function print($message, $level, $category, $timestamp) + public static function print(mixed $message, int $level, string $category, int $timestamp): void { echo self::format($message, $level, $category, $timestamp); } @@ -191,7 +191,7 @@ public static function print($message, $level, $category, $timestamp) * @param int $timestamp * @return string */ - public static function format($message, $level, $category, $timestamp) + public static function format(mixed $message, int $level, string $category, int $timestamp): string { $line = ''; $line .= '[' . date('c', $timestamp) . ']'; @@ -206,9 +206,10 @@ public static function format($message, $level, $category, $timestamp) * An attempt to convert things into strings. * * @param mixed $value + * @param int $indent * @return string */ - public static function stringify($value, $indent = 0): string + public static function stringify(mixed $value, int $indent = 0): string { // Bad hack. if (!$indent and is_object($value)) $indent = 2; @@ -290,7 +291,7 @@ public static function stringify($value, $indent = 0): string * @param mixed $thing * @return void */ - public static function dump($thing) + public static function dump(mixed $thing): void { while (ob_get_level() > 0) ob_end_clean(); header('content-type: text/plain'); @@ -310,7 +311,7 @@ public static function dump($thing) * @param int[]|int $levels Filtering; only log on these levels * @return callable (message, level, category) */ - public static function createFileLogger(string $path, $cache_size = 5, $levels = null) + public static function createFileLogger(string $path, int $cache_size = 5, int|array|null $levels = null): callable { // A happy little closure value. $cache = []; diff --git a/src/LoggerTrait.php b/src/LoggerTrait.php index c94ba61..4264d51 100644 --- a/src/LoggerTrait.php +++ b/src/LoggerTrait.php @@ -20,7 +20,7 @@ trait LoggerTrait { private $loggers = []; - public function clearLoggers() + public function clearLoggers(): void { $this->loggers = []; } diff --git a/src/RulesClassValidator.php b/src/RulesClassValidator.php index 0fc2a7b..88f9cc9 100644 --- a/src/RulesClassValidator.php +++ b/src/RulesClassValidator.php @@ -24,37 +24,37 @@ class RulesClassValidator implements RulesValidatorInterface { /** @var array|object */ - protected $data; + protected array|object $data; /** * Available rules, as installed by setValidators(). * * @var RuleInterface[] */ - protected $validators = []; + protected array $validators = []; /** * Active rules, a subset of the validators as determined by setRules(). * * @var RuleInterface[] */ - protected $rules = []; + protected array $rules = []; /** * A copy of the original rulesets, used for reparsing rules. * * @var array */ - protected $original_rules = []; + protected array $original_rules = []; /** @var array */ - protected $errors = []; + protected array $errors = []; /** * @param array|object $data Data to validate */ - public function __construct($data) + public function __construct(array|object $data) { $validators = require __DIR__ . '/config/rules.php'; $this->setValidators($validators); @@ -67,7 +67,7 @@ public function __construct($data) * * @param array|object $data Data to validate */ - public function setData($data) + public function setData(array|object $data): void { if (is_array($data) or $data instanceof ArrayAccess) { $this->data = $data; @@ -86,7 +86,7 @@ public function setData($data) * @param string $field The field to set * @param mixed $value The value to set on the field */ - public function setFieldValue($field, $value) + public function setFieldValue(string $field, mixed $value): void { $this->data[$field] = $value; } @@ -98,7 +98,7 @@ public function setFieldValue($field, $value) * @return void * @throws InvalidArgumentException */ - public function setValidators(array $validators) + public function setValidators(array $validators): void { $this->validators = []; @@ -125,7 +125,7 @@ public function setValidators(array $validators) * @return void * @throws InvalidArgumentException */ - public function addValidator($validator, ?string $name = null) + public function addValidator($validator, ?string $name = null): void { /** @var RuleInterface $validator */ $validator = Configure::configure($validator, RuleInterface::class); @@ -182,7 +182,7 @@ public function parseRule(string $name, array $ruleset): RuleInterface * @return void * @throws InvalidArgumentException */ - public function refreshRules() + public function refreshRules(): void { $this->setRules($this->original_rules); } @@ -307,7 +307,7 @@ public function validate(): bool * * @param array $fields Fields to check */ - public function required(array $fields) + public function required(array $fields): void { foreach ($fields as $field_name) { if (RequiredRule::isEmpty($this->data, $field_name)) { @@ -323,7 +323,7 @@ public function required(array $fields) * @param string $field_name The field to add the error message for * @param string|string[] $message The message text */ - public function addFieldError($field_name, $message) + public function addFieldError(string $field_name, string|array $message): void { if (is_array($message)) { foreach ($message as $item) { @@ -342,7 +342,7 @@ public function addFieldError($field_name, $message) * @param array $fields The fields to add the error message for * @param string $message The message text */ - public function addMultipleFieldError(array $fields, $message) + public function addMultipleFieldError(array $fields, string $message): void { foreach ($fields as $f) { $this->addFieldError($f, $message); diff --git a/src/RulesStaticValidator.php b/src/RulesStaticValidator.php index 472d418..1ba7b22 100644 --- a/src/RulesStaticValidator.php +++ b/src/RulesStaticValidator.php @@ -79,12 +79,12 @@ */ class RulesStaticValidator implements RulesValidatorInterface { - protected $labels; - protected $data; - protected $rules; - protected $field_errors; - protected $general_errors; - protected $validity; + protected array $labels; + protected array|object $data; + protected array $rules; + protected array $field_errors; + protected array $general_errors; + protected string $validity; /** * Recursive trim data @@ -118,7 +118,7 @@ public static function trim(array &$data) * @param array|object $data Data to validate * @param array $rules Validation rules */ - public function __construct($data, array $rules = []) + public function __construct(array|object $data, array $rules = []) { $this->labels = []; $this->field_errors = []; @@ -135,7 +135,7 @@ public function __construct($data, array $rules = []) * * @param array $labels Field labels */ - public function setLabels(array $labels) + public function setLabels(array $labels): void { $this->labels = $labels; } @@ -146,7 +146,7 @@ public function setLabels(array $labels) * * @param array|object $data Data to validate */ - public function setData($data) + public function setData(array|object $data): void { if (is_array($data) or $data instanceof ArrayAccess) { $this->data = $data; @@ -176,7 +176,7 @@ public function setRules(array $rules): void * @param string $field The field to set * @param mixed $value The value to set on the field */ - public function setFieldValue($field, $value) + public function setFieldValue(string $field, mixed $value): void { $this->data[$field] = $value; } @@ -188,7 +188,7 @@ public function setFieldValue($field, $value) * @param string $field The field to set * @param string $label The label to set on the field */ - public function setFieldLabel($field, $label) + public function setFieldLabel(string $field, string $label): void { $this->labels[$field] = $label; } @@ -200,7 +200,7 @@ public function setFieldLabel($field, $label) * @param string $class * @throws InvalidArgumentException */ - public function setValidity(string $class) + public function setValidity(string $class): void { if (!class_exists($class)) { throw new InvalidArgumentException("Invalid validity class: {$class}"); @@ -215,7 +215,7 @@ public function setValidity(string $class) * @param callable|string $func The function to expand. * @return callable|false False if not callable. */ - protected function expandNs($func) + protected function expandNs(callable|string $func): mixed { // Check for methods on a validity class first. $expanded = [$this->validity, $func]; @@ -351,11 +351,11 @@ public function validate(): bool * If a empty value is provided, it is not validated - returns true * * @param string $field_name The field to check - * @param callable $func The function or method to call. + * @param callable|string $func The function or method to call. * @param array $args * @return bool True if validation was successful, false if it failed */ - public function check($field_name, $func, ...$args) + public function check(string $field_name, callable|string $func, mixed ...$args): bool { $value = $this->data[$field_name] ?? null; @@ -394,11 +394,11 @@ public function check($field_name, $func, ...$args) * // $errs now contains [ 'vals' => [2 => [...], 3 => [...]] ] * * @param string $field_name The field to check - * @param callable $func The function or method to call. + * @param callable|string $func The function or method to call. * @param array $args * @return array Key => Boolean True if validation was successful, false if it failed */ - public function arrayCheck($field_name, $func, ...$args) + public function arrayCheck(string $field_name, callable|string $func, mixed ...$args): array { $values = $this->data[$field_name] ?? null; @@ -436,11 +436,11 @@ public function arrayCheck($field_name, $func, ...$args) * Additional arguments are passed to the underlying method * * @param array $fields The fields to check - * @param callable $func The function or method to call. + * @param callable|string $func The function or method to call. * @param array $args * @return bool True if validation was successful, false if it failed */ - public function multipleCheck(array $fields, $func, ...$args) + public function multipleCheck(array $fields, callable|string $func, mixed ...$args): bool { $this->expandNs($func); @@ -466,7 +466,7 @@ public function multipleCheck(array $fields, $func, ...$args) * @param mixed $val * @return bool True if empty, false if not. */ - public static function isEmpty($val) + public static function isEmpty($val): bool { if (is_array($val) and count($val) == 0) { return true; @@ -483,7 +483,7 @@ public static function isEmpty($val) * * @param array $fields Fields to check */ - public function required(array $fields) + public function required(array $fields): void { foreach ($fields as $field_name) { if (!isset($this->data[$field_name])) { @@ -501,7 +501,7 @@ public function required(array $fields) * @param string $field_name The field to add the error message for * @param string $message The message text */ - public function addFieldError($field_name, $message) + public function addFieldError(string $field_name, string $message): void { if (!isset($this->field_errors[$field_name])) { $this->field_errors[$field_name] = [$message]; @@ -519,7 +519,7 @@ public function addFieldError($field_name, $message) * @param int $index The array index of the field to report error for * @param string $message The message text */ - public function addArrayFieldError($field_name, $index, $message) + public function addArrayFieldError(string $field_name, int $index, string $message): void { if (!isset($this->field_errors[$field_name])) { $this->field_errors[$field_name] = []; @@ -538,7 +538,7 @@ public function addArrayFieldError($field_name, $index, $message) * @param array $fields The fields to add the error message for * @param string $message The message text */ - public function addMultipleFieldError(array $fields, $message) + public function addMultipleFieldError(array $fields, string $message): void { foreach ($fields as $f) { $this->addFieldError($f, $message); @@ -552,7 +552,7 @@ public function addMultipleFieldError(array $fields, $message) * * @return array */ - public function getFieldErrors() + public function getFieldErrors(): array { return $this->field_errors; } @@ -576,7 +576,7 @@ public function getErrors(): array * * @param string $message The message text */ - public function addGeneralError($message) + public function addGeneralError(string $message): void { $this->general_errors[] = $message; } @@ -587,7 +587,7 @@ public function addGeneralError($message) * * @return array */ - public function getGeneralErrors() + public function getGeneralErrors(): array { return $this->general_errors; } diff --git a/src/Secrets.php b/src/Secrets.php index 6257b1e..0d769d5 100644 --- a/src/Secrets.php +++ b/src/Secrets.php @@ -74,16 +74,16 @@ class Secrets extends DataObject /** @var string[] */ - public $key_rules; + public array $key_rules; /** @var string[] */ - public $value_rules; + public array $value_rules; /** @var string */ - public $key_pattern; + public string $key_pattern; /** @var string */ - public $value_pattern; + public string $value_pattern; /** * Whether to treat _all_ base64 strings as secrets. @@ -97,7 +97,7 @@ class Secrets extends DataObject * * @var bool */ - public $base64 = false; + public bool $base64 = false; /** * Whether to treat _all_ hex strings as secrets. @@ -111,14 +111,14 @@ class Secrets extends DataObject * * @var bool */ - public $hex = false; + public bool $hex = false; /** * Create masks with fixed sizes. * * @var int|null */ - public $mask_length = 16; + public ?int $mask_length = 16; /** @@ -150,7 +150,7 @@ public function update(iterable $config): void * @param string $pattern regex * @return void */ - public function addKeyRule(string $pattern) + public function addKeyRule(string $pattern): void { $this->key_rules[] = $pattern; $this->key_pattern = $this->buildPattern($this->key_rules); @@ -163,7 +163,7 @@ public function addKeyRule(string $pattern) * @param string $pattern regex * @return void */ - public function addValueRule(string $pattern) + public function addValueRule(string $pattern): void { $this->value_rules[] = $pattern; $this->value_pattern = static::buildPattern($this->value_rules); @@ -176,7 +176,7 @@ public function addValueRule(string $pattern) * @param mixed $item * @return bool */ - public function isSecretKey($item): bool + public function isSecretKey(mixed $item): bool { if (!is_string($item)) { return false; @@ -201,7 +201,7 @@ public function isSecretKey($item): bool * @param bool $recursive - process url/json strings * @return bool */ - public function isSecretValue($item, bool $recursive = true): bool + public function isSecretValue(mixed $item, bool $recursive = true): bool { if (!is_string($item)) { return false; @@ -317,7 +317,7 @@ public function isSecretValue($item, bool $recursive = true): bool * @param mixed $item * @return bool */ - public function isSecret($item): bool + public function isSecret(mixed $item): bool { if (!is_string($item)) { return false; diff --git a/src/Security.php b/src/Security.php index 459332c..a5464ba 100644 --- a/src/Security.php +++ b/src/Security.php @@ -37,7 +37,7 @@ class Security * @param int $length * @return string Binary string */ - public static function randBytes($length) + public static function randBytes(int $length): string { $length = (int) $length; if ($length < 8) { @@ -53,7 +53,7 @@ public static function randBytes($length) * * @return string Binary string; one byte */ - public static function randByte() + public static function randByte(): string { static $buffer = []; if (count($buffer) === 0) { @@ -69,7 +69,7 @@ public static function randByte() * @param int $length * @return string */ - public static function randStr($length = 16, $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890') + public static function randStr(int $length = 16, string $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890'): string { $num_chars = strlen($chars) * 1.0; $mask = 256 - (256 % $num_chars); @@ -95,7 +95,7 @@ public static function randStr($length = 16, $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXY * @param string $user_string The user supplied hash to check * @return bool True if the strings match, false if they don't */ - public static function compareStrings($known_string, $user_string) + public static function compareStrings(string $known_string, string $user_string): bool { return hash_equals($known_string, $user_string); } @@ -106,12 +106,12 @@ public static function compareStrings($known_string, $user_string) * * @deprecated Use password_hash() instead. * @param string $known_hash The known hash to check against, typically from the database - * @param int $algorithm Password algorithm, {@see self} + * @param int|string $algorithm Password algorithm, {@see self} * @param string $salt * @param string $user_string Password which was entered by the user, to check against the stored hash * @return bool True if the password matches, false if it doesn't */ - public static function doPasswordCheck($known_hash, $algorithm, $salt, $user_string) + public static function doPasswordCheck(string $known_hash, int|string $algorithm, string $salt, string $user_string): bool { switch ($algorithm) { case self::PASSWORD_DEFAULT: @@ -152,7 +152,7 @@ public static function doPasswordCheck($known_hash, $algorithm, $salt, $user_str * @return array 0 => hash, 1 => algorithm, 2 => salt * @throws InvalidArgumentException */ - public static function hashPassword($password, $algorithm = self::PASSWORD_DEFAULT) + public static function hashPassword(string $password, int|string $algorithm = self::PASSWORD_DEFAULT): array { switch ($algorithm) { case self::PASSWORD_DEFAULT: diff --git a/src/Shell.php b/src/Shell.php index 49837d1..215c92b 100644 --- a/src/Shell.php +++ b/src/Shell.php @@ -35,7 +35,7 @@ class Shell * @param array $args keyed args * @return string escaped cmd string */ - public static function escape(string $cmd, array $args) + public static function escape(string $cmd, array $args): string { return preg_replace_callback('/{([^}]+)}/', function($matches) use ($args) { $index = $matches[1]; @@ -54,7 +54,7 @@ public static function escape(string $cmd, array $args) * @param mixed $args * @return string */ - public static function runSync(string $dir, string $cmd, ...$args) + public static function runSync(string $dir, string $cmd, mixed ...$args): string { $shell = self::run([ 'cwd' => $dir, @@ -79,7 +79,7 @@ public static function runSync(string $dir, string $cmd, ...$args) * @param mixed $args * @return Generator */ - public static function runAsync(string $dir, string $cmd, ...$args) + public static function runAsync(string $dir, string $cmd, mixed ...$args): Generator { $shell = self::run([ 'cwd' => $dir, @@ -115,7 +115,7 @@ public static function runAsync(string $dir, string $cmd, ...$args) * - env - `string[]` * @return ShellOutput */ - public static function run($config) + public static function run(string|array|ShellOptions $config): ShellOutput { $config = ShellOptions::parse($config); diff --git a/src/ShellOptions.php b/src/ShellOptions.php index e5c22fb..577aed0 100644 --- a/src/ShellOptions.php +++ b/src/ShellOptions.php @@ -12,28 +12,28 @@ class ShellOptions extends Collection { /** @var string required */ - public $cmd; + public string $cmd = ''; /** @var array */ - public $args = []; + public array $args = []; /** @var string|null */ - public $cwd = null; + public ?string $cwd = null; - /** @var string[] */ - public $env = []; + /** @var array */ + public array $env = []; /** @var string|array|resource|false */ - public $stdin = 'pipe'; + public mixed $stdin = 'pipe'; /** @var string|array|resource|false */ - public $stdout = 'pipe'; + public mixed $stdout = 'pipe'; /** @var string|array|resource|false */ - public $stderr = 'pipe'; + public mixed $stderr = 'pipe'; /** @var int Limit for fgets() in bytes. */ - public $chunk_size = 1024; + public int $chunk_size = 1024; /** @@ -46,7 +46,7 @@ class ShellOptions extends Collection * @param string|array|ShellOptions $config * @return ShellOptions */ - public static function parse($config) + public static function parse(string|array|ShellOptions $config): self { if ($config instanceof self) { return clone $config; @@ -108,7 +108,7 @@ public function getCommand(): string * @param resource|array|string $descriptor * @return resource|array */ - private static function parseDescriptor(string $mode, $descriptor) + private static function parseDescriptor(string $mode, mixed$descriptor): mixed { // Resource, cool. if (is_resource($descriptor)) { diff --git a/src/ShellOutput.php b/src/ShellOutput.php index 1c1fc0d..151b8c4 100644 --- a/src/ShellOutput.php +++ b/src/ShellOutput.php @@ -22,29 +22,29 @@ class ShellOutput /** @var int milliseconds */ - static $SELECT_TIMEOUT = 100; + public static int $SELECT_TIMEOUT = 100; /** @var ShellOptions */ - public $config; + public ShellOptions $config; /** @var resource */ - public $handle; + public mixed $handle; /** @var int */ - public $pid = -1; + public int $pid = -1; /** @var bool */ - public $running = false; + public bool $running = false; /** @var int|false */ - public $exit = false; + public int|false $exit = false; /** @var array [ stdin, stdout, stderr ] */ - private $pipes; + private array $pipes; /** @var array resource, string array */ - private $descriptors; + private array $descriptors; /** @@ -53,7 +53,7 @@ class ShellOutput * @param resource $handle from proc_open() * @param array $pipes from proc_open() */ - public function __construct(ShellOptions $config, $handle, array $pipes) + public function __construct(ShellOptions $config, mixed $handle, array $pipes) { $this->config = $config; $this->handle = $handle; diff --git a/src/Text.php b/src/Text.php index 6dcf9c9..8be84b4 100644 --- a/src/Text.php +++ b/src/Text.php @@ -55,23 +55,23 @@ class Text { /** @var string */ - static $ENCODING = 'UTF-8'; + public static string $ENCODING = 'UTF-8'; /** @var int */ - static $MIN_SIMILAR_PERCENT = 85; + public static int $MIN_SIMILAR_PERCENT = 85; /** @var int */ - static $DISTANCE_FACTOR = 10; + public static int $DISTANCE_FACTOR = 10; /** @var array */ - static $ALPHA_RULES = [ + public static array $ALPHA_RULES = [ "a4 e3 o0D ilL1!| `’", "AA EE OOO IIIIII ''", ]; /** @var array|null Not for public use. */ - static $_map = null; + public static ?array $_map = null; /** @@ -89,7 +89,7 @@ class Text { * @param int $flags * @return string */ - public static function normalize(string $str, $flags = self::NORMALIZE_ALL) + public static function normalize(string $str, int $flags = self::NORMALIZE_ALL): string { if ($flags & self::NORMALIZE_ALPHA) { $str = self::normalizeAlpha($str); @@ -119,7 +119,7 @@ public static function normalize(string $str, $flags = self::NORMALIZE_ALL) * @param string $str * @return string */ - public static function normalizeAlpha(string $str) + public static function normalizeAlpha(string $str): string { list($find, $replace) = self::$ALPHA_RULES; return strtr($str, $find, $replace); @@ -145,7 +145,7 @@ public static function normalizeAlpha(string $str) * @param array $map * @return string */ - public static function normalizeMultibyte(string $str, array &$map = []) + public static function normalizeMultibyte(string $str, array &$map = []): string { $matches = []; @@ -174,7 +174,7 @@ public static function normalizeMultibyte(string $str, array &$map = []) * @param int $flags one of the normalisation flags * @return float 0-100 bigger is better */ - public static function similarity(string $str1, string $str2, $flags = self::NORMALIZE_ALL) + public static function similarity(string $str1, string $str2, int $flags = self::NORMALIZE_ALL): float { if ($flags) { self::$_map = []; @@ -197,7 +197,7 @@ public static function similarity(string $str1, string $str2, $flags = self::NOR * @param int $flags one of the normalisation flags * @return int lower is better (or -1 if too long) */ - public static function compare(string $str1, string $str2, $flags = self::NORMALIZE_ALL) + public static function compare(string $str1, string $str2, int $flags = self::NORMALIZE_ALL): int { if ($flags) { self::$_map = []; @@ -223,7 +223,7 @@ public static function compare(string $str1, string $str2, $flags = self::NORMAL * @param int $flags one of the normalisation flags * @return bool */ - public static function similar(string $str1, string $str2, $flags = self::NORMALIZE_ALL) + public static function similar(string $str1, string $str2, int $flags = self::NORMALIZE_ALL): bool { if ($flags) { self::$_map = []; @@ -270,7 +270,7 @@ public static function similar(string $str1, string $str2, $flags = self::NORMAL * @param int $flags one of the normalisation flags * @return string[] subset of 'options' in order of closeness */ - public static function find(string $needle, array $haystack, $max = 5, $flags = self::NORMALIZE_ALL): array + public static function find(string $needle, array $haystack, int $max = 5, int $flags = self::NORMALIZE_ALL): array { self::$_map = []; @@ -335,7 +335,7 @@ public static function find(string $needle, array $haystack, $max = 5, $flags = * @param int $flags * @return array */ - public static function startsWith(string $needle, array $haystack, $max = 5, $flags = self::NORMALIZE_ALL): array + public static function startsWith(string $needle, array $haystack, int $max = 5, int $flags = self::NORMALIZE_ALL): array { $flags |= self::FIND_STARTS_WITH; return self::find($needle, $haystack, $max, $flags); @@ -351,7 +351,7 @@ public static function startsWith(string $needle, array $haystack, $max = 5, $fl * @param int $end Optional number of characters to keep from the end of string. Eg `2` = `***le` * @return string Eg `*****`|`A****`|`****e`|`A***e` */ - public static function mask(string $word, $mask_char = '*', $start = 0, $end = 0) + public static function mask(string $word, string $mask_char = '*', int $start = 0, int $end = 0): string { if (empty($word)) return ''; if (empty($mask_char)) $mask_char = '*'; @@ -384,11 +384,11 @@ public static function mask(string $word, $mask_char = '*', $start = 0, $end = 0 * * @param string $word * @param string $preset Text::MASK_TYPE_* - * @param string|null $mask_char Optional masking character. Default of `*` + * @param string $mask_char Optional masking character. Default of `*` * @return string * @throws Exception Unknown preset */ - public static function maskPreset(string $word, string $preset, $mask_char = '*') + public static function maskPreset(string $word, string $preset, string $mask_char = '*'): string { switch ($preset) { diff --git a/src/Time.php b/src/Time.php index 6a9b552..45b2149 100644 --- a/src/Time.php +++ b/src/Time.php @@ -48,7 +48,7 @@ class Time /** @var array{float,float}|null */ - protected static $time_travel = null; + protected static ?array $time_travel = null; /** @@ -90,7 +90,7 @@ public static function getDate(string $modifier = 'now'): DateTimeImmutable * @param DateTimeImmutable|string|float|null $date * @return void */ - public static function setTimeTravel($date): void + public static function setTimeTravel(DateTimeImmutable|string|float|null $date): void { if ($date === null) { self::$time_travel = null; @@ -150,7 +150,7 @@ public static function resume(): void * @param bool $hrtime Use high-resolution if available. * @return int microseconds */ - public static function utime($hrtime = true): int + public static function utime(bool $hrtime = true): int { if ($hrtime and function_exists('hrtime')) { // phpcs:ignore @@ -171,7 +171,7 @@ public static function utime($hrtime = true): int * @param int $timediff Amount of time that has passed, in seconds. * @return string **/ - public static function timeAgo(int $timediff) + public static function timeAgo(int $timediff): string { $timediff = (int) $timediff; @@ -209,15 +209,13 @@ public static function timeAgo(int $timediff) * - classic PHP date parsing * - timezones * - * @param string|int|float|DateTimeInterface $value + * @param mixed $value * @param string|DateTimeZone|null $zone * @return DateTimeInterface * @throws InvalidArgumentException */ - public static function parse($value, $zone = null): DateTimeInterface + public static function parse(mixed $value, string|DateTimeZone|null $zone = null): DateTimeInterface { - /** @var mixed $value */ - // Also parse timezones while we're here. if (is_string($zone)) { $zone = new DateTimeZone($zone); @@ -302,14 +300,12 @@ public static function parseFloat(float $timestamp, ?DateTimeZone $zone = null): * * `T101 => 'T10:10:00'` * - * @param string|int $time + * @param mixed $time * @param bool $big_endian left or right aligned number parsing * @return string|null `T HH:MM:II.SSS` */ - public static function parseTimeString($time, $big_endian = true) + public static function parseTimeString(mixed $time, bool $big_endian = true): ?string { - /** @var mixed $time */ - // 24 hour time. if (is_numeric($time)) { $args = []; @@ -529,12 +525,12 @@ public static function toTimeFloat(DateTimeInterface $date): float * Convert a timestamp to a date string in the given timezone * * @param string $timezone - * @param int|float $timestamp + * @param float $timestamp * @param string $format * @return string The date string in the requested format * @throws InvalidArgumentException */ - public static function utcTimeToDate(string $timezone, $timestamp, string $format = 'Y-m-d H:i:s'): string + public static function utcTimeToDate(string $timezone, float $timestamp, string $format = 'Y-m-d H:i:s'): string { $timezone_dt = new DateTimeZone($timezone); $date = self::parseFloat($timestamp, $timezone_dt); @@ -644,7 +640,7 @@ public static function localNow(string $timezone, string $format = 'Y-m-d H:i:s' * @param DateInterval|array|string $intervals * @return DateInterval */ - public static function modifyInterval(...$intervals) + public static function modifyInterval(mixed ...$intervals): DateInterval { if (empty($intervals)) { return new DateInterval('P0D'); @@ -839,7 +835,7 @@ public static function getIntervalTotal(DateInterval $interval, string $unit = ' * @param string|null $gap A date modifier, a gap between each period * @return Generator [start, end] */ - public static function periods(DateTimeInterface $start, DateTimeInterface $end, string $period, ?string $gap = null) + public static function periods(DateTimeInterface $start, DateTimeInterface $end, string $period, ?string $gap = null): Generator { $start = self::toDateTimeImmutable($start); $end = self::toDateTimeImmutable($end); @@ -870,9 +866,9 @@ public static function periods(DateTimeInterface $start, DateTimeInterface $end, * * @param DateTimeInterface $start * @param DateTimeInterface $end - * @return iterable + * @return Generator */ - public static function between(DateTimeInterface $start, DateTimeInterface $end) + public static function between(DateTimeInterface $start, DateTimeInterface $end): Generator { $periods = self::periods($start, $end, '+1 day'); foreach ($periods as $days) yield $days[0]; @@ -894,9 +890,9 @@ public static function between(DateTimeInterface $start, DateTimeInterface $end) * @param int $year * @param int $from 1-indexed, inclusive * @param int $to 1-indexed, inclusive - * @return iterable + * @return Generator */ - public static function months(int $year, int $from, int $to) + public static function months(int $year, int $from, int $to): Generator { while ($from <= $to) { @@ -935,9 +931,9 @@ public static function months(int $year, int $from, int $to) * @param int $year * @param int $from 1-indexed, inclusive * @param int $to 1-indexed, inclusive - * @return iterable + * @return Generator */ - public static function monthGrid(int $year, int $from, int $to) + public static function monthGrid(int $year, int $from, int $to): Generator { $months = self::months($year, $from, $to); @@ -990,10 +986,10 @@ public static function monthGrid(int $year, int $from, int $to) * - minute * - second * - * @param array|string $config + * @param array $config * @return DateTimeImmutable */ - public static function now($config = []): DateTimeInterface + public static function now(array $config = []): DateTimeInterface { $now = new DateTimeImmutable(); @@ -1047,7 +1043,7 @@ public static function weekdays(int $length = 0): array * @param int $day day of the month, useful if using a day in the format * @return string[] */ - public static function monthOptions(int $length = 9, string $format = 'F', int $day = 1) + public static function monthOptions(int $length = 9, string $format = 'F', int $day = 1): array { $options = []; @@ -1096,7 +1092,7 @@ public static function years(int $length = 5, ?int $year = null): array * @param DateTimeInterface|int|null $now * @return string */ - public static function getTimezoneOffset($timezone, $now = null): string + public static function getTimezoneOffset(string|DateTimeZone $timezone, DateTimeInterface|int|null $now = null): string { if (is_string($timezone)) { $timezone = new DateTimeZone($timezone); diff --git a/src/TimeZones.php b/src/TimeZones.php index a841f2a..58831eb 100644 --- a/src/TimeZones.php +++ b/src/TimeZones.php @@ -18,7 +18,7 @@ class TimeZones { - protected static $map = null; + protected static ?array $map = null; /** diff --git a/src/Url.php b/src/Url.php index 660c51a..3811879 100644 --- a/src/Url.php +++ b/src/Url.php @@ -18,28 +18,28 @@ class Url extends DataObject use UpdateVirtualTrait; /** @var string|null */ - public $scheme; + public ?string $scheme = null; /** @var string|null */ - public $host; + public ?string $host = null; - /** @var string|null */ - public $port; + /** @var int|null */ + public ?int $port = null; /** @var string|null */ - public $user; + public ?string $user = null; /** @var string|null */ - public $pass; + public ?string $pass = null; /** @var string|null */ - public $path; + public ?string $path = null; /** @var array after the question mark ? */ - public $query = []; + public mixed $query = []; /** @var string|null after the hashmark # */ - public $fragment; + public ?string $fragment = null; /** @inheritdoc */ @@ -58,7 +58,7 @@ public function virtual(): array * @return static * @throws UrlDecodeException */ - public function setQuery($query) + public function setQuery(array|string $query): static { if (is_array($query)) { $this->query = $query; @@ -77,7 +77,7 @@ public function setQuery($query) * @return static * @throws UrlDecodeException */ - public function addParams(array $query) + public function addParams(array $query): static { $this->query = array_merge($this->query, $query); return $this; @@ -91,7 +91,7 @@ public function addParams(array $query) * @param mixed $value * @return static */ - public function setParam(string $name, $value) + public function setParam(string $name, mixed $value): static { $this->query[$name] = $value; return $this; @@ -108,7 +108,7 @@ public function setParam(string $name, $value) * @param mixed $value * @return static */ - public function addParam(string $name, $value) + public function addParam(string $name, mixed $value): static { if (array_key_exists($name, $this->query)) { $existing = $this->query[$name]; @@ -133,7 +133,7 @@ public function addParam(string $name, $value) * @param string $name * @return static */ - public function removeParam(string $name) + public function removeParam(string $name): static { unset($this->query[$name]); return $this; @@ -157,7 +157,7 @@ public function hasParam(string $name): bool * * @return void */ - public function normalize() + public function normalize(): void { if ($this->scheme) { $default = self::getDefaultPort($this->scheme); @@ -256,10 +256,10 @@ public function __toString(): string * @return self * @throws UrlParseException */ - public static function parse(string $url) + public static function parse(string $url): self { $config = parse_url($url); - if ($config === false) { + if (!is_array($config)) { throw new UrlParseException("Could not parse URL: {$url}"); } return new self($config); @@ -296,7 +296,7 @@ public static function decode(string $query): array /** * - * @return array + * @return array */ public static function getDefaultPorts(): array { @@ -310,7 +310,7 @@ public static function getDefaultPorts(): array * @param string $scheme * @return null|int */ - public static function getDefaultPort(string $scheme) + public static function getDefaultPort(string $scheme): ?int { $ports = self::getDefaultPorts(); return $ports[$scheme] ?? null; @@ -336,7 +336,7 @@ public static function getDefaultPort(string $scheme) * @param string|array $parts * @return string */ - public static function build(...$parts): string + public static function build(mixed ...$parts): string { if (empty($parts)) return '/'; diff --git a/src/UrlDecodeException.php b/src/UrlDecodeException.php index 871112e..9f3cbbf 100644 --- a/src/UrlDecodeException.php +++ b/src/UrlDecodeException.php @@ -15,14 +15,14 @@ class UrlDecodeException extends UrlException { /** @var string|null */ - public $query; + public ?string $query = null; /** * * @param string $query * @return static */ - public function setQuery(string $query) + public function setQuery(string $query): static { $this->query = $query; return $this; diff --git a/src/Uuid.php b/src/Uuid.php index 1102454..9ea7ff5 100644 --- a/src/Uuid.php +++ b/src/Uuid.php @@ -97,7 +97,7 @@ public static function nil(): string * @return string * @throws Exception Not enough entropy */ - public static function uuid1($options = 0): string + public static function uuid1(int $options = 0): string { // 60-bit time in 100ths of nanoseconds $timestamp = self::getSubNanoTime((bool) ($options & self::V1_LAZY)); @@ -399,7 +399,7 @@ private static function getMacAddress() * * @return int 16-bit number. */ - private static function getSequence() + private static function getSequence(): int { static $base; if (!$base) $base = getmypid() ?: 1; diff --git a/src/ValidationException.php b/src/ValidationException.php index 262ee63..47dca2f 100644 --- a/src/ValidationException.php +++ b/src/ValidationException.php @@ -22,7 +22,7 @@ class ValidationException extends Exception implements ValidationExceptionInterf * * @var array [ item => [errors] ] */ - public $errors = []; + public array $errors = []; /** @@ -44,7 +44,7 @@ public function getErrors(): array * @param array $errors * @return static */ - public function addErrors(array $errors) + public function addErrors(array $errors): static { foreach ($errors as $name => $messages) { if (isset($this->errors[$name])) { diff --git a/src/Validity.php b/src/Validity.php index 24cacd2..2bae99e 100644 --- a/src/Validity.php +++ b/src/Validity.php @@ -16,6 +16,9 @@ * * Used with the {@see RulesStaticValidator} class. * + * Note, these methods accept mixed rather than strong 'string' types because + * often we're validating data from user input, which may contain nulls or other types. + * * @package karmabunny\kb */ class Validity @@ -27,13 +30,14 @@ class Validity * @example * $valid->check('name', 'length', 1, 100) * - * @param string $val The value + * @param mixed $val The value * @param int $min Minimum length * @param int $max Maximum length * @throws ValidationException If item is too short or too long */ - public static function length($val, $min, $max = PHP_INT_MAX) + public static function length(mixed $val, int $min, int $max = PHP_INT_MAX): void { + $val = (string) $val; $len = mb_strlen($val); if ($len < $min) { throw new ValidationException("Shorter than minimum allowed length of {$min}"); @@ -53,11 +57,12 @@ public static function length($val, $min, $max = PHP_INT_MAX) * @example * $valid->check('email', 'email') * - * @param string $val email address + * @param mixed $val email address * @throws ValidationException */ - public static function email($val) + public static function email(mixed $val): void { + $val = (string) $val; $regex = '/^[^@]+@[^@.]+\.[^@]+$/iD'; if (!preg_match($regex, $val)) { @@ -78,11 +83,12 @@ public static function email($val) * @example * $valid->check('password', 'password') * - * @param string $val Password to validate + * @param mixed $val Password to validate * @throws ValidationException */ - public static function password($val) + public static function password(mixed $val): void { + $val = (string) $val; $errs = []; if (mb_strlen($val) < 8) { @@ -113,13 +119,14 @@ public static function password($val) * @example * $valid->check('mobile', 'phone', 10) * - * @param string $val Phone number + * @param mixed $val Phone number * @param int $min_digits Minimum number of digits required in phone number. * This can be less than 8 for fields which allow short numbers like 000 or 13 11 66 * @throws ValidationException */ - public static function phone($val, $min_digits = 8) + public static function phone(mixed $val, int $min_digits = 8): void { + $val = (string) $val; $min_digits = (int) $min_digits; if ($min_digits <= 0) $min_digits = 8; @@ -155,12 +162,12 @@ public static function phone($val, $min_digits = 8) * @example * $valid->check('region_id', 'positiveInt') * - * @param string $val Value to check + * @param mixed $val Value to check * @throws ValidationException */ - public static function positiveInt($val) + public static function positiveInt(mixed $val): void { - if (preg_match('/[^0-9]/', $val)) { + if (preg_match('/[^0-9]/', (string) $val)) { throw new ValidationException("Value must be a whole number that is greater than zero"); } @@ -181,10 +188,10 @@ public static function positiveInt($val) * @example * $valid->check('name', 'proseText') * - * @param string $str + * @param mixed $str * @throws ValidationException */ - public static function proseText($str) + public static function proseText(mixed $str): void { // pL = letters, pN = numbers if (preg_match('/[^-\pL\pN \'"\/!?@#$%&():;.,]/u', (string) $str)) { @@ -199,13 +206,13 @@ public static function proseText($str) * @example * $valid->check('date_published', 'dateMySQL') * - * @param string $val Value to check + * @param mixed $val Value to check * @throws ValidationException */ - public static function dateMySQL($val) + public static function dateMySQL(mixed $val): void { $matches = null; - if (!preg_match('/^([0-9]{4})-([0-9]{2})-([0-9]{2})$/', $val, $matches)) { + if (!preg_match('/^([0-9]{4})-([0-9]{2})-([0-9]{2})$/', (string) $val, $matches)) { throw new ValidationException('Invalid date format'); } @@ -229,13 +236,13 @@ public static function dateMySQL($val) * @example * $valid->check('event_time', 'timeMySQL') * - * @param string $val Value to check + * @param mixed $val Value to check * @throws ValidationException */ - public static function timeMySQL($val) + public static function timeMySQL(mixed $val): void { $matches = null; - if (!preg_match('/^([0-9]{2}):([0-9]{2}):([0-9]{2})$/', $val, $matches)) { + if (!preg_match('/^([0-9]{2}):([0-9]{2}):([0-9]{2})$/', (string) $val, $matches)) { throw new ValidationException('Invalid time format'); } @@ -259,13 +266,13 @@ public static function timeMySQL($val) * @example * $valid->check('start_date', 'datetimeMySQL') * - * @param string $val Value to check + * @param mixed $val Value to check * @throws ValidationException */ - public static function datetimeMySQL($val) + public static function datetimeMySQL(mixed $val): void { $matches = null; - if (!preg_match('/^([0-9]{4}-[0-9]{2}-[0-9]{2}) ([0-9]{2}:[0-9]{2}:[0-9]{2})$/', $val, $matches)) { + if (!preg_match('/^([0-9]{4}-[0-9]{2}-[0-9]{2}) ([0-9]{2}:[0-9]{2}:[0-9]{2})$/', (string) $val, $matches)) { throw new ValidationException('Invalid datedate format'); } @@ -283,7 +290,7 @@ public static function datetimeMySQL($val) * @param array $vals Values to check * @throws ValidationException */ - public static function oneRequired(array $vals) + public static function oneRequired(array $vals): void { foreach ($vals as $v) { if (is_array($v) and count($v) > 0) { @@ -306,7 +313,7 @@ public static function oneRequired(array $vals) * @param array $vals Values to check * @throws ValidationException */ - public static function allMatch(array $vals) + public static function allMatch(array $vals): void { $unique = array_unique($vals); if (count($unique) > 1) { @@ -325,7 +332,7 @@ public static function allMatch(array $vals) * @param array $vals Values to check * @throws ValidationException */ - public static function allUnique(array $vals) + public static function allUnique(array $vals): void { $unique = array_unique($vals); if (count($unique) != count($vals)) { @@ -344,7 +351,7 @@ public static function allUnique(array $vals) * @param array $allowed * @throws ValidationException */ - public static function inArray($val, array $allowed) + public static function inArray(mixed $val, array $allowed): void { if (!in_array($val, $allowed)) { throw new ValidationException('Invalid value'); @@ -377,10 +384,10 @@ public static function allInArray(array $val, array $allowed) * @example * $valid->check('cost', 'numeric') * - * @param string $val + * @param mixed $val * @throws ValidationException */ - public static function numeric($val) + public static function numeric(mixed $val): void { if (!is_numeric($val)) { throw new ValidationException('Value must be a number'); @@ -394,10 +401,10 @@ public static function numeric($val) * @example * $valid->check('active', 'binary') * - * @param string|int $val + * @param mixed $val * @throws ValidationException */ - public static function binary($val) + public static function binary(mixed $val): void { if ($val !== '1' and $val !== 1 and $val !== '0' and $val !== 0) { throw new ValidationException('Value must be a "1" or "0"'); @@ -412,11 +419,11 @@ public static function binary($val) * $valid->check('cost', 'range', 0, 5000) * * @param string $val - * @param number $min The minimum the value may be - * @param number $max The maximum the value may be + * @param int|float $min The minimum the value may be + * @param int|float $max The maximum the value may be * @throws ValidationException */ - public static function range($val, $min, $max) + public static function range(mixed $val, int|float $min, int|float $max): void { static::numeric($val); @@ -437,7 +444,7 @@ public static function range($val, $min, $max) * @param string $max (optional) A date string (compatible with strtotime) for the maximum of the date range. * @param bool $enforce_ordering (optional) Ensures that the start date is less than or equal to the end date. On by default. */ - public static function dateRange(array $vals, $min = null, $max = null, $enforce_ordering = true) + public static function dateRange(array $vals, string $min = null, string $max = null, bool $enforce_ordering = true): void { if (count($vals) != 2) { throw new InvalidArgumentException('Incorrect number of fields. A date range must only contain two dates: a start and an end date.'); @@ -481,7 +488,7 @@ public static function dateRange(array $vals, $min = null, $max = null, $enforce * @return void * @throws ValidationException If the value doesn't match the pattern */ - public static function regex($val, $pattern) + public static function regex(string $val, string $pattern): void { if (!preg_match($pattern, $val)) { throw new ValidationException('Incorrect format'); @@ -495,7 +502,7 @@ public static function regex($val, $pattern) * @return void * @throws ValidationException If the value isn't a valid IPv4 address */ - public static function ipv4Addr($val) + public static function ipv4Addr(string $val): void { if (!preg_match('/^[0-9]+(?:\.[0-9]+){3}$/', $val)) { throw new ValidationException('Invalid IP address'); @@ -515,7 +522,7 @@ public static function ipv4Addr($val) * @return void * @throws ValidationException If the value isn't a valid IPv4 CIDR block */ - public static function ipv4Cidr($val) + public static function ipv4Cidr(string $val): void { if (strpos($val, '/') === false) { throw new ValidationException('Invalid CIDR block'); @@ -540,7 +547,7 @@ public static function ipv4Cidr($val) * @return void * @throws ValidationException If the value isn't a valid IPv4 address or CIDR block */ - public static function ipv4AddrOrCidr($val) + public static function ipv4AddrOrCidr(string $val): void { if (strpos($val, '/') === false) { self::ipv4Addr($val); diff --git a/src/Wrap.php b/src/Wrap.php index 093a16f..7e85306 100644 --- a/src/Wrap.php +++ b/src/Wrap.php @@ -54,7 +54,7 @@ class Wrap * @return callable (...$args) => object * @throws InvalidArgumentException */ - public static function construct(string $name) + public static function construct(string $name): callable { // Validate, but also autoload things. if (!class_exists($name, true)) { @@ -77,7 +77,7 @@ public static function construct(string $name) * @param string $name a class name * @return callable ($item) => bool */ - public static function instanceOf(string $name) + public static function instanceOf(string $name): callable { return function ($item) use ($name) { return ( @@ -98,7 +98,7 @@ public static function instanceOf(string $name) * @param string $name * @return callable (object) => mixed */ - public static function property(string $name) + public static function property(string $name): callable { return function ($item) use ($name) { if (!is_object($item)) return null; @@ -118,7 +118,7 @@ public static function property(string $name) * @param array $args * @return callable (object) => mixed */ - public static function method(string $name, ...$args) + public static function method(string $name, mixed ...$args): callable { return function ($item) use ($name, $args) { if (!is_object($item)) return null; @@ -137,7 +137,7 @@ public static function method(string $name, ...$args) * @param string|int $key * @return callable (array) => mixed */ - public static function item($key) + public static function item($key): callable { return function ($item) use ($key) { if (!( diff --git a/src/XMLException.php b/src/XMLException.php index 945d586..8b3ef5d 100644 --- a/src/XMLException.php +++ b/src/XMLException.php @@ -17,5 +17,5 @@ class XMLException extends Exception { /** @var LibXMLError[] */ - public $errors = []; + public array $errors = []; } diff --git a/src/rules/AllInArrayRule.php b/src/rules/AllInArrayRule.php index eb66dfb..251f037 100644 --- a/src/rules/AllInArrayRule.php +++ b/src/rules/AllInArrayRule.php @@ -19,7 +19,7 @@ class AllInArrayRule extends BaseRule { /** @var array */ - public $allowed = []; + public array $allowed = []; /** @inheritdoc */ diff --git a/src/rules/DateRangeRule.php b/src/rules/DateRangeRule.php index f12fa36..636c086 100644 --- a/src/rules/DateRangeRule.php +++ b/src/rules/DateRangeRule.php @@ -18,11 +18,11 @@ class DateRangeRule extends BaseRule { - public $min = null; + public ?string $min = null; - public $max = null; + public ?string $max = null; - public $ordered = true; + public bool $ordered = true; /** @inheritdoc */ diff --git a/src/rules/InArrayRule.php b/src/rules/InArrayRule.php index e5f7280..6d74872 100644 --- a/src/rules/InArrayRule.php +++ b/src/rules/InArrayRule.php @@ -19,7 +19,7 @@ class InArrayRule extends BaseRule { /** @var array */ - public $allowed = []; + public array $allowed = []; /** @inheritdoc */ diff --git a/src/rules/LengthRule.php b/src/rules/LengthRule.php index 0f14883..d7801cf 100644 --- a/src/rules/LengthRule.php +++ b/src/rules/LengthRule.php @@ -24,9 +24,9 @@ class LengthRule extends BaseRule { - public $min = 0; + public int $min = 0; - public $max = PHP_INT_MAX; + public int $max = PHP_INT_MAX; /** @inheritdoc */ diff --git a/src/rules/OneRequiredRule.php b/src/rules/OneRequiredRule.php index f08e35b..502be88 100644 --- a/src/rules/OneRequiredRule.php +++ b/src/rules/OneRequiredRule.php @@ -17,7 +17,7 @@ class OneRequiredRule extends BaseRule { /** @var string|null */ - public $group; + public ?string $group = null; public function parse(array $ruleset): void { diff --git a/src/rules/PasswordRule.php b/src/rules/PasswordRule.php index 6157592..01bf70e 100644 --- a/src/rules/PasswordRule.php +++ b/src/rules/PasswordRule.php @@ -18,7 +18,7 @@ class PasswordRule extends BaseRule { - public $digits = 8; + public int $digits = 8; /** @inheritdoc */ diff --git a/src/rules/PhoneRule.php b/src/rules/PhoneRule.php index 5d6cc2e..55ad52c 100644 --- a/src/rules/PhoneRule.php +++ b/src/rules/PhoneRule.php @@ -17,7 +17,7 @@ class PhoneRule extends BaseRule { - public $digits = 8; + public int $digits = 8; /** @inheritdoc */ diff --git a/src/rules/RangeRule.php b/src/rules/RangeRule.php index d793ff5..4935067 100644 --- a/src/rules/RangeRule.php +++ b/src/rules/RangeRule.php @@ -18,9 +18,9 @@ class RangeRule extends BaseRule { - public $min = null; + public ?int $min = null; - public $max = null; + public ?int $max = null; /** @inheritdoc */ diff --git a/src/rules/RegexRule.php b/src/rules/RegexRule.php index 045b81a..e870e94 100644 --- a/src/rules/RegexRule.php +++ b/src/rules/RegexRule.php @@ -18,7 +18,7 @@ class RegexRule extends BaseRule { - public $pattern = null; + public ?string $pattern = null; /** @inheritdoc */ From 0f0b887c229e1b8d6c3594d72ddbee61bb2d7ae3 Mon Sep 17 00:00:00 2001 From: Gwilyn Date: Fri, 17 Jul 2026 13:34:34 +1000 Subject: [PATCH 17/22] Remove hrtime exists check. --- src/Time.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/Time.php b/src/Time.php index 45b2149..5e02020 100644 --- a/src/Time.php +++ b/src/Time.php @@ -142,18 +142,14 @@ public static function resume(): void /** * Timestamp as an integer in microseconds. * - * This uses hrtime for 7.2+ with a microtime fallback. - * You can force microtime by passing false. - * * Note, if using hrtime the timestamp _is not_ a unix epoch. * - * @param bool $hrtime Use high-resolution if available. + * @param bool $hrtime Use high-resolution (default) * @return int microseconds */ public static function utime(bool $hrtime = true): int { - if ($hrtime and function_exists('hrtime')) { - // phpcs:ignore + if ($hrtime) { return intdiv(hrtime(true), 1000); } else { From cfd7da759ff892349cc0a31251743e7a301e5aa1 Mon Sep 17 00:00:00 2001 From: Gwilyn Date: Fri, 17 Jul 2026 13:35:11 +1000 Subject: [PATCH 18/22] Deprecate datetime interface helpers. --- src/Time.php | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Time.php b/src/Time.php index 5e02020..b63055f 100644 --- a/src/Time.php +++ b/src/Time.php @@ -437,8 +437,7 @@ public static function parseInterval(string $value): DateInterval /** * Convert any date interface into a datetime. * - * This exists in PHP8+ as `DateTime::createFromInterface()`. - * + * @deprecated use DateTime::createFromInterface() instead * @param DateTimeInterface $interface * @return DateTime */ @@ -458,8 +457,7 @@ public static function toDateTime(DateTimeInterface $interface): DateTime /** * Convert any date interface into a immutable. * - * This exists in PHP8+ as `DateTimeImmutable::createFromInterface()`. - * + * @deprecated use DateTimeImmutable::createFromInterface() instead * @param DateTimeInterface $interface * @return DateTimeImmutable */ @@ -833,8 +831,8 @@ public static function getIntervalTotal(DateInterval $interval, string $unit = ' */ public static function periods(DateTimeInterface $start, DateTimeInterface $end, string $period, ?string $gap = null): Generator { - $start = self::toDateTimeImmutable($start); - $end = self::toDateTimeImmutable($end); + $start = DateTimeImmutable::createFromInterface($start); + $end = DateTimeImmutable::createFromInterface($end); $periodStart = $start; $periodEnd = $end; From 352e9f3e5ed9a4bf7f0c04b5c3c511d9de1e125f Mon Sep 17 00:00:00 2001 From: Gwilyn Date: Fri, 17 Jul 2026 13:35:44 +1000 Subject: [PATCH 19/22] Fix phpstan error on addLogger(). Callable guarantees two elements for an array. --- src/LoggerTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LoggerTrait.php b/src/LoggerTrait.php index 4264d51..b5b68e3 100644 --- a/src/LoggerTrait.php +++ b/src/LoggerTrait.php @@ -55,7 +55,7 @@ public function addLogger(callable|LogSinkInterface $logger, ?int $level = null, { if ( $logger === $this - or (is_array($logger) and ($logger[0] ?? false) === $this) + or (is_array($logger) and ($logger[0]) === $this) ) { throw new InvalidArgumentException('Cannot attach to self'); } From 27d32f8397e8bc38a203f36583edb74862a32d07 Mon Sep 17 00:00:00 2001 From: Gwilyn Date: Fri, 17 Jul 2026 13:36:14 +1000 Subject: [PATCH 20/22] Require interfaces feat/php8. --- composer.json | 2 +- composer.lock | 20 +++++++++++--------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/composer.json b/composer.json index 69d2910..52a50d8 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ "symfony/polyfill-php73": "*", "php": "^8.2", "symfony/polyfill-php81": "^1.26", - "karmabunny/interfaces": "^1.2" + "karmabunny/interfaces": "dev-feat/php8" }, "require-dev": { "phpunit/phpunit": "^9.3", diff --git a/composer.lock b/composer.lock index 32c7097..4bc6de1 100644 --- a/composer.lock +++ b/composer.lock @@ -4,24 +4,24 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "318b4af6611bdd35902e72128cabf2c0", + "content-hash": "e78215c5cc91fefd1f05b60276ecddc6", "packages": [ { "name": "karmabunny/interfaces", - "version": "v1.2.1", + "version": "dev-feat/php8", "source": { "type": "git", "url": "https://github.com/Karmabunny/kbinterfaces.git", - "reference": "dcf87a7013dbdb29c66480d3bdb8561d1167e0fe" + "reference": "0119a8b95d97f96c60651f93b237e4960b94fcb1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Karmabunny/kbinterfaces/zipball/dcf87a7013dbdb29c66480d3bdb8561d1167e0fe", - "reference": "dcf87a7013dbdb29c66480d3bdb8561d1167e0fe", + "url": "https://api.github.com/repos/Karmabunny/kbinterfaces/zipball/0119a8b95d97f96c60651f93b237e4960b94fcb1", + "reference": "0119a8b95d97f96c60651f93b237e4960b94fcb1", "shasum": "" }, "require": { - "php": "^7.2|^8" + "php": "^8.2" }, "require-dev": { "phpcompatibility/php-compatibility": "^9.3", @@ -53,9 +53,9 @@ ], "support": { "issues": "https://github.com/Karmabunny/kbinterfaces/issues", - "source": "https://github.com/Karmabunny/kbinterfaces/tree/v1.2.1" + "source": "https://github.com/Karmabunny/kbinterfaces/tree/feat/php8" }, - "time": "2026-01-28T01:05:13+00:00" + "time": "2026-07-17T03:10:22+00:00" }, { "name": "symfony/polyfill-php73", @@ -2207,7 +2207,9 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": {}, + "stability-flags": { + "karmabunny/interfaces": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { From e518397ebdfd26b1fd6fee504595bac3210871d5 Mon Sep 17 00:00:00 2001 From: Gwilyn Date: Fri, 17 Jul 2026 15:15:58 +1000 Subject: [PATCH 21/22] Update CLI helper typings. --- src/Cli.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Cli.php b/src/Cli.php index e6ee6cc..74ccdc1 100644 --- a/src/Cli.php +++ b/src/Cli.php @@ -53,7 +53,7 @@ class Cli /** @var bool|null */ - protected static $colors = null; + protected static ?bool $colors = null; /** @@ -93,7 +93,7 @@ public static function error(mixed ...$args): void * @param mixed ...$args * @return void */ - public static function write($stream, ...$args) + public static function write(mixed $stream, mixed ...$args): void { $hasColors = self::$colors ?? self::hasColors($stream); @@ -206,7 +206,7 @@ public static function hasColors($stream = \STDOUT): bool * @param bool|string $enable * @return void */ - public static function setColors($enable = true) + public static function setColors(bool|string $enable = true): void { $enable = filter_var($enable, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE); self::$colors = $enable; From df5b4b6b5718dbcce2b962bff88656f8df1f9721 Mon Sep 17 00:00:00 2001 From: Gwilyn Date: Fri, 17 Jul 2026 15:19:18 +1000 Subject: [PATCH 22/22] Fix typing typos. --- src/ShellOptions.php | 2 +- src/Validity.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ShellOptions.php b/src/ShellOptions.php index 577aed0..7ea4dc0 100644 --- a/src/ShellOptions.php +++ b/src/ShellOptions.php @@ -108,7 +108,7 @@ public function getCommand(): string * @param resource|array|string $descriptor * @return resource|array */ - private static function parseDescriptor(string $mode, mixed$descriptor): mixed + private static function parseDescriptor(string $mode, mixed $descriptor): mixed { // Resource, cool. if (is_resource($descriptor)) { diff --git a/src/Validity.php b/src/Validity.php index 2bae99e..3bc9535 100644 --- a/src/Validity.php +++ b/src/Validity.php @@ -444,7 +444,7 @@ public static function range(mixed $val, int|float $min, int|float $max): void * @param string $max (optional) A date string (compatible with strtotime) for the maximum of the date range. * @param bool $enforce_ordering (optional) Ensures that the start date is less than or equal to the end date. On by default. */ - public static function dateRange(array $vals, string $min = null, string $max = null, bool $enforce_ordering = true): void + public static function dateRange(array $vals, ?string $min = null, ?string $max = null, bool $enforce_ordering = true): void { if (count($vals) != 2) { throw new InvalidArgumentException('Incorrect number of fields. A date range must only contain two dates: a start and an end date.');