Skip to content

Commit

Permalink
phpstan level 7
Browse files Browse the repository at this point in the history
  • Loading branch information
sirn-se committed Feb 20, 2025
1 parent 6e574ac commit 2e22d06
Show file tree
Hide file tree
Showing 23 changed files with 107 additions and 43 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ cs: composer.lock
./vendor/bin/phpcs

stan: composer.lock
./vendor/bin/phpstan analyse
./vendor/bin/phpstan analyse --memory-limit 256M

coverage: composer.lock build
XDEBUG_MODE=coverage ./vendor/bin/phpunit --coverage-clover build/logs/clover.xml
Expand Down
3 changes: 2 additions & 1 deletion phpstan.neon
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
parameters:
level: 6
level: 7
paths:
- src
- tests
11 changes: 8 additions & 3 deletions src/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,11 @@ public function setFrameSize(int $frameSize): self

/**
* Get frame size.
* @return int Frame size in bytes
* @return int<1, max> Frame size in bytes
*/
public function getFrameSize(): int
{
return $this->frameSize;
return max(1, $this->frameSize);
}

/**
Expand Down Expand Up @@ -289,7 +289,12 @@ public function send(Message $message): Message
return $this->pushMessage($message);
}

// Push a message to stream
/**
* Push a message to stream.
* @template T of Message
* @param T $message
* @return T
*/
public function pushMessage(Message $message): Message
{
try {
Expand Down
16 changes: 13 additions & 3 deletions src/Frame/FrameHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public function pull(): Frame
{
// Read the frame "header" first, two bytes.
$data = $this->read(2);
list ($byte_1, $byte_2) = array_values(unpack('C*', $data));
list ($byte_1, $byte_2) = array_values($this->unpack('C*', $data));
$final = (bool)($byte_1 & 0b10000000); // Final fragment marker.
$rsv1 = (bool)($byte_1 & 0b01000000);
$rsv2 = (bool)($byte_1 & 0b00100000);
Expand All @@ -75,10 +75,10 @@ public function pull(): Frame
if ($payload_length > 125) {
if ($payload_length === 126) {
$data = $this->read(2); // 126: Payload length is a 16-bit unsigned int
$payload_length = current(unpack('n', $data));
$payload_length = current($this->unpack('n', $data));
} else {
$data = $this->read(8); // 127: Payload length is a 64-bit unsigned int
$payload_length = current(unpack('J', $data));
$payload_length = current($this->unpack('J', $data));
}
}

Expand Down Expand Up @@ -197,4 +197,14 @@ private function write(string $data): int
}
return $written;
}

/** @return array<int> */
private function unpack(string $format, string $string): array
{
$result = unpack($format, $string);
if ($result === false) {
throw new RuntimeException('Could not parse message header');
}
return $result;
}
}
3 changes: 1 addition & 2 deletions src/Http/Message.php
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,7 @@ private function handleHeader(string $name, mixed $value): void
if (!is_string($content) && !is_numeric($content)) {
throw new InvalidArgumentException("Invalid header value(s) provided.");
}
$content = trim($content);
$this->headers[strtolower($name)][$name][] = $content;
$this->headers[strtolower($name)][$name][] = trim((string)$content);
}
}
}
2 changes: 1 addition & 1 deletion src/Http/ServerRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public function withCookieParams(array $cookies): self

