diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b63e2df..ac2b26a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,29 +7,6 @@ on: - cron: '0 0 * * *' jobs: - php74-min: - name: PHP 7.4 (--prefer-lowest) - runs-on: ubuntu-20.04 - steps: - - name: checkout - uses: actions/checkout@v2 - - name: composer test - uses: docker://chubbyphp/ci-php74:latest - env: - COMPOSER_ARGS: "--prefer-lowest" - COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} - STRYKER_DASHBOARD_API_KEY: ${{ secrets.STRYKER_DASHBOARD_API_KEY }} - php74: - name: PHP 7.4 - runs-on: ubuntu-20.04 - steps: - - name: checkout - uses: actions/checkout@v2 - - name: composer test - uses: docker://chubbyphp/ci-php74:latest - env: - COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} - STRYKER_DASHBOARD_API_KEY: ${{ secrets.STRYKER_DASHBOARD_API_KEY }} php80: name: PHP 8.0 runs-on: ubuntu-20.04 diff --git a/LICENSE b/LICENSE index bb61236..7b2b327 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2021 Dominik Zogg +Copyright (c) 2022 Dominik Zogg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 10eb5e1..3427370 100644 --- a/README.md +++ b/README.md @@ -25,21 +25,21 @@ A simple http handler implementation for API. ## Requirements - * php: ^7.4|^8.0 - * chubbyphp/chubbyphp-deserialization: ^3.0 - * chubbyphp/chubbyphp-negotiation: ^1.7 - * chubbyphp/chubbyphp-serialization: ^3.0 + * php: ^8.0 + * chubbyphp/chubbyphp-deserialization: ^3.4.1 + * chubbyphp/chubbyphp-negotiation: ^1.9 + * chubbyphp/chubbyphp-serialization: ^3.2 * psr/http-factory: ^1.0.1 * psr/http-message: ^1.0.1 * psr/http-server-middleware: ^1.0.1 - * psr/log: ^1.1.3 + * psr/log: ^1.1.4|^2.0|^3.0 ## Installation Through [Composer](http://getcomposer.org) as [chubbyphp/chubbyphp-api-http][1]. ```sh -composer require chubbyphp/chubbyphp-api-http "^4.1" +composer require chubbyphp/chubbyphp-api-http "^4.2" ``` ## Usage @@ -59,7 +59,7 @@ composer require chubbyphp/chubbyphp-api-http "^4.1" ## Copyright -Dominik Zogg 2021 +Dominik Zogg 2022 [1]: https://packagist.org/packages/chubbyphp/chubbyphp-api-http [2]: doc/ApiProblem/ApiProblem.md diff --git a/composer.json b/composer.json index d298584..f74d6e1 100644 --- a/composer.json +++ b/composer.json @@ -10,28 +10,28 @@ } ], "require": { - "php": "^7.4|^8.0", - "chubbyphp/chubbyphp-deserialization": "^3.0", - "chubbyphp/chubbyphp-negotiation": "^1.7", - "chubbyphp/chubbyphp-serialization": "^3.0", + "php": "^8.0", + "chubbyphp/chubbyphp-deserialization": "^3.4.1", + "chubbyphp/chubbyphp-negotiation": "^1.9", + "chubbyphp/chubbyphp-serialization": "^3.2", "psr/http-factory": "^1.0.1", "psr/http-message": "^1.0.1", "psr/http-server-middleware": "^1.0.1", - "psr/log": "^1.1.3" + "psr/log": "^1.1.4|^2.0|^3.0" }, "require-dev": { - "chubbyphp/chubbyphp-container": "^1.4|^2.0", + "chubbyphp/chubbyphp-container": "^2.1", "chubbyphp/chubbyphp-dev-helper": "dev-master", - "chubbyphp/chubbyphp-laminas-config-factory": "^1.1.1", + "chubbyphp/chubbyphp-laminas-config-factory": "^1.2", "chubbyphp/chubbyphp-mock": "^1.6.1", - "infection/infection": "^0.25.3", - "php-coveralls/php-coveralls": "^2.5.1", + "infection/infection": "^0.26.5", + "php-coveralls/php-coveralls": "^2.5.2", "phploc/phploc": "^7.0.2", "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "^1.1.2", - "phpunit/phpunit": "^9.5.10", - "pimple/pimple": "^3.4", - "psr/container": "^1.1.1|^2.0.1" + "phpstan/phpstan": "^1.4.8", + "phpunit/phpunit": "^9.5.17", + "pimple/pimple": "^3.5", + "psr/container": "^2.0.2" }, "autoload": { "psr-4": { "Chubbyphp\\ApiHttp\\": "src/" } @@ -40,11 +40,15 @@ "psr-4": { "Chubbyphp\\Tests\\ApiHttp\\": "tests/" } }, "config": { - "sort-packages": true + "sort-packages": true, + "allow-plugins": { + "infection/extension-installer": true, + "phpstan/extension-installer": true + } }, "extra": { "branch-alias": { - "dev-master": "4.1-dev" + "dev-master": "4.2-dev" } }, "scripts": { @@ -59,7 +63,7 @@ "@test:cs" ], "test:cs": "mkdir -p build && PHP_CS_FIXER_IGNORE_ENV=1 vendor/bin/php-cs-fixer fix --dry-run --stop-on-violation --cache-file=build/phpcs.cache", - "test:infection": "vendor/bin/infection --threads=$(nproc) --min-msi=98 --verbose --coverage=build/phpunit", + "test:infection": "vendor/bin/infection --threads=$(nproc) --min-msi=63 --verbose --coverage=build/phpunit", "test:integration": "vendor/bin/phpunit --testsuite=Integration --cache-result-file=build/phpunit/result.cache", "test:lint": "mkdir -p build && find src tests -name '*.php' -print0 | xargs -0 -n1 -P$(nproc) php -l | tee build/phplint.log", "test:loc": "mkdir -p build && vendor/bin/phploc src | tee build/phploc.log", diff --git a/infection.json b/infection.json index 70dba91..96e37a6 100644 --- a/infection.json +++ b/infection.json @@ -6,9 +6,12 @@ }, "timeout": 10, "logs": { - "text": "build/phpinfection.log", - "badge": { - "branch": "master" + "text": "build/phpinfection/infection.log", + "html": "build/phpinfection/infection.html", + "json": "build/phpinfection/infection.json", + "summary": "build/phpinfection/summary.log", + "stryker": { + "report": "master" } }, "mutators": { diff --git a/src/ApiProblem/AbstractApiProblem.php b/src/ApiProblem/AbstractApiProblem.php index f567f29..69bfb6d 100644 --- a/src/ApiProblem/AbstractApiProblem.php +++ b/src/ApiProblem/AbstractApiProblem.php @@ -6,28 +6,13 @@ abstract class AbstractApiProblem implements ApiProblemInterface { - protected string $type; - - protected int $status; - - protected string $title; - - protected ?string $detail; - - protected ?string $instance; - public function __construct( - string $type, - int $status, - string $title, - ?string $detail = null, - ?string $instance = null + protected string $type, + protected int $status, + protected string $title, + protected ?string $detail = null, + protected ?string $instance = null ) { - $this->type = $type; - $this->status = $status; - $this->title = $title; - $this->detail = $detail; - $this->instance = $instance; } public function getType(): string diff --git a/src/ApiProblem/ClientError/BadRequest.php b/src/ApiProblem/ClientError/BadRequest.php index ca69a0a..997dcbb 100644 --- a/src/ApiProblem/ClientError/BadRequest.php +++ b/src/ApiProblem/ClientError/BadRequest.php @@ -8,15 +8,10 @@ final class BadRequest extends AbstractApiProblem { - /** - * @var array> - */ - private array $invalidParameters = []; - /** * @param array> $invalidParameters */ - public function __construct(array $invalidParameters, ?string $detail = null, ?string $instance = null) + public function __construct(private array $invalidParameters, ?string $detail = null, ?string $instance = null) { parent::__construct( 'https://tools.ietf.org/html/rfc2616#section-10.4.1', @@ -25,8 +20,6 @@ public function __construct(array $invalidParameters, ?string $detail = null, ?s $detail, $instance ); - - $this->invalidParameters = $invalidParameters; } /** diff --git a/src/ApiProblem/ClientError/ExpectationFailed.php b/src/ApiProblem/ClientError/ExpectationFailed.php index 4ffbd3d..bcbf742 100644 --- a/src/ApiProblem/ClientError/ExpectationFailed.php +++ b/src/ApiProblem/ClientError/ExpectationFailed.php @@ -8,15 +8,10 @@ final class ExpectationFailed extends AbstractApiProblem { - /** - * @var array - */ - private array $failedExpectations = []; - /** * @param array $failedExpectations */ - public function __construct(array $failedExpectations, ?string $detail = null, ?string $instance = null) + public function __construct(private array $failedExpectations, ?string $detail = null, ?string $instance = null) { parent::__construct( 'https://tools.ietf.org/html/rfc2616#section-10.4.18', @@ -25,8 +20,6 @@ public function __construct(array $failedExpectations, ?string $detail = null, ? $detail, $instance ); - - $this->failedExpectations = $failedExpectations; } /** diff --git a/src/ApiProblem/ClientError/MethodNotAllowed.php b/src/ApiProblem/ClientError/MethodNotAllowed.php index c6cee36..20cbd45 100644 --- a/src/ApiProblem/ClientError/MethodNotAllowed.php +++ b/src/ApiProblem/ClientError/MethodNotAllowed.php @@ -8,19 +8,16 @@ final class MethodNotAllowed extends AbstractApiProblem { - private string $method; - - /** - * @var array - */ - private array $allowedMethods = []; - /** * @param string $method, * @param array $allowedMethods */ - public function __construct(string $method, array $allowedMethods, ?string $detail = null, ?string $instance = null) - { + public function __construct( + private string $method, + private array $allowedMethods, + ?string $detail = null, + ?string $instance = null + ) { parent::__construct( 'https://tools.ietf.org/html/rfc2616#section-10.4.6', 405, @@ -28,9 +25,6 @@ public function __construct(string $method, array $allowedMethods, ?string $deta $detail, $instance ); - - $this->method = $method; - $this->allowedMethods = $allowedMethods; } /** diff --git a/src/ApiProblem/ClientError/NotAcceptable.php b/src/ApiProblem/ClientError/NotAcceptable.php index ed1f90a..32ce48d 100644 --- a/src/ApiProblem/ClientError/NotAcceptable.php +++ b/src/ApiProblem/ClientError/NotAcceptable.php @@ -8,19 +8,12 @@ final class NotAcceptable extends AbstractApiProblem { - private string $accept; - - /** - * @var array - */ - private array $acceptables = []; - /** * @param array $acceptables */ public function __construct( - string $accept, - array $acceptables, + private string $accept, + private array $acceptables, ?string $detail = null, ?string $instance = null ) { @@ -31,9 +24,6 @@ public function __construct( $detail, $instance ); - - $this->accept = $accept; - $this->acceptables = $acceptables; } public function getAccept(): string diff --git a/src/ApiProblem/ClientError/PaymentRequired.php b/src/ApiProblem/ClientError/PaymentRequired.php index 0c74502..1e06871 100644 --- a/src/ApiProblem/ClientError/PaymentRequired.php +++ b/src/ApiProblem/ClientError/PaymentRequired.php @@ -8,15 +8,10 @@ final class PaymentRequired extends AbstractApiProblem { - /** - * @var array - */ - private array $paymentTypes = []; - /** * @param array $paymentTypes */ - public function __construct(array $paymentTypes, ?string $detail = null, ?string $instance = null) + public function __construct(private array $paymentTypes, ?string $detail = null, ?string $instance = null) { parent::__construct( 'https://tools.ietf.org/html/rfc2616#section-10.4.3', @@ -25,8 +20,6 @@ public function __construct(array $paymentTypes, ?string $detail = null, ?string $detail, $instance ); - - $this->paymentTypes = $paymentTypes; } /** diff --git a/src/ApiProblem/ClientError/PreconditionFailed.php b/src/ApiProblem/ClientError/PreconditionFailed.php index 1a834a7..c0e9730 100644 --- a/src/ApiProblem/ClientError/PreconditionFailed.php +++ b/src/ApiProblem/ClientError/PreconditionFailed.php @@ -8,15 +8,10 @@ final class PreconditionFailed extends AbstractApiProblem { - /** - * @var array - */ - private array $failedPreconditions = []; - /** * @param array $failedPreconditions */ - public function __construct(array $failedPreconditions, ?string $detail = null, ?string $instance = null) + public function __construct(private array $failedPreconditions, ?string $detail = null, ?string $instance = null) { parent::__construct( 'https://tools.ietf.org/html/rfc2616#section-10.4.13', @@ -25,8 +20,6 @@ public function __construct(array $failedPreconditions, ?string $detail = null, $detail, $instance ); - - $this->failedPreconditions = $failedPreconditions; } /** diff --git a/src/ApiProblem/ClientError/RequestEntityTooLarge.php b/src/ApiProblem/ClientError/RequestEntityTooLarge.php index a1ef42e..6c88682 100644 --- a/src/ApiProblem/ClientError/RequestEntityTooLarge.php +++ b/src/ApiProblem/ClientError/RequestEntityTooLarge.php @@ -8,9 +8,7 @@ final class RequestEntityTooLarge extends AbstractApiProblem { - private int $maxContentLength; - - public function __construct(int $maxContentLength, ?string $detail = null, ?string $instance = null) + public function __construct(private int $maxContentLength, ?string $detail = null, ?string $instance = null) { parent::__construct( 'https://tools.ietf.org/html/rfc2616#section-10.4.14', @@ -19,8 +17,6 @@ public function __construct(int $maxContentLength, ?string $detail = null, ?stri $detail, $instance ); - - $this->maxContentLength = $maxContentLength; } public function getMaxContentLength(): int diff --git a/src/ApiProblem/ClientError/RequestUriTooLong.php b/src/ApiProblem/ClientError/RequestUriTooLong.php index b82215f..1e9da88 100644 --- a/src/ApiProblem/ClientError/RequestUriTooLong.php +++ b/src/ApiProblem/ClientError/RequestUriTooLong.php @@ -8,9 +8,7 @@ final class RequestUriTooLong extends AbstractApiProblem { - private int $maxUriLength; - - public function __construct(int $maxUriLength, ?string $detail = null, ?string $instance = null) + public function __construct(private int $maxUriLength, ?string $detail = null, ?string $instance = null) { parent::__construct( 'https://tools.ietf.org/html/rfc2616#section-10.4.15', @@ -19,8 +17,6 @@ public function __construct(int $maxUriLength, ?string $detail = null, ?string $ $detail, $instance ); - - $this->maxUriLength = $maxUriLength; } public function getMaxUriLength(): int diff --git a/src/ApiProblem/ClientError/Unauthorized.php b/src/ApiProblem/ClientError/Unauthorized.php index 433a0af..36cf6a4 100644 --- a/src/ApiProblem/ClientError/Unauthorized.php +++ b/src/ApiProblem/ClientError/Unauthorized.php @@ -8,19 +8,12 @@ final class Unauthorized extends AbstractApiProblem { - private string $authorization; - - /** - * @var array - */ - private array $authorizationTypes = []; - /** * @param array $authorizationTypes */ public function __construct( - string $authorization, - array $authorizationTypes, + private string $authorization, + private array $authorizationTypes, ?string $detail = null, ?string $instance = null ) { @@ -31,9 +24,6 @@ public function __construct( $detail, $instance ); - - $this->authorization = $authorization; - $this->authorizationTypes = $authorizationTypes; } /** diff --git a/src/ApiProblem/ClientError/UnprocessableEntity.php b/src/ApiProblem/ClientError/UnprocessableEntity.php index f3af738..0a2b97a 100644 --- a/src/ApiProblem/ClientError/UnprocessableEntity.php +++ b/src/ApiProblem/ClientError/UnprocessableEntity.php @@ -8,15 +8,10 @@ final class UnprocessableEntity extends AbstractApiProblem { - /** - * @var array> - */ - private array $invalidParameters = []; - /** * @param array> $invalidParameters */ - public function __construct(array $invalidParameters, ?string $detail = null, ?string $instance = null) + public function __construct(private array $invalidParameters, ?string $detail = null, ?string $instance = null) { parent::__construct( 'https://tools.ietf.org/html/rfc4918#section-11.2', @@ -25,8 +20,6 @@ public function __construct(array $invalidParameters, ?string $detail = null, ?s $detail, $instance ); - - $this->invalidParameters = $invalidParameters; } /** diff --git a/src/ApiProblem/ClientError/UnsupportedMediaType.php b/src/ApiProblem/ClientError/UnsupportedMediaType.php index eecf98b..b729b62 100644 --- a/src/ApiProblem/ClientError/UnsupportedMediaType.php +++ b/src/ApiProblem/ClientError/UnsupportedMediaType.php @@ -8,19 +8,12 @@ final class UnsupportedMediaType extends AbstractApiProblem { - private string $mediaType; - - /** - * @var array - */ - private array $supportedMediaTypes = []; - /** * @param array $supportedMediaTypes */ public function __construct( - string $mediaType, - array $supportedMediaTypes, + private string $mediaType, + private array $supportedMediaTypes, ?string $detail = null, ?string $instance = null ) { @@ -31,9 +24,6 @@ public function __construct( $detail, $instance ); - - $this->mediaType = $mediaType; - $this->supportedMediaTypes = $supportedMediaTypes; } public function getMediaType(): string diff --git a/src/Manager/RequestManager.php b/src/Manager/RequestManager.php index f32d38b..4989103 100644 --- a/src/Manager/RequestManager.php +++ b/src/Manager/RequestManager.php @@ -10,11 +10,8 @@ final class RequestManager implements RequestManagerInterface { - private DeserializerInterface $deserializer; - - public function __construct(DeserializerInterface $deserializer) + public function __construct(private DeserializerInterface $deserializer) { - $this->deserializer = $deserializer; } /** diff --git a/src/Manager/ResponseManager.php b/src/Manager/ResponseManager.php index 694ea09..f34b312 100644 --- a/src/Manager/ResponseManager.php +++ b/src/Manager/ResponseManager.php @@ -12,14 +12,10 @@ final class ResponseManager implements ResponseManagerInterface { - private ResponseFactoryInterface $responseFactory; - - private SerializerInterface $serializer; - - public function __construct(ResponseFactoryInterface $responseFactory, SerializerInterface $serializer) - { - $this->responseFactory = $responseFactory; - $this->serializer = $serializer; + public function __construct( + private ResponseFactoryInterface $responseFactory, + private SerializerInterface $serializer + ) { } public function create( diff --git a/src/Middleware/AcceptAndContentTypeMiddleware.php b/src/Middleware/AcceptAndContentTypeMiddleware.php index 68b54ce..37d9e53 100644 --- a/src/Middleware/AcceptAndContentTypeMiddleware.php +++ b/src/Middleware/AcceptAndContentTypeMiddleware.php @@ -16,20 +16,11 @@ final class AcceptAndContentTypeMiddleware implements MiddlewareInterface { - private AcceptNegotiatorInterface $acceptNegotiator; - - private ContentTypeNegotiatorInterface $contentTypeNegotiator; - - private ResponseManagerInterface $responseManager; - public function __construct( - AcceptNegotiatorInterface $acceptNegotiator, - ContentTypeNegotiatorInterface $contentTypeNegotiator, - ResponseManagerInterface $responseManager + private AcceptNegotiatorInterface $acceptNegotiator, + private ContentTypeNegotiatorInterface $contentTypeNegotiator, + private ResponseManagerInterface $responseManager ) { - $this->acceptNegotiator = $acceptNegotiator; - $this->contentTypeNegotiator = $contentTypeNegotiator; - $this->responseManager = $responseManager; } public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface diff --git a/src/Middleware/ApiExceptionMiddleware.php b/src/Middleware/ApiExceptionMiddleware.php index 6218f00..c2ef1ab 100644 --- a/src/Middleware/ApiExceptionMiddleware.php +++ b/src/Middleware/ApiExceptionMiddleware.php @@ -15,19 +15,13 @@ final class ApiExceptionMiddleware implements MiddlewareInterface { - private ResponseManagerInterface $responseManager; - - private bool $debug; - private LoggerInterface $logger; public function __construct( - ResponseManagerInterface $responseManager, - bool $debug = false, + private ResponseManagerInterface $responseManager, + private bool $debug = false, ?LoggerInterface $logger = null ) { - $this->responseManager = $responseManager; - $this->debug = $debug; $this->logger = $logger ?? new NullLogger(); } @@ -68,7 +62,7 @@ private function backtrace(\Throwable $exception): array $exceptions = []; do { $exceptions[] = [ - 'class' => \get_class($exception), + 'class' => $exception::class, 'message' => $exception->getMessage(), 'code' => $exception->getCode(), 'file' => $exception->getFile(), diff --git a/src/ServiceFactory/ApiHttpServiceFactory.php b/src/ServiceFactory/ApiHttpServiceFactory.php index 822302a..e0dbd86 100644 --- a/src/ServiceFactory/ApiHttpServiceFactory.php +++ b/src/ServiceFactory/ApiHttpServiceFactory.php @@ -17,12 +17,10 @@ public function __invoke(): array { return [ 'api-http.request.manager' => static fn (ContainerInterface $container) => new RequestManager($container->get('deserializer')), - 'api-http.response.manager' => static function (ContainerInterface $container) { - return new ResponseManager( - $container->get('api-http.response.factory'), - $container->get('serializer') - ); - }, + 'api-http.response.manager' => static fn (ContainerInterface $container) => new ResponseManager( + $container->get('api-http.response.factory'), + $container->get('serializer') + ), 'api-http.response.factory' => static function (): void { throw new \RuntimeException('Missing response factory, define service "api-http.response.factory"'); }, diff --git a/src/ServiceProvider/ApiHttpServiceProvider.php b/src/ServiceProvider/ApiHttpServiceProvider.php index 341d8ff..f18dcc8 100644 --- a/src/ServiceProvider/ApiHttpServiceProvider.php +++ b/src/ServiceProvider/ApiHttpServiceProvider.php @@ -15,12 +15,10 @@ public function register(Container $container): void { $container['api-http.request.manager'] = static fn () => new RequestManager($container['deserializer']); - $container['api-http.response.manager'] = static function () use ($container) { - return new ResponseManager( - $container['api-http.response.factory'], - $container['serializer'] - ); - }; + $container['api-http.response.manager'] = static fn () => new ResponseManager( + $container['api-http.response.factory'], + $container['serializer'] + ); $container['api-http.response.factory'] = static function (): void { throw new \RuntimeException('Missing response factory, define service "api-http.response.factory"'); diff --git a/tests/Unit/Middleware/AcceptAndContentTypeMiddlewareTest.php b/tests/Unit/Middleware/AcceptAndContentTypeMiddlewareTest.php index ee2bc61..ad0ec7e 100644 --- a/tests/Unit/Middleware/AcceptAndContentTypeMiddlewareTest.php +++ b/tests/Unit/Middleware/AcceptAndContentTypeMiddlewareTest.php @@ -86,11 +86,8 @@ public function testWithAccept(): void $response = $this->getMockByCalls(ResponseInterface::class, []); $requestHandler = new class($response) implements RequestHandlerInterface { - private ResponseInterface $response; - - public function __construct(ResponseInterface $response) + public function __construct(private ResponseInterface $response) { - $this->response = $response; } public function handle(ServerRequestInterface $request): ResponseInterface @@ -188,11 +185,8 @@ public function testWithContentType(): void $response = $this->getMockByCalls(ResponseInterface::class, []); $requestHandler = new class($response) implements RequestHandlerInterface { - private ResponseInterface $response; - - public function __construct(ResponseInterface $response) + public function __construct(private ResponseInterface $response) { - $this->response = $response; } public function handle(ServerRequestInterface $request): ResponseInterface diff --git a/tests/Unit/Middleware/ApiExceptionMiddlewareTest.php b/tests/Unit/Middleware/ApiExceptionMiddlewareTest.php index 83060c7..2718541 100644 --- a/tests/Unit/Middleware/ApiExceptionMiddlewareTest.php +++ b/tests/Unit/Middleware/ApiExceptionMiddlewareTest.php @@ -35,11 +35,8 @@ public function testWithoutExceptionWithDebugWithLogger(): void $response = $this->getMockByCalls(ResponseInterface::class); $requestHandler = new class($response) implements RequestHandlerInterface { - private ResponseInterface $response; - - public function __construct(ResponseInterface $response) + public function __construct(private ResponseInterface $response) { - $this->response = $response; } public function handle(ServerRequestInterface $request): ResponseInterface