Even stricted PHPStan rules!
This commit is contained in:
parent
310a665595
commit
fbca708fbd
24 changed files with 178 additions and 103 deletions
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
0.2408.32219
|
||||
0.2408.40014
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
parameters:
|
||||
level: 9
|
||||
checkUninitializedProperties: true
|
||||
checkImplicitMixed: true
|
||||
checkBenevolentUnionTypes: true
|
||||
paths:
|
||||
- src
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
// CSRFP.php
|
||||
// Created: 2021-06-11
|
||||
// Updated: 2024-08-03
|
||||
// Updated: 2024-08-04
|
||||
|
||||
namespace Index;
|
||||
|
||||
|
@ -74,10 +74,10 @@ class CSRFP {
|
|||
return false;
|
||||
|
||||
$unpacked = unpack('Vts', $token);
|
||||
if($unpacked === false)
|
||||
if(!is_array($unpacked) || !isset($unpacked['ts']) || !is_int($unpacked['ts']))
|
||||
return false;
|
||||
|
||||
$uTime = (int)($unpacked['ts'] ?? 0);
|
||||
$uTime = $unpacked['ts'];
|
||||
if($uTime < 0)
|
||||
return false;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
// ArrayCacheProvider.php
|
||||
// Created: 2024-04-10
|
||||
// Updated: 2024-08-03
|
||||
// Updated: 2024-08-04
|
||||
|
||||
namespace Index\Cache\ArrayCache;
|
||||
|
||||
|
@ -65,6 +65,9 @@ class ArrayCacheProvider implements ICacheProvider {
|
|||
'ttl' => 0,
|
||||
];
|
||||
|
||||
if(is_float($value))
|
||||
$value = (int)$value;
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
// CacheTools.php
|
||||
// Created: 2024-04-10
|
||||
// Updated: 2024-08-03
|
||||
// Updated: 2024-08-04
|
||||
|
||||
namespace Index\Cache;
|
||||
|
||||
|
@ -44,13 +44,14 @@ final class CacheTools {
|
|||
|
||||
/** @param array<string, int|string> $uri */
|
||||
private static function resolveBackend(array $uri): ICacheBackend {
|
||||
static $backends = [];
|
||||
static $backends = null;
|
||||
if(!is_array($backends))
|
||||
$backends = [];
|
||||
|
||||
$scheme = $uri['scheme'];
|
||||
$backend = $backends[$scheme] ?? null;
|
||||
|
||||
if(in_array($scheme, $backends))
|
||||
$backend = $backends[$scheme];
|
||||
else {
|
||||
if(!($backend instanceof ICacheBackend)) {
|
||||
$backend = null;
|
||||
|
||||
if(array_key_exists($scheme, self::CACHE_PROTOS))
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
// MemcachedBackend.php
|
||||
// Created: 2024-04-10
|
||||
// Updated: 2024-08-03
|
||||
// Updated: 2024-08-04
|
||||
|
||||
namespace Index\Cache\Memcached;
|
||||
|
||||
|
@ -106,6 +106,9 @@ class MemcachedBackend implements ICacheBackend {
|
|||
|
||||
if(is_array($query['server']))
|
||||
foreach($query['server'] as $endPoint) {
|
||||
if(!is_string($endPoint))
|
||||
continue;
|
||||
|
||||
$parts = explode(';', $endPoint, 2);
|
||||
$weight = count($parts) > 1 ? (int)$parts[1] : 0;
|
||||
$endPoint = EndPoint::parse($parts[0]);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
// ValkeyProvider.php
|
||||
// Created: 2024-04-10
|
||||
// Updated: 2024-04-10
|
||||
// Updated: 2024-08-04
|
||||
|
||||
namespace Index\Cache\Valkey;
|
||||
|
||||
|
@ -63,11 +63,13 @@ class ValkeyProvider implements ICacheProvider {
|
|||
}
|
||||
|
||||
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 {
|
||||
return $this->redis->decrBy($key, $amount);
|
||||
$result = $this->redis->decrBy($key, $amount);
|
||||
return is_int($result) ? $result : 0;
|
||||
}
|
||||
|
||||
public function close(): void {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
// DbResultIterator.php
|
||||
// Created: 2024-02-06
|
||||
// Updated: 2024-08-03
|
||||
// Updated: 2024-08-04
|
||||
|
||||
namespace Index\Data;
|
||||
|
||||
|
@ -14,7 +14,7 @@ use Iterator;
|
|||
* @implements Iterator<int, object>
|
||||
*/
|
||||
class DbResultIterator implements Iterator {
|
||||
private bool $wasValid;
|
||||
private bool $wasValid = false;
|
||||
private object $current;
|
||||
|
||||
/**
|
||||
|
@ -29,6 +29,8 @@ class DbResultIterator implements Iterator {
|
|||
) {
|
||||
if(!is_callable($construct))
|
||||
throw new InvalidArgumentException('$construct must be a callable.');
|
||||
|
||||
$this->current = (object)[];
|
||||
}
|
||||
|
||||
public function current(): mixed {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
// DbTools.php
|
||||
// Created: 2021-05-02
|
||||
// Updated: 2024-08-03
|
||||
// Updated: 2024-08-04
|
||||
|
||||
namespace Index\Data;
|
||||
|
||||
|
@ -43,13 +43,14 @@ final class DbTools {
|
|||
|
||||
/** @param array<string, string|int> $uri */
|
||||
private static function resolveBackend(array $uri): IDbBackend {
|
||||
static $backends = [];
|
||||
static $backends = null;
|
||||
if(!is_array($backends))
|
||||
$backends = [];
|
||||
|
||||
$scheme = $uri['scheme'];
|
||||
$backend = $backends[$scheme] ?? null;
|
||||
|
||||
if(in_array($scheme, $backends))
|
||||
$backend = $backends[$scheme];
|
||||
else {
|
||||
if(!($backend instanceof IDbBackend)) {
|
||||
$backend = null;
|
||||
|
||||
if(array_key_exists($scheme, self::DB_PROTOS))
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
// MariaDBCharacterSetInfo.php
|
||||
// Created: 2021-05-02
|
||||
// Updated: 2024-08-03
|
||||
// Updated: 2024-08-04
|
||||
|
||||
namespace Index\Data\MariaDB;
|
||||
|
||||
|
@ -27,7 +27,8 @@ class MariaDBCharacterSetInfo {
|
|||
* @return string Character set name.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
public function getState(): int {
|
||||
return $this->charSet->state ?? 0;
|
||||
return isset($this->charSet->state) && is_scalar($this->charSet->state)
|
||||
? (int)$this->charSet->state : 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
// MariaDBConnection.php
|
||||
// Created: 2021-04-30
|
||||
// Updated: 2024-08-03
|
||||
// Updated: 2024-08-04
|
||||
|
||||
namespace Index\Data\MariaDB;
|
||||
|
||||
|
@ -250,7 +250,10 @@ class MariaDBConnection implements IDbConnection, IDbTransactions {
|
|||
* @return MariaDBWarning[] List of last errors.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
<?php
|
||||
// DbMigrationManager.php
|
||||
// Created: 2023-01-07
|
||||
// Updated: 2024-08-03
|
||||
// Updated: 2024-08-04
|
||||
|
||||
namespace Index\Data\Migration;
|
||||
|
||||
use stdClass;
|
||||
use InvalidArgumentException;
|
||||
use DateTimeImmutable;
|
||||
use DateTimeInterface;
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
use Index\XDateTime;
|
||||
use Index\Data\{IDbConnection,IDbStatement,DbType};
|
||||
use Index\Data\SQLite\SQLiteConnection;
|
||||
|
@ -44,8 +45,8 @@ final class %s implements IDbMigration {
|
|||
|
||||
EOF;
|
||||
|
||||
private IDbStatement $checkStmt;
|
||||
private IDbStatement $insertStmt;
|
||||
private ?IDbStatement $checkStmt = null;
|
||||
private ?IDbStatement $insertStmt = null;
|
||||
|
||||
/**
|
||||
* @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.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
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->addParameter(1, $name, DbType::STRING);
|
||||
$this->checkStmt->execute();
|
||||
|
@ -109,8 +114,12 @@ EOF;
|
|||
*
|
||||
* @param string $name Name of the migration.
|
||||
* @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 {
|
||||
if($this->insertStmt === null)
|
||||
throw new RuntimeException('Database migration manager has not been initialised.');
|
||||
|
||||
$dateTime = XDateTime::toISO8601String($dateTime);
|
||||
|
||||
$this->insertStmt->reset();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
// SQLiteBackend.php
|
||||
// Created: 2021-05-02
|
||||
// Updated: 2024-08-03
|
||||
// Updated: 2024-08-04
|
||||
|
||||
namespace Index\Data\SQLite;
|
||||
|
||||
|
@ -23,7 +23,9 @@ class SQLiteBackend implements IDbBackend {
|
|||
* @return string Version of the library.
|
||||
*/
|
||||
public function getVersion(): string {
|
||||
return SQLite3::version()['versionString'];
|
||||
$version = SQLite3::version();
|
||||
return isset($version['versionString']) && is_scalar($version['versionString'])
|
||||
? (string)$version['versionString'] : '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
// FormContent.php
|
||||
// Created: 2022-02-10
|
||||
// Updated: 2024-08-03
|
||||
// Updated: 2024-08-04
|
||||
|
||||
namespace Index\Http\Content;
|
||||
|
||||
|
@ -110,7 +110,13 @@ class FormContent implements IHttpContent {
|
|||
* @return FormContent Instance representing the request body.
|
||||
*/
|
||||
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 {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
// HttpRequest.php
|
||||
// Created: 2022-02-08
|
||||
// Updated: 2024-08-03
|
||||
// Updated: 2024-08-04
|
||||
|
||||
namespace Index\Http;
|
||||
|
||||
|
@ -136,11 +136,11 @@ class HttpRequest extends HttpMessage {
|
|||
*/
|
||||
public static function fromRequest(): HttpRequest {
|
||||
$build = new HttpRequestBuilder;
|
||||
$build->setHttpVersion($_SERVER['SERVER_PROTOCOL']);
|
||||
$build->setMethod($_SERVER['REQUEST_METHOD']);
|
||||
$build->setHttpVersion((string)filter_input(INPUT_SERVER, 'SERVER_PROTOCOL'));
|
||||
$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
|
||||
$path = $_SERVER['REQUEST_URI'];
|
||||
$path = (string)filter_input(INPUT_SERVER, 'REQUEST_URI');
|
||||
$pathQueryOffset = strpos($path, '?');
|
||||
if($pathQueryOffset !== false)
|
||||
$path = substr($path, 0, $pathQueryOffset);
|
||||
|
@ -154,22 +154,27 @@ class HttpRequest extends HttpMessage {
|
|||
$path = '/' . $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;
|
||||
$contentLength = 0;
|
||||
|
||||
$headers = self::getRawRequestHeaders();
|
||||
foreach($headers as $name => $value) {
|
||||
$nameLower = strtolower($name);
|
||||
if($nameLower === 'content-type')
|
||||
if($name === 'content-type')
|
||||
try {
|
||||
$contentType = MediaType::parse($value);
|
||||
} catch(InvalidArgumentException $ex) {
|
||||
$contentType = null;
|
||||
}
|
||||
elseif($nameLower === 'content-length')
|
||||
elseif($name === 'content-length')
|
||||
$contentLength = (int)$value;
|
||||
|
||||
$build->setHeader($name, $value);
|
||||
|
@ -189,29 +194,43 @@ class HttpRequest extends HttpMessage {
|
|||
|
||||
/** @return array<string, string> */
|
||||
private static function getRawRequestHeaders(): array {
|
||||
if(function_exists('getallheaders'))
|
||||
return getallheaders();
|
||||
if(function_exists('getallheaders')) {
|
||||
$raw = getallheaders();
|
||||
$headers = [];
|
||||
foreach($raw as $name => $value)
|
||||
if(is_string($name) && is_string($value))
|
||||
$headers[strtolower($name)] = $value;
|
||||
|
||||
return $headers;
|
||||
}
|
||||
|
||||
$headers = [];
|
||||
|
||||
foreach($_SERVER as $key => $value) {
|
||||
if(!is_string($key) || !is_scalar($value))
|
||||
continue;
|
||||
|
||||
if(substr($key, 0, 5) === 'HTTP_') {
|
||||
$key = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($key, 5)))));
|
||||
$headers[$key] = $value;
|
||||
$key = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($key, 5))));
|
||||
$headers[$key] = (string)$value;
|
||||
} elseif($key === 'CONTENT_TYPE') {
|
||||
$headers['Content-Type'] = $value;
|
||||
$headers['content-type'] = (string)$value;
|
||||
} elseif($key === 'CONTENT_LENGTH') {
|
||||
$headers['Content-Length'] = $value;
|
||||
$headers['content-length'] = (string)$value;
|
||||
}
|
||||
}
|
||||
|
||||
if(!isset($headers['Authorization'])) {
|
||||
if(isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) {
|
||||
$headers['Authorization'] = $_SERVER['REDIRECT_HTTP_AUTHORIZATION'];
|
||||
} elseif(isset($_SERVER['PHP_AUTH_USER'])) {
|
||||
$headers['Authorization'] = 'Basic ' . base64_encode($_SERVER['PHP_AUTH_USER'] . ':' . ($_SERVER['PHP_AUTH_PW'] ?? ''));
|
||||
} elseif(isset($_SERVER['PHP_AUTH_DIGEST'])) {
|
||||
$headers['Authorization'] = $_SERVER['PHP_AUTH_DIGEST'];
|
||||
if(!isset($headers['authorization'])) {
|
||||
if(filter_has_var(INPUT_SERVER, 'REDIRECT_HTTP_AUTHORIZATION')) {
|
||||
$headers['authorization'] = (string)filter_input(INPUT_SERVER, 'REDIRECT_HTTP_AUTHORIZATION');
|
||||
} elseif(filter_has_var(INPUT_SERVER, 'PHP_AUTH_USER')) {
|
||||
$headers['authorization'] = sprintf('Basic %s', base64_encode(sprintf(
|
||||
'%s:%s',
|
||||
(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');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
// HttpResponseBuilder.php
|
||||
// Created: 2022-02-08
|
||||
// Updated: 2024-08-03
|
||||
// Updated: 2024-08-04
|
||||
|
||||
namespace Index\Http;
|
||||
|
||||
|
@ -14,7 +14,7 @@ use Index\Performance\Timings;
|
|||
*/
|
||||
class HttpResponseBuilder extends HttpMessageBuilder {
|
||||
private int $statusCode = -1;
|
||||
private ?string $statusText;
|
||||
private ?string $statusText = null;
|
||||
|
||||
/** @var string[] */
|
||||
private array $vary = [];
|
||||
|
@ -61,7 +61,7 @@ class HttpResponseBuilder extends HttpMessageBuilder {
|
|||
* @param string $statusText Status text.
|
||||
*/
|
||||
public function setStatusText(string $statusText): void {
|
||||
$this->statusText = (string)$statusText;
|
||||
$this->statusText = $statusText;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
// HttpUploadedFile.php
|
||||
// Created: 2022-02-10
|
||||
// Updated: 2024-08-03
|
||||
// Updated: 2024-08-04
|
||||
|
||||
namespace Index\Http;
|
||||
|
||||
|
@ -200,6 +200,7 @@ class HttpUploadedFile implements ICloseable {
|
|||
$key = "_{$key}";
|
||||
|
||||
if(is_array($val)) {
|
||||
/** @var array<string, mixed> $val */
|
||||
$arr[$key] = self::traverseFILES($val, $keyName);
|
||||
} else {
|
||||
$arr[$key][$keyName] = $val;
|
||||
|
@ -230,8 +231,17 @@ class HttpUploadedFile implements ICloseable {
|
|||
if(is_array($arr['error'])) {
|
||||
$keys = array_keys($arr);
|
||||
|
||||
foreach($keys as $keyName)
|
||||
$out[$key] = array_merge_recursive($out[$key] ?? [], self::traverseFILES($arr[$keyName], (string)$keyName));
|
||||
foreach($keys as $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;
|
||||
}
|
||||
}
|
||||
|
@ -251,9 +261,13 @@ class HttpUploadedFile implements ICloseable {
|
|||
continue;
|
||||
|
||||
$key = substr($key, 1);
|
||||
$coll[$key] = isset($val['error'])
|
||||
? self::createFromFILE($val)
|
||||
: self::createObjectInstances($val);
|
||||
|
||||
if(isset($val['error']))
|
||||
/** @var array<string, int|string> $val */
|
||||
$coll[$key] = self::createFromFILE($val);
|
||||
else
|
||||
/** @var array<string, mixed> $val */
|
||||
$coll[$key] = self::createObjectInstances($val);
|
||||
}
|
||||
|
||||
return $coll;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
// HttpRouter.php
|
||||
// Created: 2024-03-28
|
||||
// Updated: 2024-08-03
|
||||
// Updated: 2024-08-04
|
||||
|
||||
namespace Index\Http\Routing;
|
||||
|
||||
|
@ -15,7 +15,7 @@ use Index\Http\ErrorHandling\{HtmlErrorHandler,IErrorHandler,PlainErrorHandler};
|
|||
class HttpRouter implements IRouter {
|
||||
use RouterTrait;
|
||||
|
||||
/** @var object[] */
|
||||
/** @var array{handler: callable, match?: string, prefix?: string}[] */
|
||||
private array $middlewares = [];
|
||||
|
||||
/** @var array<string, array<string, callable>> */
|
||||
|
@ -147,16 +147,16 @@ class HttpRouter implements IRouter {
|
|||
* @param callable $handler Middleware handler.
|
||||
*/
|
||||
public function use(string $path, callable $handler): void {
|
||||
$this->middlewares[] = $mwInfo = new stdClass;
|
||||
$mwInfo->handler = $handler;
|
||||
$mwInfo = [];
|
||||
$mwInfo['handler'] = $handler;
|
||||
|
||||
$prepared = self::preparePath($path, true);
|
||||
$mwInfo->dynamic = $prepared !== false;
|
||||
|
||||
if($mwInfo->dynamic)
|
||||
$mwInfo->match = $prepared;
|
||||
if($prepared === false)
|
||||
$mwInfo['prefix'] = $path;
|
||||
else
|
||||
$mwInfo->prefix = $path;
|
||||
$mwInfo['match'] = $prepared;
|
||||
|
||||
$this->middlewares[] = $mwInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -207,19 +207,19 @@ class HttpRouter implements IRouter {
|
|||
$middlewares = [];
|
||||
|
||||
foreach($this->middlewares as $mwInfo) {
|
||||
if($mwInfo->dynamic ?? false) {
|
||||
if(preg_match($mwInfo->match ?? '', $path, $args) !== 1)
|
||||
if(array_key_exists('match', $mwInfo)) {
|
||||
if(preg_match($mwInfo['match'], $path, $args) !== 1)
|
||||
continue;
|
||||
|
||||
array_shift($args);
|
||||
} else {
|
||||
if(!str_starts_with($path, $mwInfo->prefix ?? ''))
|
||||
} elseif(array_key_exists('prefix', $mwInfo)) {
|
||||
if(!str_starts_with($path, $mwInfo['prefix']))
|
||||
continue;
|
||||
|
||||
$args = [];
|
||||
}
|
||||
} else continue;
|
||||
|
||||
$middlewares[] = [$mwInfo->handler ?? null, $args];
|
||||
$middlewares[] = [$mwInfo['handler'], $args];
|
||||
}
|
||||
|
||||
$methods = [];
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
// IntegerBaseConverter.php
|
||||
// Created: 2024-07-31
|
||||
// Updated: 2024-07-31
|
||||
// Updated: 2024-08-04
|
||||
|
||||
namespace Index;
|
||||
|
||||
|
@ -95,6 +95,6 @@ class IntegerBaseConverter {
|
|||
$output += $pos * ($fromBase ** ($length - $i));
|
||||
}
|
||||
|
||||
return $output;
|
||||
return (int)$output;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
// PerformanceCounter.php
|
||||
// Created: 2022-02-16
|
||||
// Updated: 2024-08-01
|
||||
// Updated: 2024-08-04
|
||||
|
||||
namespace Index\Performance;
|
||||
|
||||
|
@ -24,7 +24,7 @@ final class PerformanceCounter {
|
|||
* @return int Ticks count.
|
||||
*/
|
||||
public static function getTicks(): int {
|
||||
return hrtime(true);
|
||||
return (int)hrtime(true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
// Stopwatch.php
|
||||
// Created: 2021-04-26
|
||||
// Updated: 2024-08-01
|
||||
// Updated: 2024-08-04
|
||||
|
||||
namespace Index\Performance;
|
||||
|
||||
|
@ -59,9 +59,9 @@ class Stopwatch {
|
|||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
// TimingPoint.php
|
||||
// Created: 2022-02-16
|
||||
// Updated: 2024-08-01
|
||||
// Updated: 2024-08-04
|
||||
|
||||
namespace Index\Performance;
|
||||
|
||||
|
@ -45,7 +45,7 @@ class TimingPoint {
|
|||
*
|
||||
* @return int Duration time amount.
|
||||
*/
|
||||
public function getDurationTime(): int {
|
||||
public function getDurationTime(): int|float {
|
||||
return $this->duration / PerformanceCounter::getFrequency();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
// Timings.php
|
||||
// Created: 2022-02-16
|
||||
// Updated: 2024-08-03
|
||||
// Updated: 2024-08-04
|
||||
|
||||
namespace Index\Performance;
|
||||
|
||||
|
@ -15,7 +15,7 @@ class Timings {
|
|||
private int $lastLapTicks;
|
||||
|
||||
/** @var TimingPoint[] */
|
||||
private array $laps;
|
||||
private array $laps = [];
|
||||
|
||||
/**
|
||||
* @param ?Stopwatch $sw Stopwatch to measure timing points from, null to start a new one.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
// XArray.php
|
||||
// Created: 2022-02-02
|
||||
// Updated: 2024-08-03
|
||||
// Updated: 2024-08-04
|
||||
|
||||
namespace Index;
|
||||
|
||||
|
@ -119,9 +119,9 @@ final class XArray {
|
|||
* Retrieves the first key in a collection.
|
||||
*
|
||||
* @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))
|
||||
return array_key_first($iterable);
|
||||
|
||||
|
@ -135,9 +135,9 @@ final class XArray {
|
|||
* Retrieves the last key in a collection.
|
||||
*
|
||||
* @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))
|
||||
return array_key_last($iterable);
|
||||
|
||||
|
@ -153,13 +153,13 @@ final class XArray {
|
|||
* @param mixed[] $iterable
|
||||
* @param mixed $value
|
||||
* @param bool $strict
|
||||
* @return int|string|false
|
||||
* @return mixed
|
||||
*/
|
||||
public static function indexOf(
|
||||
iterable $iterable,
|
||||
mixed $value,
|
||||
bool $strict = false
|
||||
): int|string|false {
|
||||
): mixed {
|
||||
if(is_array($iterable))
|
||||
return array_search($value, $iterable, $strict);
|
||||
|
||||
|
|
Loading…
Reference in a new issue