Even stricted PHPStan rules!

This commit is contained in:
flash 2024-08-04 00:14:17 +00:00
parent 310a665595
commit fbca708fbd
24 changed files with 178 additions and 103 deletions

View file

@ -1 +1 @@
0.2408.32219 0.2408.40014

View file

@ -1,4 +1,7 @@
parameters: parameters:
level: 9 level: 9
checkUninitializedProperties: true
checkImplicitMixed: true
checkBenevolentUnionTypes: true
paths: paths:
- src - src

View file

@ -1,7 +1,7 @@
<?php <?php
// CSRFP.php // CSRFP.php
// Created: 2021-06-11 // Created: 2021-06-11
// Updated: 2024-08-03 // Updated: 2024-08-04
namespace Index; namespace Index;
@ -74,10 +74,10 @@ class CSRFP {
return false; return false;
$unpacked = unpack('Vts', $token); $unpacked = unpack('Vts', $token);
if($unpacked === false) if(!is_array($unpacked) || !isset($unpacked['ts']) || !is_int($unpacked['ts']))
return false; return false;
$uTime = (int)($unpacked['ts'] ?? 0); $uTime = $unpacked['ts'];
if($uTime < 0) if($uTime < 0)
return false; return false;

View file

@ -1,7 +1,7 @@
<?php <?php
// ArrayCacheProvider.php // ArrayCacheProvider.php
// Created: 2024-04-10 // Created: 2024-04-10
// Updated: 2024-08-03 // Updated: 2024-08-04
namespace Index\Cache\ArrayCache; namespace Index\Cache\ArrayCache;
@ -65,6 +65,9 @@ class ArrayCacheProvider implements ICacheProvider {
'ttl' => 0, 'ttl' => 0,
]; ];
if(is_float($value))
$value = (int)$value;
return $value; return $value;
} }

View file

