From 8c005f0b75e1abde21b881846008d9704e2e10ec Mon Sep 17 00:00:00 2001 From: Jagepard Date: Fri, 29 May 2026 08:39:50 +0300 Subject: [PATCH] refactor: PHP 8.4 compatibility & readonly props --- src/Facades/Request.php | 3 +- src/Facades/Rudra.php | 16 ++--- src/Request.php | 7 ++ src/Response.php | 9 ++- src/Rudra.php | 91 +++++++++++++------------- src/Traits/SetRudraContainersTrait.php | 5 ++ src/helpers.php | 5 +- tests/ConfigFunctionTest.php | 15 +++-- 8 files changed, 89 insertions(+), 62 deletions(-) diff --git a/src/Facades/Request.php b/src/Facades/Request.php index 6143714..4f6a0d5 100644 --- a/src/Facades/Request.php +++ b/src/Facades/Request.php @@ -11,7 +11,8 @@ namespace Rudra\Container\Facades; -use Rudra\Container\{Traits\FacadeTrait, Interfaces\ContainerInterface}; +use Rudra\Container\Traits\FacadeTrait; +use Rudra\Container\Interfaces\ContainerInterface; /** * @method static ContainerInterface get() diff --git a/src/Facades/Rudra.php b/src/Facades/Rudra.php index bab27b2..6863f49 100644 --- a/src/Facades/Rudra.php +++ b/src/Facades/Rudra.php @@ -11,14 +11,12 @@ namespace Rudra\Container\Facades; -use Rudra\Container\{ - Cookie, - Session, - Interfaces\RudraInterface, - Interfaces\RequestInterface, - Interfaces\ResponseInterface, - Interfaces\ContainerInterface -}; +use Rudra\Container\Cookie; +use Rudra\Container\Session; +use Rudra\Container\Interfaces\RudraInterface; +use Rudra\Container\Interfaces\RequestInterface; +use Rudra\Container\Interfaces\ResponseInterface; +use Rudra\Container\Interfaces\ContainerInterface; /** * @method static Cookie cookie() @@ -35,7 +33,7 @@ * @method static ContainerInterface waiting(array $services = []) * @method static ContainerInterface binding(array $contracts = []) * @method static mixed autowire($object, string $method, ?array $params = null) - * @method static array getParamsIoC(ReflectionMethod $constructor, ?array $params) + * @method static array getParamsIoC(\ReflectionMethod $constructor, ?array $params) * * @see \Rudra\Container\Rudra */ diff --git a/src/Request.php b/src/Request.php index 58d8b54..5dec82f 100644 --- a/src/Request.php +++ b/src/Request.php @@ -25,6 +25,7 @@ class Request implements RequestInterface /** * @return ContainerInterface */ + #[\Override] public function get(): ContainerInterface { return $this->containerize("get", Container::class, $_GET); @@ -33,6 +34,7 @@ public function get(): ContainerInterface /** * @return ContainerInterface */ + #[\Override] public function post(): ContainerInterface { return $this->containerize("post", Container::class, $_POST); @@ -41,6 +43,7 @@ public function post(): ContainerInterface /** * @return ContainerInterface */ + #[\Override] public function put(): ContainerInterface { return $this->containerize("put", Container::class); @@ -49,6 +52,7 @@ public function put(): ContainerInterface /** * @return ContainerInterface */ + #[\Override] public function patch(): ContainerInterface { return $this->containerize("patch", Container::class); @@ -57,6 +61,7 @@ public function patch(): ContainerInterface /** * @return ContainerInterface */ + #[\Override] public function delete(): ContainerInterface { return $this->containerize("delete", Container::class); @@ -65,6 +70,7 @@ public function delete(): ContainerInterface /** * @return ContainerInterface */ + #[\Override] public function server(): ContainerInterface { return $this->containerize("server", Container::class, $_SERVER); @@ -73,6 +79,7 @@ public function server(): ContainerInterface /** * @return ContainerInterface */ + #[\Override] public function files(): ContainerInterface { return $this->containerize("files", Container::class, $_FILES); diff --git a/src/Response.php b/src/Response.php index 0b5fb30..2377b15 100755 --- a/src/Response.php +++ b/src/Response.php @@ -19,9 +19,14 @@ class Response implements ResponseInterface * @param array $data * @return void */ - public function json(array $data): void + #[\Override] + public function json(array $data, int $code = 200): void { - header("Content-Type: application/json"); + if (!headers_sent()) { + http_response_code($code); + header("Content-Type: application/json"); + } + print $this->getJson($data); } diff --git a/src/Rudra.php b/src/Rudra.php index 49e1ab1..e822611 100644 --- a/src/Rudra.php +++ b/src/Rudra.php @@ -11,24 +11,17 @@ namespace Rudra\Container; -use Closure; -use ReflectionClass; -use ReflectionMethod; -use Rudra\Exceptions\{ - LogicException, - NotFoundException -}; -use Rudra\Container\{ - Interfaces\RudraInterface, - Traits\InstantiationsTrait, - Interfaces\FactoryInterface, -}; +use Rudra\Exceptions\LogicException; +use Rudra\Exceptions\NotFoundException; +use Rudra\Container\Interfaces\RudraInterface; +use Rudra\Container\Traits\InstantiationsTrait; +use Rudra\Container\Interfaces\FactoryInterface; use Psr\Container\ContainerInterface; /** - * @method waiting() Возвращает контейнер для временных данных (waiting). - * @method binding() Возвращает контейнер для связываний (binding). - * @method services() Возвращает контейнер для сервисов (services). + * @method waiting() Returns a container for temporary data / Возвращает контейнер для временных данных + * @method binding() Returns a container for bindings / Возвращает контейнер для связываний + * @method services() Returns a container for services / Возвращает контейнер для сервисов */ class Rudra implements RudraInterface, ContainerInterface { @@ -36,20 +29,25 @@ class Rudra implements RudraInterface, ContainerInterface public static ?RudraInterface $rudra = null; - protected array $allowedContainersMap = [ - 'waiting' => true, - 'binding' => true, - 'services' => true, - 'shared' => true, - 'config' => true - ]; - - protected array $allowedInstances = [ - 'request' => Request::class, - 'response' => Response::class, - 'cookie' => Cookie::class, - 'session' => Session::class - ]; + protected readonly array $allowedContainersMap; + protected readonly array $allowedInstances; + + public function __construct() + { + $this->allowedContainersMap = [ + 'waiting' => true, + 'binding' => true, + 'services' => true, + 'shared' => true, + 'config' => true + ]; + $this->allowedInstances = [ + 'request' => Request::class, + 'response' => Response::class, + 'cookie' => Cookie::class, + 'session' => Session::class + ]; + } /** * Handles dynamic method calls for the class. @@ -68,9 +66,9 @@ class Rudra implements RudraInterface, ContainerInterface * * @param string $method * @param array $parameters - * @return void + * @return mixed */ - public function __call(string $method, array $parameters = []) + public function __call(string $method, array $parameters = []): mixed { if (isset($this->allowedContainersMap[$method])) { $data = $parameters[0] ?? []; @@ -81,7 +79,7 @@ public function __call(string $method, array $parameters = []) return $this->init($this->allowedInstances[$method]); } - throw new LogicException("{$method}' is not allowed."); + throw new LogicException("Method '{$method}' is not allowed."); } /** @@ -93,6 +91,7 @@ public function __call(string $method, array $parameters = []) * * @return RudraInterface */ + #[\Override] public static function run(): RudraInterface { if (!isset(static::$rudra)) { @@ -116,6 +115,7 @@ public static function run(): RudraInterface * @param string $id * @return mixed */ + #[\Override] public function get(string $id): mixed { if ($this->has($id)) { @@ -133,7 +133,7 @@ public function get(string $id): mixed $waiting = $waitingStorage->get($id); - if ($waiting instanceof Closure) { + if ($waiting instanceof \Closure) { return $waiting(); } @@ -218,7 +218,7 @@ private function handleArrayObject(string $key, array $object): void */ private function resolveSetValue(mixed $value): mixed { - if ($value instanceof Closure) { + if ($value instanceof \Closure) { return $value(); } @@ -250,6 +250,7 @@ private function isFactoryImplementation(mixed $value): bool * @param string $id * @return boolean */ + #[\Override] public function has(string $id): bool { return $this->services()->has($id); @@ -297,7 +298,7 @@ private function setObject(string $key, string|object $object): void */ private function iOc(string $key, string $object, ?array $params = null): void { - $reflection = new ReflectionClass($object); + $reflection = new \ReflectionClass($object); $constructor = $reflection->getConstructor(); if ($constructor && $constructor->getNumberOfParameters() > 0) { @@ -329,7 +330,7 @@ public function new(string $object, ?array $params = null): object throw new LogicException("Class {$object} does not exist"); } - $reflection = new ReflectionClass($object); + $reflection = new \ReflectionClass($object); $constructor = $reflection->getConstructor(); if ($constructor && $constructor->getNumberOfParameters() > 0) { @@ -337,7 +338,7 @@ public function new(string $object, ?array $params = null): object return $reflection->newInstanceArgs($args); } - return $reflection->newInstanceWithoutConstructor(); + return new $object(); } /** @@ -349,14 +350,14 @@ public function new(string $object, ?array $params = null): object * Использует рефлексию для анализа параметров метода и разрешает их с помощью `getParamsIoC`. * Если метод не имеет параметров, он вызывается напрямую. В противном случае разрешённые аргументы передаются при вызове. * - * @param $object - * @param string $method - * @param array|null $params + * @param object|string $object + * @param string $method + * @param array|null $params * @return mixed */ - public function autowire($object, string $method, ?array $params = null): mixed + public function autowire(object|string$object, string $method, ?array $params = null): mixed { - $reflectionMethod = new ReflectionMethod($object, $method); + $reflectionMethod = new \ReflectionMethod($object, $method); if ($reflectionMethod->getNumberOfParameters() === 0) { return $reflectionMethod->invoke($object); @@ -376,11 +377,11 @@ public function autowire($object, string $method, ?array $params = null): mixed * Обрабатывает каждый параметр конструктора, разрешая зависимости с использованием привязок, имён классов или значений по умолчанию. * Если параметр не может быть разрешён, используется предоставленный массив `$params`. * - * @param ReflectionMethod $constructor + * @param \ReflectionMethod $constructor * @param array|null $params * @return array */ - public function getParamsIoC(ReflectionMethod $constructor, ?array $params): array + public function getParamsIoC(\ReflectionMethod $constructor, ?array $params): array { $i = 0; $params = is_array($params) ? array_values($params) : [$params]; @@ -432,7 +433,7 @@ public function getParamsIoC(ReflectionMethod $constructor, ?array $params): arr */ private function resolveDependency($className): object { - if ($className instanceof Closure) { + if ($className instanceof \Closure) { return $className(); } diff --git a/src/Traits/SetRudraContainersTrait.php b/src/Traits/SetRudraContainersTrait.php index 6c2241c..0e1e9fe 100644 --- a/src/Traits/SetRudraContainersTrait.php +++ b/src/Traits/SetRudraContainersTrait.php @@ -11,6 +11,7 @@ namespace Rudra\Container\Traits; +use Rudra\Exceptions\LogicException; use Rudra\Container\Interfaces\RudraInterface; trait SetRudraContainersTrait @@ -25,6 +26,10 @@ public function __construct(private RudraInterface $rudra) {} */ public function rudra(): RudraInterface { + if (!isset($this->rudra)) { + throw new LogicException('Rudra instance not initialized. Did you override __construct()?'); + } + return $this->rudra; } } diff --git a/src/helpers.php b/src/helpers.php index 2530798..ecd13b1 100644 --- a/src/helpers.php +++ b/src/helpers.php @@ -11,6 +11,7 @@ use Rudra\Container\Facades\Rudra; use Rudra\Container\Facades\Response; +use Rudra\Exceptions\NotFoundException; if (!function_exists('data')) { function data(mixed $data = null): mixed @@ -41,7 +42,9 @@ function config(?string $key, ?string $subKey = null): mixed return $data; } - return is_array($data) && isset($data[$subKey]) ? $data[$subKey] : false; + return (is_array($data) && array_key_exists($subKey, $data)) + ? $data[$subKey] + : throw new NotFoundException("Конфигурационный ключ \"$key.$subKey\" не найден."); } } diff --git a/tests/ConfigFunctionTest.php b/tests/ConfigFunctionTest.php index 54accad..5255494 100644 --- a/tests/ConfigFunctionTest.php +++ b/tests/ConfigFunctionTest.php @@ -15,6 +15,7 @@ use PHPUnit\Framework\TestCase; use Rudra\Container\Facades\Rudra; +use Rudra\Exceptions\NotFoundException; class ConfigFunctionTest extends TestCase { @@ -47,14 +48,20 @@ public function testReturnsSubKeyWhenPresent() $this->assertSame($value, config('app', 'name')); } - public function testReturnsFalseWhenSubKeyDoesNotExist() + public function testThrowsExceptionWhenSubKeyDoesNotExist(): void { - $this->assertFalse(config('app', 'non_existing_key')); + $this->expectException(NotFoundException::class); + $this->expectExceptionMessage('Конфигурационный ключ "app.non_existing_key" не найден.'); + + config('app', 'non_existing_key'); } - public function testReturnsFalseWhenValueIsNotArray() + public function testThrowsExceptionWhenValueIsNotArray(): void { // Предположим, что 'version' — это строка, а не массив - $this->assertFalse(config('version', 'subkey')); + $this->expectException(NotFoundException::class); + $this->expectExceptionMessage('Конфигурационный ключ "version.subkey" не найден.'); + + config('version', 'subkey'); } }