Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add static analysis tool PHPStan #927

Merged
merged 14 commits into from
Jul 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ jobs:
timeout_minutes: 5
max_attempts: 5
command: composer update --${{ matrix.stability }} --prefer-dist --no-interaction --no-progress
# command: composer install --prefer-dist --no-interaction --no-progress

- name: Static analysis
run: composer analyse

- name: Execute tests
run: vendor/bin/pest --coverage
Expand Down
6 changes: 5 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,15 @@
"require-dev": {
"pestphp/pest": "2.x-dev",
"mockery/mockery": "2.0.x-dev",
"guzzlehttp/guzzle": "^7.0"
"guzzlehttp/guzzle": "^7.0",
"phpstan/phpstan": "1.11.x-dev"
},
"config": {
"allow-plugins": {
"pestphp/pest-plugin": true
}
},
"scripts": {
"analyse": "phpstan analyse -c phpstan.neon --memory-limit=-1"
}
}
34 changes: 34 additions & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
parameters:
level: 5
paths:
- src
- tests
ignoreErrors:
-
path: src/Events/Revolt.php
messages:
- '#Property Workerman\\Events\\Revolt::\$driver has unknown class Revolt\\EventLoop\\Driver as its type.#'
- '#Call to static method getDriver\(\) on an unknown class Revolt\\EventLoop.#'
- '#Method Workerman\\Events\\Revolt::driver\(\) has invalid return type Revolt\\EventLoop\\Driver.#'
- '#Call to method .* on an unknown class Revolt\\EventLoop\\Driver.#'
-
path: src/Events/Swow.php
messages:
- '#Used function Swow\\Sync\\waitAll not found.#'
- '#Call to static method .* on an unknown class Swow\\.*.#'
- '#Function msleep not found.#'
- '#Function stream_poll_one not found.#'
- '#Caught class Swow\\SignalException not found.#'
- '#Function Swow\\Sync\\waitAll not found.#'
- '#Constant STREAM_POLLHUP not found.#'
- '#Constant STREAM_POLLIN not found.#'
- '#Constant STREAM_POLLNONE not found.#'
- '#Constant STREAM_POLLOUT not found.#'
- '#Property Workerman\\Events\\Swow::.* has unknown class Swow\\Coroutine as its type.#'
- path: src/Timer.php
message: '#Call to static method getSuspension\(\) on an unknown class Revolt\\EventLoop.#'
- path: tests/Pest.php
message: '#Undefined variable: \$this#'
- path: src/Worker.php
message: '#Constant LINE_VERSION_LENGTH not found.#'
- message: '#Parameter \#1 \$callback of function set_error_handler expects \(callable\(int, string, string, int\): bool\)\|null,.*#'
4 changes: 2 additions & 2 deletions src/Connection/TcpConnection.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@