/**
* Retrieves the deserialized query string arguments, if any.
* @return array<string, mixed>
* @return array<string|int, mixed>
*/
public function getQueryParams(): array
{
Expand Down
4 changes: 2 additions & 2 deletions src/Message/Close.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public function getPayload(): string
$status_binstr = sprintf('%016b', $this->status);
$status_str = '';
foreach (str_split($status_binstr, 8) as $binstr) {
$status_str .= chr(bindec($binstr));
$status_str .= chr((int)bindec($binstr));
}
return $status_str . $this->content;
}
Expand All @@ -47,7 +47,7 @@ public function setPayload(string $payload = ''): void
$this->status = 0;
$this->content = '';
if (strlen($payload) > 0) {
$this->status = current(unpack('n', $payload));
$this->status = current(unpack('n', $payload) ?: []);
}
if (strlen($payload) > 2) {
$this->content = substr($payload, 2);
Expand Down
1 change: 1 addition & 0 deletions src/Message/Message.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ public function setPayload(string $payload = ''): void

/**
* Split messages into frames
* @param int<1, max> $frameSize
* @return array<Frame>
*/
public function getFrames(int $frameSize = 4096): array
Expand Down
24 changes: 15 additions & 9 deletions src/Message/MessageHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ class MessageHandler implements LoggerAwareInterface, Stringable

private FrameHandler $frameHandler;
private LoggerInterface $logger;
/** @var array{opcode: string, payload: string, frames: int}|null $readBuffer */
private array|null $readBuffer = null;
/** @var object{opcode: string, payload: string, frames: int}|null $readBuffer */
private object|null $readBuffer = null;

public function __construct(FrameHandler $frameHandler)
{
Expand All @@ -44,7 +44,13 @@ public function setLogger(LoggerInterface $logger): void
$this->frameHandler->setLogger($logger);
}

// Push message
/**
* Push message
* @template T of Message
* @param T $message
* @param int<1, max> $size
* @return T
*/
public function push(Message $message, int $size = self::DEFAULT_SIZE): Message
{
$frames = $message->getFrames($size);
Expand All @@ -70,26 +76,26 @@ public function pull(): Message
$payload = $frame->getPayload();

// Continuation and factual opcode
$payload_opcode = $continuation ? $this->readBuffer['opcode'] : $opcode;
$payload_opcode = $continuation ? $this->readBuffer->opcode : $opcode;

// First continuation frame, create buffer
if (!$final && !$continuation) {
$this->readBuffer = ['opcode' => $opcode, 'payload' => $payload, 'frames' => 1];
$this->readBuffer = (object)['opcode' => $opcode, 'payload' => $payload, 'frames' => 1];
continue; // Continue reading
}

// Subsequent continuation frames, add to buffer
if ($continuation) {
$this->readBuffer['payload'] .= $payload;
$this->readBuffer['frames']++;
$this->readBuffer->payload .= $payload;
$this->readBuffer->frames++;
}
} while (!$final);

// Final, return payload
$frames = 1;
if ($continuation) {
$payload = $this->readBuffer['payload'];
$frames = $this->readBuffer['frames'];
$payload = $this->readBuffer->payload;
$frames = $this->readBuffer->frames;
$this->readBuffer = null;
}

Expand Down
5 changes: 3 additions & 2 deletions src/Middleware/MiddlewareHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,10 @@ public function processIncoming(Connection $connection): Message

/**
* Process middlewares for outgoing messages.
* @template T of Message
* @param Connection $connection
* @param Message $message
* @return Message
* @param T $message
* @return T
*/
public function processOutgoing(Connection $connection, Message $message): Message
{
Expand Down
2 changes: 2 additions & 0 deletions src/Middleware/ProcessHttpStack.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public function __construct(Connection $connection, HttpHandler $httpHandler, ar
*/
public function handleHttpIncoming(): MessageInterface
{
/** @var ProcessHttpIncomingInterface|null $processor */
$processor = array_shift($this->processors);
if ($processor) {
return $processor->processHttpIncoming($this, $this->connection);
Expand All @@ -59,6 +60,7 @@ public function handleHttpIncoming(): MessageInterface
*/
public function handleHttpOutgoing(MessageInterface $message): MessageInterface
{
/** @var ProcessHttpOutgoingInterface|null $processor */
$processor = array_shift($this->processors);
if ($processor) {
return $processor->processHttpOutgoing($this, $this->connection, $message);
Expand Down
5 changes: 5 additions & 0 deletions src/Middleware/ProcessOutgoingInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,10 @@
*/
interface ProcessOutgoingInterface extends MiddlewareInterface
{
/**
* @template T of Message
* @param T $message
* @return T
*/
public function processOutgoing(ProcessStack $stack, Connection $connection, Message $message): Message;
}
7 changes: 5 additions & 2 deletions src/Middleware/ProcessStack.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public function __construct(Connection $connection, MessageHandler $messageHandl
*/
public function handleIncoming(): Message
{
/** @var ProcessIncomingInterface|null $processor */
$processor = array_shift($this->processors);
if ($processor) {
return $processor->processIncoming($this, $this->connection);
Expand All @@ -56,11 +57,13 @@ public function handleIncoming(): Message

/**
* Process middleware for outgoing message.
* @param Message $message
* @return Message
* @template T of Message
* @param T $message
* @return T
*/
public function handleOutgoing(Message $message): Message
{
/** @var ProcessOutgoingInterface|null $processor */
$processor = array_shift($this->processors);
if ($processor) {
return $processor->processOutgoing($this, $this->connection, $message);
Expand Down
3 changes: 2 additions & 1 deletion tests/mock/EchoLog.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ public function log($level, $message, array $context = [])
echo str_pad($level, 8) . " | {$message} {$context_string}\n";
}

public function interpolate($message, array $context = [])
/** @param array<string, mixed> $context */
public function interpolate(string $message, array $context = []): string
{
// Build a replacement array with braces around the context keys
$replace = [];
Expand Down
24 changes: 22 additions & 2 deletions tests/mock/MockStreamTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,31 @@

namespace WebSocket\Test;

use Phrity\Net\Mock\Stack\{
ExpectSocketClientTrait,
ExpectSocketServerTrait,
StackItem
};
use Phrity\Net\Mock\StreamCollection;
use Phrity\Net\Mock\Stack\StackItem;

/**
* This trait is used by phpunit tests to mock and track various socket/stream calls.
*/
trait MockStreamTrait
{
use ExpectSocketClientTrait;
use ExpectSocketServerTrait;

/** @var array<StackItem> $stack */
private array $stack = [];
private string $last_ws_key = '';


/* ---------- WebSocket Client combinded asserts --------------------------------------------------------------- */

/**
* @param array<mixed> $context
*/
private function expectWsClientConnect(
string $scheme = 'tcp',
string $host = 'localhost',
Expand Down Expand Up @@ -83,7 +94,7 @@ private function expectWsClientPerformHandshake(
$this->expectSocketStreamWrite()->addAssert(
function (string $method, array $params) use ($host, $path, $headers): void {
preg_match('/Sec-WebSocket-Key: ([\S]*)\r\n/', $params[0], $m);
$this->last_ws_key = $m[1];
$this->last_ws_key = $m[1] ?? '';
$this->assertEquals(
"GET {$path} HTTP/1.1\r\nHost: {$host}\r\nUser-Agent: websocket-client-php\r\nConnection: Upgrade"
. "\r\nUpgrade: websocket\r\nSec-WebSocket-Key: {$this->last_ws_key}\r\nSec-WebSocket-Version: 13"
Expand Down Expand Up @@ -123,6 +134,9 @@ function (string $method, array $params) use ($host, $path, $headers): void {

/* ---------- WebSocket Server combinded asserts --------------------------------------------------------------- */

/**
* @param array<mixed> $context
*/
private function expectWsServerSetup(string $scheme = 'tcp', int $port = 8000, array $context = []): void
{
$this->expectStreamFactoryCreateSocketServer()->addAssert(function ($method, $params) use ($scheme, $port) {
Expand All @@ -145,6 +159,9 @@ private function expectWsServerSetup(string $scheme = 'tcp', int $port = 8000, a
});
}

/**
* @param array<mixed> $keys
*/
private function expectWsSelectConnections(array $keys = []): StackItem
{
$this->expectStreamCollectionWaitRead()->setReturn(function ($params, $default, $collection) use ($keys) {
Expand All @@ -164,6 +181,9 @@ private function expectWsSelectConnections(array $keys = []): StackItem
return $last;
}

/**
* @param array<mixed> $headers
*/
private function expectWsServerPerformHandshake(
string $host = 'localhost:8000',
string $path = '/my/mock/path',
Expand Down
8 changes: 5 additions & 3 deletions tests/suites/client/ClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ public function testPayload128(): void
$this->expectWsClientPerformHandshake();
$client->connect();

/** @var string $payload */
$payload = file_get_contents(__DIR__ . '/../../mock/payload.128.txt');

// Sending message
Expand Down Expand Up @@ -205,6 +206,7 @@ public function testPayload65536(): void
$this->expectWsClientPerformHandshake();
$client->connect();

/** @var string $payload */
$payload = file_get_contents(__DIR__ . '/../../mock/payload.65536.txt');

// Sending message
Expand Down Expand Up @@ -986,7 +988,7 @@ public function testAlreadyStarted(): void
$client->start();

$this->expectSocketStreamClose();
unset($server);
unset($client);
}

public function testRunConnectionClosedException(): void
Expand All @@ -1007,7 +1009,7 @@ public function testRunConnectionClosedException(): void
$this->expectWsSelectConnections(['localhost:8000']);
$this->expectSocketStreamRead()->addAssert(function (string $method, array $params) {
$this->assertEquals(2, $params[0]);
})->setReturn(function () use ($client) {
})->setReturn(function () {
throw new ConnectionClosedException();
});
$this->expectSocketStreamIsConnected();
Expand Down Expand Up @@ -1036,7 +1038,7 @@ public function testRunClientException(): void
$this->expectWsSelectConnections(['localhost:8000']);
$this->expectSocketStreamRead()->addAssert(function (string $method, array $params) {
$this->assertEquals(2, $params[0]);
})->setReturn(function () use ($client) {
})->setReturn(function () {
throw new ClientException();
});
$this->expectSocketStreamIsConnected();
Expand Down
2 changes: 1 addition & 1 deletion tests/suites/client/ConfigTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,10 @@ public function testUriInstanceWssDefaultPort(): void
unset($client);
}

/** @return array<mixed> */
public static function uriStringAuthorizationDataProvider(): array
{
$encoded = urlencode('7{v^pF8;uPK.6VWu');

return [
[
'usename:password',
Expand Down
2 changes: 1 addition & 1 deletion tests/suites/connection/ConnectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public function testCreate(): void
$this->assertSame($connection, $connection->setTimeout(10));
$this->assertEquals(10, $connection->getTimeout());

$this->assertEmpty($connection->setLogger(new NullLogger()));
$connection->setLogger(new NullLogger());
$this->assertSame($connection, $connection->setFrameSize(64));
$this->assertEquals(64, $connection->getFrameSize());
$this->assertSame($connection, $connection->addMiddleware(new Callback()));
Expand Down
Loading

0 comments on commit 2e22d06

Please sign in to comment.