@ -1,7 +1,7 @@
<?php <?php
// CacheTools.php // CacheTools.php
// Created: 2024-04-10 // Created: 2024-04-10
// Updated: 2024-08-03 // Updated: 2024-08-04
namespace Index\Cache; namespace Index\Cache;
@ -44,13 +44,14 @@ final class CacheTools {
/** @param array<string, int|string> $uri */ /** @param array<string, int|string> $uri */
private static function resolveBackend(array $uri): ICacheBackend { private static function resolveBackend(array $uri): ICacheBackend {
static $backends = []; static $backends = null;
if(!is_array($backends))
$backends = [];
$scheme = $uri['scheme']; $scheme = $uri['scheme'];
$backend = $backends[$scheme] ?? null;
if(in_array($scheme, $backends)) if(!($backend instanceof ICacheBackend)) {
$backend = $backends[$scheme];
else {
$backend = null; $backend = null;
if(array_key_exists($scheme, self::CACHE_PROTOS)) if(array_key_exists($scheme, self::CACHE_PROTOS))

View file

@ -1,7 +1,7 @@
<?php <?php
// MemcachedBackend.php // MemcachedBackend.php
// Created: 2024-04-10 // Created: 2024-04-10
// Updated: 2024-08-03 // Updated: 2024-08-04
namespace Index\Cache\Memcached; namespace Index\Cache\Memcached;
@ -106,6 +106,9 @@ class MemcachedBackend implements ICacheBackend {
if(is_array($query['server'])) if(is_array($query['server']))
foreach($query['server'] as $endPoint) { foreach($query['server'] as $endPoint) {
if(!is_string($endPoint))
continue;
$parts = explode(';', $endPoint, 2); $parts = explode(';', $endPoint, 2);
$weight = count($parts) > 1 ? (int)$parts[1] : 0; $weight = count($parts) > 1 ? (int)$parts[1] : 0;
$endPoint = EndPoint::parse($parts[0]); $endPoint = EndPoint::parse($parts[0]);

View file

@ -1,7 +1,7 @@
<?php <?php
// ValkeyProvider.php // ValkeyProvider.php
// Created: 2024-04-10 // Created: 2024-04-10
// Updated: 2024-04-10 // Updated: 2024-08-04
namespace Index\Cache\Valkey; namespace Index\Cache\Valkey;
@ -63,11 +63,13 @@ class ValkeyProvider implements ICacheProvider {
} }
public function increment(string $key, int $amount = 1): int { public function increment(string $key, int $amount = 1): int {
return $this->redis->incrBy($key, $amount); $result = $this->redis->incrBy($key, $amount);
return is_int($result) ? $result : 0;
} }
public function decrement(string $key, int $amount = 1): int { public function decrement(string $key, int $amount = 1): int {
return $this->redis->decrBy($key, $amount); $result = $this->redis->decrBy($key, $amount);
return is_int($result) ? $result : 0;
} }
public function close(): void { public function close(): void {

View file

@ -1,7 +1,7 @@
<?php <?php
// DbResultIterator.php // DbResultIterator.php
// Created: 2024-02-06 // Created: 2024-02-06
// Updated: 2024-08-03 // Updated: 2024-08-04
namespace Index\Data; namespace Index\Data;
@ -14,7 +14,7 @@ use Iterator;
* @implements Iterator<int, object> * @implements Iterator<int, object>
*/ */
class DbResultIterator implements Iterator { class DbResultIterator implements Iterator {
private bool $wasValid; private bool $wasValid = false;
private object $current; private object $current;
/** /**
@ -29,6 +29,8 @@ class DbResultIterator implements Iterator {
) { ) {
if(!is_callable($construct)) if(!is_callable($construct))
throw new InvalidArgumentException('$construct must be a callable.'); throw new InvalidArgumentException('$construct must be a callable.');
$this->current = (object)[];
} }
public function current(): mixed { public function current(): mixed {

View file

@ -1,7 +1,7 @@
<?php <?php
// DbTools.php // DbTools.php
// Created: 2021-05-02 // Created: 2021-05-02
// Updated: 2024-08-03 // Updated: 2024-08-04
namespace Index\Data; namespace Index\Data;
@ -43,13 +43,14 @@ final class DbTools {
/** @param array<string, string|int> $uri */ /** @param array<string, string|int> $uri */
private static function resolveBackend(array $uri): IDbBackend { private static function resolveBackend(array $uri): IDbBackend {
static $backends = []; static $backends = null;
if(!is_array($backends))
$backends = [];
$scheme = $uri['scheme']; $scheme = $uri['scheme'];
$backend = $backends[$scheme] ?? null;
if(in_array($scheme, $backends)) if(!($backend instanceof IDbBackend)) {
$backend = $backends[$scheme];
else {
$backend = null; $backend = null;
if(array_key_exists($scheme, self::DB_PROTOS)) if(array_key_exists($scheme, self::DB_PROTOS))

View file

@ -1,7 +1,7 @@
<?php <?php
// MariaDBCharacterSetInfo.php // MariaDBCharacterSetInfo.php
// Created: 2021-05-02 // Created: 2021-05-02
// Updated: 2024-08-03 // Updated: 2024-08-04
namespace Index\Data\MariaDB; namespace Index\Data\MariaDB;
@ -27,7 +27,8 @@ class MariaDBCharacterSetInfo {
* @return string Character set name. * @return string Character set name.
*/ */
public function getCharacterSet(): string { public function getCharacterSet(): string {
return $this->charSet->charset ?? ''; return isset($this->charSet->charset) && is_scalar($this->charSet->charset)
? (string)$this->charSet->charset : '';
} }
/** /**
@ -36,7 +37,8 @@ class MariaDBCharacterSetInfo {
* @return string Default collation name. * @return string Default collation name.
*/ */
public function getDefaultCollation(): string { public function getDefaultCollation(): string {
return $this->charSet->collation ?? ''; return isset($this->charSet->collation) && is_scalar($this->charSet->collation)
? (string)$this->charSet->collation : '';
} }
/** /**
@ -46,7 +48,8 @@ class MariaDBCharacterSetInfo {
* @return string Source directory. * @return string Source directory.
*/ */
public function getDirectory(): string { public function getDirectory(): string {
return $this->charSet->dir ?? ''; return isset($this->charSet->dir) && is_scalar($this->charSet->dir)
? (string)$this->charSet->dir : '';
} }
/** /**
@ -55,7 +58,8 @@ class MariaDBCharacterSetInfo {
* @return int Minimum character width in bytes. * @return int Minimum character width in bytes.
*/ */
public function getMinimumWidth(): int { public function getMinimumWidth(): int {
return $this->charSet->min_length ?? 0; return isset($this->charSet->min_length) && is_scalar($this->charSet->min_length)
? (int)$this->charSet->min_length : 0;
} }
/** /**
@ -64,7 +68,8 @@ class MariaDBCharacterSetInfo {
* @return int Maximum character width in bytes. * @return int Maximum character width in bytes.
*/ */
public function getMaximumWidth(): int { public function getMaximumWidth(): int {
return $this->charSet->max_length ?? 0; return isset($this->charSet->max_length) && is_scalar($this->charSet->max_length)
? (int)$this->charSet->max_length : 0;
} }
/** /**
@ -73,7 +78,8 @@ class MariaDBCharacterSetInfo {
* @return int Character set identifier. * @return int Character set identifier.
*/ */
public function getId(): int { public function getId(): int {
return $this->charSet->number ?? 0; return isset($this->charSet->number) && is_scalar($this->charSet->number)
? (int)$this->charSet->number : 0;
} }
/** /**
@ -84,6 +90,7 @@ class MariaDBCharacterSetInfo {
* @return int Character set status. * @return int Character set status.
*/ */
public function getState(): int { public function getState(): int {
return $this->charSet->state ?? 0; return isset($this->charSet->state) && is_scalar($this->charSet->state)
? (int)$this->charSet->state : 0;
} }
} }

View file

@ -1,7 +1,7 @@
<?php <?php
// MariaDBConnection.php // MariaDBConnection.php
// Created: 2021-04-30 // Created: 2021-04-30
// Updated: 2024-08-03 // Updated: 2024-08-04
namespace Index\Data\MariaDB; namespace Index\Data\MariaDB;
@ -250,7 +250,10 @@ class MariaDBConnection implements IDbConnection, IDbTransactions {
* @return MariaDBWarning[] List of last errors. * @return MariaDBWarning[] List of last errors.
*/ */
public function getLastErrors(): array { public function getLastErrors(): array {
return MariaDBWarning::fromLastErrors($this->connection->error_list); // imagine if stdlib stuff had type annotations, couldn't be me
/** @var array<int, array{errno: int, sqlstate: string, error: string}> */
$errorList = $this->connection->error_list;
return MariaDBWarning::fromLastErrors($errorList);
} }
/** /**

View file

@ -1,14 +1,15 @@
<?php <?php
// DbMigrationManager.php // DbMigrationManager.php
// Created: 2023-01-07 // Created: 2023-01-07
// Updated: 2024-08-03 // Updated: 2024-08-04
namespace Index\Data\Migration; namespace Index\Data\Migration;
use stdClass; use stdClass;
use InvalidArgumentException;
use DateTimeImmutable; use DateTimeImmutable;
use DateTimeInterface; use DateTimeInterface;
use InvalidArgumentException;
use RuntimeException;
use Index\XDateTime; use Index\XDateTime;
use Index\Data\{IDbConnection,IDbStatement,DbType}; use Index\Data\{IDbConnection,IDbStatement,DbType};
use Index\Data\SQLite\SQLiteConnection; use Index\Data\SQLite\SQLiteConnection;
@ -44,8 +45,8 @@ final class %s implements IDbMigration {
EOF; EOF;
private IDbStatement $checkStmt; private ?IDbStatement $checkStmt = null;
private IDbStatement $insertStmt; private ?IDbStatement $insertStmt = null;
/** /**
* @param IDbConnection $conn Connection to apply to migrations to. * @param IDbConnection $conn Connection to apply to migrations to.
@ -94,9 +95,13 @@ EOF;
* Checks if a particular migration is present in the tracking table. * Checks if a particular migration is present in the tracking table.
* *
* @param string $name Name of the migration. * @param string $name Name of the migration.
* @throws RuntimeException If the migration manager has not been initialised.
* @return bool true if the migration has been run, false otherwise. * @return bool true if the migration has been run, false otherwise.
*/ */
public function checkMigration(string $name): bool { public function checkMigration(string $name): bool {
if($this->checkStmt === null)
throw new RuntimeException('Database migration manager has not been initialised.');
$this->checkStmt->reset(); $this->checkStmt->reset();
$this->checkStmt->addParameter(1, $name, DbType::STRING); $this->checkStmt->addParameter(1, $name, DbType::STRING);
$this->checkStmt->execute(); $this->checkStmt->execute();
@ -109,8 +114,12 @@ EOF;
* *
* @param string $name Name of the migration. * @param string $name Name of the migration.
* @param ?DateTimeInterface $dateTime Timestamp of when the migration was run, null for now. * @param ?DateTimeInterface $dateTime Timestamp of when the migration was run, null for now.
* @throws RuntimeException If the migration manager has not been initialised.
*/ */
public function completeMigration(string $name, ?DateTimeInterface $dateTime = null): void { public function completeMigration(string $name, ?DateTimeInterface $dateTime = null): void {
if($this->insertStmt === null)
throw new RuntimeException('Database migration manager has not been initialised.');
$dateTime = XDateTime::toISO8601String($dateTime); $dateTime = XDateTime::toISO8601String($dateTime);
$this->insertStmt->reset(); $this->insertStmt->reset();

View file

@ -1,7 +1,7 @@
<?php <?php
// SQLiteBackend.php // SQLiteBackend.php
// Created: 2021-05-02 // Created: 2021-05-02
// Updated: 2024-08-03 // Updated: 2024-08-04
namespace Index\Data\SQLite; namespace Index\Data\SQLite;
@ -23,7 +23,9 @@ class SQLiteBackend implements IDbBackend {
* @return string Version of the library. * @return string Version of the library.
*/ */
public function getVersion(): string { public function getVersion(): string {
return SQLite3::version()['versionString']; $version = SQLite3::version();
return isset($version['versionString']) && is_scalar($version['versionString'])
? (string)$version['versionString'] : '';
} }
/** /**

View file

@ -1,7 +1,7 @@
<?php <?php
// FormContent.php // FormContent.php
// Created: 2022-02-10 // Created: 2022-02-10
// Updated: 2024-08-03 // Updated: 2024-08-04
namespace Index\Http\Content; namespace Index\Http\Content;
@ -110,7 +110,13 @@ class FormContent implements IHttpContent {
* @return FormContent Instance representing the request body. * @return FormContent Instance representing the request body.
*/ */
public static function fromRequest(): FormContent { public static function fromRequest(): FormContent {
return self::fromRaw($_POST, $_FILES); /** @var array<string, mixed> $postVars */
$postVars = $_POST;
/** @var array<string, mixed> $filesVars */
$filesVars = $_FILES;
return self::fromRaw($postVars, $filesVars);
} }
public function __toString(): string { public function __toString(): string {

View file

@ -1,7 +1,7 @@
<?php <?php
// HttpRequest.php // HttpRequest.php
// Created: 2022-02-08 // Created: 2022-02-08
// Updated: 2024-08-03 // Updated: 2024-08-04
namespace Index\Http; namespace Index\Http;
@ -136,11 +136,11 @@ class HttpRequest extends HttpMessage {
*/ */
public static function fromRequest(): HttpRequest { public static function fromRequest(): HttpRequest {
$build = new HttpRequestBuilder; $build = new HttpRequestBuilder;
$build->setHttpVersion($_SERVER['SERVER_PROTOCOL']); $build->setHttpVersion((string)filter_input(INPUT_SERVER, 'SERVER_PROTOCOL'));
$build->setMethod($_SERVER['REQUEST_METHOD']); $build->setMethod((string)filter_input(INPUT_SERVER, 'REQUEST_METHOD'));
// this currently doesn't "properly" support the scenario where a full url is specified in the http request // this currently doesn't "properly" support the scenario where a full url is specified in the http request
$path = $_SERVER['REQUEST_URI']; $path = (string)filter_input(INPUT_SERVER, 'REQUEST_URI');
$pathQueryOffset = strpos($path, '?'); $pathQueryOffset = strpos($path, '?');
if($pathQueryOffset !== false) if($pathQueryOffset !== false)
$path = substr($path, 0, $pathQueryOffset); $path = substr($path, 0, $pathQueryOffset);
@ -154,22 +154,27 @@ class HttpRequest extends HttpMessage {
$path = '/' . $path; $path = '/' . $path;
$build->setPath($path); $build->setPath($path);
$build->setParams($_GET);
$build->setCookies($_COOKIE); /** @var array<string, mixed> $getVars */
$getVars = $_GET;
$build->setParams($getVars);
/** @var array<string, string> $cookieVars */
$cookieVars = $_COOKIE;
$build->setCookies($cookieVars);
$contentType = null; $contentType = null;
$contentLength = 0; $contentLength = 0;
$headers = self::getRawRequestHeaders(); $headers = self::getRawRequestHeaders();
foreach($headers as $name => $value) { foreach($headers as $name => $value) {
$nameLower = strtolower($name); if($name === 'content-type')
if($nameLower === 'content-type')
try { try {
$contentType = MediaType::parse($value); $contentType = MediaType::parse($value);
} catch(InvalidArgumentException $ex) { } catch(InvalidArgumentException $ex) {
$contentType = null; $contentType = null;
} }
elseif($nameLower === 'content-length') elseif($name === 'content-length')
$contentLength = (int)$value; $contentLength = (int)$value;
$build->setHeader($name, $value); $build->setHeader($name, $value);
@ -189,29 +194,43 @@ class HttpRequest extends HttpMessage {
/** @return array<string, string> */ /** @return array<string, string> */
private static function getRawRequestHeaders(): array { private static function getRawRequestHeaders(): array {
if(function_exists('getallheaders')) if(function_exists('getallheaders')) {
return getallheaders(); $raw = getallheaders();
$headers = [];
foreach($raw as $name => $value)
if(is_string($name) && is_string($value))
$headers[strtolower($name)] = $value;
return $headers;
}
$headers = []; $headers = [];
foreach($_SERVER as $key => $value) { foreach($_SERVER as $key => $value) {
if(!is_string($key) || !is_scalar($value))
continue;
if(substr($key, 0, 5) === 'HTTP_') { if(substr($key, 0, 5) === 'HTTP_') {
$key = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($key, 5))))); $key = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($key, 5))));
$headers[$key] = $value; $headers[$key] = (string)$value;
} elseif($key === 'CONTENT_TYPE') { } elseif($key === 'CONTENT_TYPE') {
$headers['Content-Type'] = $value; $headers['content-type'] = (string)$value;
} elseif($key === 'CONTENT_LENGTH') { } elseif($key === 'CONTENT_LENGTH') {
$headers['Content-Length'] = $value; $headers['content-length'] = (string)$value;
} }
} }
if(!isset($headers['Authorization'])) { if(!isset($headers['authorization'])) {
if(isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) { if(filter_has_var(INPUT_SERVER, 'REDIRECT_HTTP_AUTHORIZATION')) {
$headers['Authorization'] = $_SERVER['REDIRECT_HTTP_AUTHORIZATION']; $headers['authorization'] = (string)filter_input(INPUT_SERVER, 'REDIRECT_HTTP_AUTHORIZATION');
} elseif(isset($_SERVER['PHP_AUTH_USER'])) { } elseif(filter_has_var(INPUT_SERVER, 'PHP_AUTH_USER')) {
$headers['Authorization'] = 'Basic ' . base64_encode($_SERVER['PHP_AUTH_USER'] . ':' . ($_SERVER['PHP_AUTH_PW'] ?? '')); $headers['authorization'] = sprintf('Basic %s', base64_encode(sprintf(
} elseif(isset($_SERVER['PHP_AUTH_DIGEST'])) { '%s:%s',
$headers['Authorization'] = $_SERVER['PHP_AUTH_DIGEST']; (string)filter_input(INPUT_SERVER, 'PHP_AUTH_USER'),
(string)filter_input(INPUT_SERVER, 'PHP_AUTH_PW')
)));
} elseif(filter_has_var(INPUT_SERVER, 'PHP_AUTH_DIGEST')) {
$headers['authorization'] = (string)filter_input(INPUT_SERVER, 'PHP_AUTH_DIGEST');
} }
} }

View file

@ -1,7 +1,7 @@
<?php <?php
// HttpResponseBuilder.php // HttpResponseBuilder.php
// Created: 2022-02-08 // Created: 2022-02-08
// Updated: 2024-08-03 // Updated: 2024-08-04
namespace Index\Http; namespace Index\Http;
@ -14,7 +14,7 @@ use Index\Performance\Timings;
*/ */
class HttpResponseBuilder extends HttpMessageBuilder { class HttpResponseBuilder extends HttpMessageBuilder {
private int $statusCode = -1; private int $statusCode = -1;
private ?string $statusText; private ?string $statusText = null;
/** @var string[] */ /** @var string[] */
private array $vary = []; private array $vary = [];
@ -61,7 +61,7 @@ class HttpResponseBuilder extends HttpMessageBuilder {
* @param string $statusText Status text. * @param string $statusText Status text.
*/ */
public function setStatusText(string $statusText): void { public function setStatusText(string $statusText): void {
$this->statusText = (string)$statusText; $this->statusText = $statusText;
} }
/** /**

View file

@ -1,7 +1,7 @@
<?php <?php
// HttpUploadedFile.php // HttpUploadedFile.php
// Created: 2022-02-10 // Created: 2022-02-10
// Updated: 2024-08-03 // Updated: 2024-08-04
namespace Index\Http; namespace Index\Http;
@ -200,6 +200,7 @@ class HttpUploadedFile implements ICloseable {
$key = "_{$key}"; $key = "_{$key}";
if(is_array($val)) { if(is_array($val)) {
/** @var array<string, mixed> $val */
$arr[$key] = self::traverseFILES($val, $keyName); $arr[$key] = self::traverseFILES($val, $keyName);
} else { } else {
$arr[$key][$keyName] = $val; $arr[$key][$keyName] = $val;
@ -230,8 +231,17 @@ class HttpUploadedFile implements ICloseable {
if(is_array($arr['error'])) { if(is_array($arr['error'])) {
$keys = array_keys($arr); $keys = array_keys($arr);
foreach($keys as $keyName) foreach($keys as $keyName) {
$out[$key] = array_merge_recursive($out[$key] ?? [], self::traverseFILES($arr[$keyName], (string)$keyName)); $source = $arr[$keyName];
if(!is_array($source))
continue;
/** @var array<string, mixed> $mergeWith */
$mergeWith = $out[$key] ?? [];
/** @var array<string, mixed> $source */
$out[$key] = array_merge_recursive($mergeWith, self::traverseFILES($source, (string)$keyName));
}
continue; continue;
} }
} }
@ -251,9 +261,13 @@ class HttpUploadedFile implements ICloseable {
continue; continue;
$key = substr($key, 1); $key = substr($key, 1);
$coll[$key] = isset($val['error'])
? self::createFromFILE($val) if(isset($val['error']))
: self::createObjectInstances($val); /** @var array<string, int|string> $val */
$coll[$key] = self::createFromFILE($val);
else
/** @var array<string, mixed> $val */
$coll[$key] = self::createObjectInstances($val);
} }
return $coll; return $coll;

View file

@ -1,7 +1,7 @@
<?php <?php
// HttpRouter.php // HttpRouter.php
// Created: 2024-03-28 // Created: 2024-03-28
// Updated: 2024-08-03 // Updated: 2024-08-04
namespace Index\Http\Routing; namespace Index\Http\Routing;
@ -15,7 +15,7 @@ use Index\Http\ErrorHandling\{HtmlErrorHandler,IErrorHandler,PlainErrorHandler};
class HttpRouter implements IRouter { class HttpRouter implements IRouter {
use RouterTrait; use RouterTrait;
/** @var object[] */ /** @var array{handler: callable, match?: string, prefix?: string}[] */
private array $middlewares = []; private array $middlewares = [];
/** @var array<string, array<string, callable>> */ /** @var array<string, array<string, callable>> */
@ -147,16 +147,16 @@ class HttpRouter implements IRouter {
* @param callable $handler Middleware handler. * @param callable $handler Middleware handler.
*/ */
public function use(string $path, callable $handler): void { public function use(string $path, callable $handler): void {
$this->middlewares[] = $mwInfo = new stdClass; $mwInfo = [];
$mwInfo->handler = $handler; $mwInfo['handler'] = $handler;
$prepared = self::preparePath($path, true); $prepared = self::preparePath($path, true);
$mwInfo->dynamic = $prepared !== false; if($prepared === false)
$mwInfo['prefix'] = $path;
if($mwInfo->dynamic)
$mwInfo->match = $prepared;
else else
$mwInfo->prefix = $path; $mwInfo['match'] = $prepared;
$this->middlewares[] = $mwInfo;
} }
/** /**
@ -207,19 +207,19 @@ class HttpRouter implements IRouter {
$middlewares = []; $middlewares = [];
foreach($this->middlewares as $mwInfo) { foreach($this->middlewares as $mwInfo) {
if($mwInfo->dynamic ?? false) { if(array_key_exists('match', $mwInfo)) {
if(preg_match($mwInfo->match ?? '', $path, $args) !== 1) if(preg_match($mwInfo['match'], $path, $args) !== 1)
continue; continue;
array_shift($args); array_shift($args);
} else { } elseif(array_key_exists('prefix', $mwInfo)) {
if(!str_starts_with($path, $mwInfo->prefix ?? '')) if(!str_starts_with($path, $mwInfo['prefix']))
continue; continue;
$args = []; $args = [];
} } else continue;
$middlewares[] = [$mwInfo->handler ?? null, $args]; $middlewares[] = [$mwInfo['handler'], $args];
} }
$methods = []; $methods = [];

View file

@ -1,7 +1,7 @@
<?php <?php
// IntegerBaseConverter.php // IntegerBaseConverter.php
// Created: 2024-07-31 // Created: 2024-07-31
// Updated: 2024-07-31 // Updated: 2024-08-04
namespace Index; namespace Index;
@ -95,6 +95,6 @@ class IntegerBaseConverter {
$output += $pos * ($fromBase ** ($length - $i)); $output += $pos * ($fromBase ** ($length - $i));
} }
return $output; return (int)$output;
} }
} }

View file

@ -1,7 +1,7 @@
<?php <?php
// PerformanceCounter.php // PerformanceCounter.php
// Created: 2022-02-16 // Created: 2022-02-16
// Updated: 2024-08-01 // Updated: 2024-08-04
namespace Index\Performance; namespace Index\Performance;
@ -24,7 +24,7 @@ final class PerformanceCounter {
* @return int Ticks count. * @return int Ticks count.
*/ */
public static function getTicks(): int { public static function getTicks(): int {
return hrtime(true); return (int)hrtime(true);
} }
/** /**

View file

@ -1,7 +1,7 @@
<?php <?php
// Stopwatch.php // Stopwatch.php
// Created: 2021-04-26 // Created: 2021-04-26
// Updated: 2024-08-01 // Updated: 2024-08-04
namespace Index\Performance; namespace Index\Performance;
@ -59,9 +59,9 @@ class Stopwatch {
/** /**
* Gets the number of elapsed milliseconds. * Gets the number of elapsed milliseconds.
* *
* @return int Number of elapsed milliseconds. * @return int|float Number of elapsed milliseconds.
*/ */
public function getElapsedTime(): int { public function getElapsedTime(): int|float {
return $this->getElapsedTicks() / $this->frequency; return $this->getElapsedTicks() / $this->frequency;
} }

View file

@ -1,7 +1,7 @@
<?php <?php
// TimingPoint.php // TimingPoint.php
// Created: 2022-02-16 // Created: 2022-02-16
// Updated: 2024-08-01 // Updated: 2024-08-04
namespace Index\Performance; namespace Index\Performance;
@ -45,7 +45,7 @@ class TimingPoint {
* *
* @return int Duration time amount. * @return int Duration time amount.
*/ */
public function getDurationTime(): int { public function getDurationTime(): int|float {
return $this->duration / PerformanceCounter::getFrequency(); return $this->duration / PerformanceCounter::getFrequency();
} }

View file

@ -1,7 +1,7 @@
<?php <?php
// Timings.php // Timings.php
// Created: 2022-02-16 // Created: 2022-02-16
// Updated: 2024-08-03 // Updated: 2024-08-04
namespace Index\Performance; namespace Index\Performance;
@ -15,7 +15,7 @@ class Timings {
private int $lastLapTicks; private int $lastLapTicks;
/** @var TimingPoint[] */ /** @var TimingPoint[] */
private array $laps; private array $laps = [];
/** /**
* @param ?Stopwatch $sw Stopwatch to measure timing points from, null to start a new one. * @param ?Stopwatch $sw Stopwatch to measure timing points from, null to start a new one.

View file

@ -1,7 +1,7 @@
<?php <?php
// XArray.php // XArray.php
// Created: 2022-02-02 // Created: 2022-02-02
// Updated: 2024-08-03 // Updated: 2024-08-04
namespace Index; namespace Index;
@ -119,9 +119,9 @@ final class XArray {
* Retrieves the first key in a collection. * Retrieves the first key in a collection.
* *
* @param mixed[] $iterable * @param mixed[] $iterable
* @return int|string|null * @return mixed
*/ */
public static function firstKey(iterable $iterable): int|string|null { public static function firstKey(iterable $iterable): mixed {
if(is_array($iterable)) if(is_array($iterable))
return array_key_first($iterable); return array_key_first($iterable);
@ -135,9 +135,9 @@ final class XArray {
* Retrieves the last key in a collection. * Retrieves the last key in a collection.
* *
* @param mixed[] $iterable * @param mixed[] $iterable
* @return int|string|null * @return mixed
*/ */
public static function lastKey(iterable $iterable): int|string|null { public static function lastKey(iterable $iterable): mixed {
if(is_array($iterable)) if(is_array($iterable))
return array_key_last($iterable); return array_key_last($iterable);
@ -153,13 +153,13 @@ final class XArray {
* @param mixed[] $iterable * @param mixed[] $iterable
* @param mixed $value * @param mixed $value
* @param bool $strict * @param bool $strict
* @return int|string|false * @return mixed
*/ */
public static function indexOf( public static function indexOf(
iterable $iterable, iterable $iterable,
mixed $value, mixed $value,
bool $strict = false bool $strict = false
): int|string|false { ): mixed {
if(is_array($iterable)) if(is_array($iterable))
return array_search($value, $iterable, $strict); return array_search($value, $iterable, $strict);