/**
* TcpConnection.
* @property string websocketType
* @property string $websocketType
*/
class TcpConnection extends ConnectionInterface implements JsonSerializable
{
Expand Down Expand Up @@ -1033,7 +1033,7 @@ public function destroy(): void
/**
* Enable or disable Cache.
*
* @param mixed $value
* @param bool $value
*/
public static function enableCache(bool $value = true): void
{
Expand Down
2 changes: 2 additions & 0 deletions src/Events/Event.php
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ public function onReadable($stream, callable $func): void
$className = $this->eventClassName;
$fdKey = (int)$stream;
$event = new $this->eventClassName($this->eventBase, $stream, $className::READ | $className::PERSIST, $func, $stream);
// @phpstan-ignore-next-line Negated boolean expression is always false.
if (!$event || !$event->add()) {
return;
}
Expand Down Expand Up @@ -194,6 +195,7 @@ public function onWritable($stream, callable $func): void
$className = $this->eventClassName;
$fdKey = (int)$stream;
$event = new $this->eventClassName($this->eventBase, $stream, $className::WRITE | $className::PERSIST, $func, $stream);
// @phpstan-ignore-next-line Negated boolean expression is always false.
if (!$event || !$event->add()) {
return;
}
Expand Down
1 change: 1 addition & 0 deletions src/Events/Swow.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ public function repeat(float $interval, callable $func, array $args = []): int
$t = max($t, 1);
$that = $this;
$coroutine = Coroutine::run(static function () use ($t, $func, $args, $that): void {
// @phpstan-ignore-next-line While loop condition is always true.
while (true) {
msleep($t);
try {
Expand Down
11 changes: 9 additions & 2 deletions src/Protocols/Http/Request.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,13 @@ class Request
*/
protected static bool $enableCache = true;

/**
* Session id.
*
* @var mixed|string
*/
protected mixed $sid;

/**
* Request constructor.
*
Expand Down Expand Up @@ -296,11 +303,11 @@ public function session(): Session
/**
* Get/Set session id.
*
* @param null $sessionId
* @param string|null $sessionId
* @return string
* @throws Exception
*/
public function sessionId($sessionId = null): string
public function sessionId(string $sessionId = null): string
{
if ($sessionId) {
unset($this->sid);
Expand Down
2 changes: 1 addition & 1 deletion src/Protocols/Http/Response.php
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ protected function createHeadForFile(array $fileInfo): string

$fileInfo = pathinfo($file);
$extension = $fileInfo['extension'] ?? '';
$baseName = $fileInfo['basename'] ?? 'unknown';
$baseName = $fileInfo['basename'] ?: 'unknown';
if (!isset($headers['Content-Type'])) {
if (isset(self::$mimeTypeMap[$extension])) {
$head .= "Content-Type: " . self::$mimeTypeMap[$extension] . "\r\n";
Expand Down
2 changes: 0 additions & 2 deletions src/Protocols/Http/Session.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
namespace Workerman\Protocols\Http;

use Exception;
use JetBrains\PhpStorm\ArrayShape;
use RuntimeException;
use Workerman\Protocols\Http\Session\FileSessionHandler;
use Workerman\Protocols\Http\Session\SessionHandlerInterface;
Expand Down Expand Up @@ -381,7 +380,6 @@ public static function handlerClass(mixed $className = null, mixed $config = nul
*
* @return array
*/
#[ArrayShape(['lifetime' => "int", 'path' => "string", 'domain' => "string", 'secure' => "bool", 'httponly' => "bool", 'samesite' => "string"])]
public static function getCookieParams(): array
{
return [
Expand Down
16 changes: 4 additions & 12 deletions src/Protocols/Ws.php
Original file line number Diff line number Diff line change
Expand Up @@ -233,17 +233,13 @@ public static function input(string $buffer, AsyncTcpConnection $connection): bo
/**
* Websocket encode.
*
* @param mixed $payload
* @param string $payload
* @param AsyncTcpConnection $connection
* @return string
* @throws Throwable
*/
public static function encode(mixed $payload, AsyncTcpConnection $connection): string
public static function encode(string $payload, AsyncTcpConnection $connection): string
{
if (!is_scalar($payload)) {
throw new Exception("You can't send(" . gettype($payload) . ") to client, you need to convert it to string. ");
}

if (empty($connection->websocketType)) {
$connection->websocketType = self::BINARY_TYPE_BLOB;
}
Expand Down Expand Up @@ -371,12 +367,8 @@ public static function sendHandshake(AsyncTcpConnection $connection): void
$userHeader = $connection->headers ?? null;
$userHeaderStr = '';
if (!empty($userHeader)) {
if (is_array($userHeader)) {
foreach ($userHeader as $k => $v) {
$userHeaderStr .= "$k: $v\r\n";
}
} else {
$userHeaderStr .= $userHeader;
foreach ($userHeader as $k => $v) {
$userHeaderStr .= "$k: $v\r\n";
}
$userHeaderStr = "\r\n" . trim($userHeaderStr);
}
Expand Down
2 changes: 1 addition & 1 deletion src/Timer.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ public static function signalHandle(): void
*
* @param float $timeInterval
* @param callable $func
* @param mixed|array $args
* @param null|array $args
* @param bool $persistent
* @return int
*/
Expand Down
35 changes: 14 additions & 21 deletions src/Worker.php
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ class Worker
/**
* Emitted when data is received.
*
* @var callable
* @var ?callable
*/
public $onMessage = null;

Expand Down Expand Up @@ -312,7 +312,7 @@ class Worker
/**
* EventLoopClass
*
* @var class-string
* @var string|class-string
*/
public static string $eventLoopClass = '';

Expand Down Expand Up @@ -340,7 +340,7 @@ class Worker
/**
* Listening socket.
*
* @var resource
* @var ?resource
*/
protected $mainSocket = null;

Expand Down Expand Up @@ -534,7 +534,7 @@ class Worker

/**
* Standard output stream
* @var resource
* @var ?resource
*/
protected static $outputStream = null;

Expand Down Expand Up @@ -1279,7 +1279,7 @@ public static function resetStd(bool $throwException = true): void
}
// change output stream
static::$outputStream = null;
static::outputStream($STDOUT);
self::outputStream($STDOUT);
restore_error_handler();
return;
}
Expand Down Expand Up @@ -1516,14 +1516,10 @@ public static function checkWorkerStatusForWindows(): void
$process = $processData[0];
$startFile = $processData[1];
$status = proc_get_status($process);
if (isset($status['running'])) {
if (!$status['running']) {
static::safeEcho("process $startFile terminated and try to restart\n");
proc_close($process);
static::forkOneWorkerForWindows($startFile);
}
} else {
static::safeEcho("proc_get_status fail\n");
if (!$status['running']) {
static::safeEcho("process $startFile terminated and try to restart\n");
proc_close($process);
static::forkOneWorkerForWindows($startFile);
}
}
}
Expand Down Expand Up @@ -1686,6 +1682,7 @@ protected static function monitorWorkers(): void
protected static function monitorWorkersForLinux(): void
{
static::$status = static::STATUS_RUNNING;
// @phpstan-ignore-next-line While loop condition is always true.
while (1) {
// Calls signal handlers for pending signals.
pcntl_signal_dispatch();
Expand Down Expand Up @@ -1918,11 +1915,7 @@ public static function stopAll(int $code = 0, mixed $log = ''): void
static::$workers = [];
static::$globalEvent?->stop();

try {
exit($code);
} catch (Exception $e) {

}
exit($code);
}
}
}
Expand Down Expand Up @@ -1972,7 +1965,6 @@ protected static function writeStatisticsToStatusFile(): void
if (static::$masterPid === posix_getpid()) {
$allWorkerInfo = [];
foreach (static::$pidMap as $workerId => $pidArray) {
/** @var /Workerman/Worker $worker */
$worker = static::$workers[$workerId];
foreach ($pidArray as $pid) {
$allWorkerInfo[$pid] = ['name' => $worker->name, 'listen' => $worker->getSocketName()];
Expand Down Expand Up @@ -2086,7 +2078,6 @@ protected static function writeConnectionsStatisticsToStatusFile(): void
$currentWorker = current(static::$workers);
$defaultWorkerName = $currentWorker->name;

/** @var static $worker */
foreach (TcpConnection::$connections as $connection) {
/** @var TcpConnection $connection */
$transport = $connection->transport;
Expand Down Expand Up @@ -2180,7 +2171,7 @@ public static function log(mixed $msg, bool $decorated = false): void
*/
public static function safeEcho(string $msg, bool $decorated = false): bool
{
$stream = static::outputStream();
$stream = self::outputStream();
if (!$stream) {
return false;
}
Expand Down Expand Up @@ -2213,6 +2204,7 @@ private static function outputStream($stream = null)
if (!$stream) {
$stream = static::$outputStream ?: STDOUT;
}
// @phpstan-ignore-next-line Negated boolean expression is always false.
if (!$stream || !is_resource($stream) || 'stream' !== get_resource_type($stream)) {
return false;
}
Expand Down Expand Up @@ -2552,6 +2544,7 @@ public function acceptUdpConnection($socket): bool
if ($this->protocol !== null) {
/** @var ProtocolInterface $parser */
$parser = $this->protocol;
// @phpstan-ignore-next-line Left side of && is always true.
if ($parser && method_exists($parser, 'input')) {
while ($recvBuffer !== '') {
$len = $parser::input($recvBuffer, $connection);
Expand Down
2 changes: 1 addition & 1 deletion tests/Feature/UdpConnectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@

it('tests udp connection', function () use ($serverAddress) {
$socket = stream_socket_client($serverAddress, $errno, $errstr, 1);
expect($errno)->toBeInt(0);
expect($errno)->toBeInt()->toBe(0);
fwrite($socket, 'xiami');
$data = fread($socket, 1024);
expect($data)->toBeString('received: xiami');
Expand Down
3 changes: 3 additions & 0 deletions tests/Unit/Protocols/HttpTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
});

it('tests ::encode for non-object response', function () {
/** @var TcpConnection $tcpConnection */
$tcpConnection = Mockery::mock(TcpConnection::class);
$tcpConnection->headers = [
'foo' => 'bar',
Expand All @@ -73,6 +74,7 @@
});

it('tests ::encode for ' . Response::class, function () {
/** @var TcpConnection $tcpConnection */
$tcpConnection = Mockery::mock(TcpConnection::class);
$tcpConnection->headers = [
'foo' => 'bar',
Expand All @@ -93,6 +95,7 @@
});

it('tests ::decode', function () {
/** @var TcpConnection $tcpConnection */
$tcpConnection = Mockery::mock(TcpConnection::class);

//example request from ChatGPT :)
Expand Down
1 change: 1 addition & 0 deletions tests/Unit/Protocols/TextTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
use Workerman\Protocols\Text;

test(Text::class, function () {
/** @var ConnectionInterface $connection */
$connection = Mockery::mock(ConnectionInterface::class);

//::input
Expand Down