Skip to content

Commit 4ce6783

Browse files
committed
[WIP][3.x] Introduce PHPStan
Full commit message will follow
1 parent 229fb29 commit 4ce6783

12 files changed

+110
-16
lines changed

Diff for: .github/workflows/ci.yml

+33
Original file line numberDiff line numberDiff line change
@@ -120,3 +120,36 @@ jobs:
120120
uses: docker://hhvm/hhvm:3.30-lts-latest
121121
with:
122122
args: hhvm vendor/bin/phpunit
123+
124+
PHPStan:
125+
name: PHPStan (PHP ${{ matrix.php }})
126+
runs-on: ubuntu-22.04
127+
strategy:
128+
matrix:
129+
php:
130+
- 8.3
131+
- 8.2
132+
- 8.1
133+
- 8.0
134+
- 7.4
135+
- 7.3
136+
- 7.2
137+
- 7.1
138+
steps:
139+
- uses: actions/checkout@v4
140+
- uses: shivammathur/setup-php@v2
141+
with:
142+
php-version: ${{ matrix.php }}
143+
coverage: none
144+
ini-file: development
145+
ini-values: disable_functions='' # do not disable PCNTL functions on PHP < 8.1
146+
extensions: sockets, pcntl ${{ matrix.php >= 5.6 && ', event' || '' }} ${{ matrix.php >= 5.4 && ', ev' || '' }}
147+
env:
148+
fail-fast: true # fail step if any extension can not be installed
149+
- name: Install ext-uv on PHP 7+
150+
run: |
151+
sudo apt-get update -q && sudo apt-get install libuv1-dev
152+
echo "yes" | sudo pecl install ${{ matrix.php >= 8.0 && 'uv-0.3.0' || 'uv-0.2.4' }}
153+
php -m | grep -q uv || echo "extension=uv.so" >> "$(php -r 'echo php_ini_loaded_file();')"
154+
- run: composer install
155+
- run: vendor/bin/phpstan

Diff for: composer.json

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"php": ">=5.3.0"
3030
},
3131
"require-dev": {
32+
"phpstan/phpstan": "^1",
3233
"phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36"
3334
},
3435
"suggest": {

Diff for: phpstan.neon.dist

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
parameters:
2+
level: 5
3+
4+
paths:
5+
- src/
6+
- tests/

Diff for: src/ExtEvLoop.php

+12-2
Original file line numberDiff line numberDiff line change
@@ -192,13 +192,21 @@ public function run()
192192
$this->futureTickQueue->tick();
193193

194194
$hasPendingCallbacks = !$this->futureTickQueue->isEmpty();
195+
/**
196+
* @link https://github.com/phpstan/phpstan/issues/10566
197+
* @phpstan-ignore-next-line
198+
*/
195199
$wasJustStopped = !$this->running;
196200
$nothingLeftToDo = !$this->readStreams
197201
&& !$this->writeStreams
198202
&& !$this->timers->count()
199203
&& $this->signals->isEmpty();
200204

201205
$flags = Ev::RUN_ONCE;
206+
/**
207+
* @link https://github.com/phpstan/phpstan/issues/10566
208+
* @phpstan-ignore-next-line
209+
*/
202210
if ($wasJustStopped || $hasPendingCallbacks) {
203211
$flags |= Ev::RUN_NOWAIT;
204212
} elseif ($nothingLeftToDo) {
@@ -222,11 +230,13 @@ public function __destruct()
222230
}
223231

224232
foreach ($this->readStreams as $key => $stream) {
225-
$this->removeReadStream($key);
233+
$this->readStreams[$key]->stop();
234+
unset($this->readStreams[$key]);
226235
}
227236

228237
foreach ($this->writeStreams as $key => $stream) {
229-
$this->removeWriteStream($key);
238+
$this->readStreams[$key]->stop();
239+
unset($this->readStreams[$key]);
230240
}
231241
}
232242

Diff for: src/ExtEventLoop.php

+4
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,10 @@ public function run()
196196
$this->futureTickQueue->tick();
197197

198198
$flags = EventBase::LOOP_ONCE;
199+
/**
200+
* @link https://github.com/phpstan/phpstan/issues/10566
201+
* @phpstan-ignore-next-line
202+
*/
199203
if (!$this->running || !$this->futureTickQueue->isEmpty()) {
200204
$flags |= EventBase::LOOP_NONBLOCK;
201205
} elseif (!$this->readEvents && !$this->writeEvents && !$this->timerEvents->count() && $this->signals->isEmpty()) {

Diff for: src/ExtUvLoop.php

+16
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,10 @@ public function run()
213213
$this->futureTickQueue->tick();
214214

215215
$hasPendingCallbacks = !$this->futureTickQueue->isEmpty();
216+
/**
217+
* @link https://github.com/phpstan/phpstan/issues/10566
218+
* @phpstan-ignore-next-line
219+
*/
216220
$wasJustStopped = !$this->running;
217221
$nothingLeftToDo = !$this->readStreams
218222
&& !$this->writeStreams
@@ -223,12 +227,20 @@ public function run()
223227
// otherwise use UV::RUN_NOWAIT.
224228
// @link http://docs.libuv.org/en/v1.x/loop.html#c.uv_run
225229
$flags = \UV::RUN_ONCE;
230+
/**
231+
* @link https://github.com/phpstan/phpstan/issues/10566
232+
* @phpstan-ignore-next-line
233+
*/
226234
if ($wasJustStopped || $hasPendingCallbacks) {
227235
$flags = \UV::RUN_NOWAIT;
228236
} elseif ($nothingLeftToDo) {
229237
break;
230238
}
231239

240+
/**
241+
* @link https://github.com/JetBrains/phpstorm-stubs/pull/1614
242+
* @phpstan-ignore-next-line
243+
*/
232244
\uv_run($this->uv, $flags);
233245
}
234246
}
@@ -261,6 +273,10 @@ private function removeStream($stream)
261273
if (!isset($this->readStreams[(int) $stream])
262274
&& !isset($this->writeStreams[(int) $stream])) {
263275
\uv_poll_stop($this->streamEvents[(int) $stream]);
276+
/**
277+
* @link https://github.com/JetBrains/phpstorm-stubs/pull/1615
278+
* @phpstan-ignore-next-line
279+
*/
264280
\uv_close($this->streamEvents[(int) $stream]);
265281
unset($this->streamEvents[(int) $stream]);
266282
return;

Diff for: src/SignalsHandler.php

+6
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
*/
88
final class SignalsHandler
99
{
10+
/**
11+
* @var array<int, array<callable>>
12+
*/
1013
private $signals = array();
1114

1215
public function add($signal, $listener)
@@ -47,6 +50,9 @@ public function call($signal)
4750
}
4851
}
4952

53+
/**
54+
* @return int
55+
*/
5056
public function count($signal)
5157
{
5258
if (!isset($this->signals[$signal])) {

Diff for: src/StreamSelectLoop.php

+15-2
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ final class StreamSelectLoop implements LoopInterface
6363
private $running;
6464
private $pcntl = false;
6565
private $pcntlPoll = false;
66+
/**
67+
* @var SignalsHandler
68+
*/
6669
private $signals;
6770

6871
public function __construct()
@@ -169,6 +172,10 @@ public function removeSignal($signal, $listener)
169172

170173
$this->signals->remove($signal, $listener);
171174

175+
/**
176+
* @link https://github.com/phpstan/phpstan/issues/10576
177+
* @phpstan-ignore-next-line
178+
*/
172179
if ($this->signals->count($signal) === 0) {
173180
\pcntl_signal($signal, \SIG_DFL);
174181
}
@@ -183,7 +190,13 @@ public function run()
183190

184191
$this->timers->tick();
185192

186-
// Future-tick queue has pending callbacks ...
193+
/**
194+
* Future-tick queue has pending callbacks ...
195+
*
196+
*
197+
* @link https://github.com/phpstan/phpstan/issues/10566
198+
* @phpstan-ignore-next-line
199+
*/
187200
if (!$this->running || !$this->futureTickQueue->isEmpty()) {
188201
$timeout = 0;
189202

@@ -305,7 +318,7 @@ private function streamSelect(array &$read, array &$write, $timeout)
305318
} catch (\Throwable $e) { // @codeCoverageIgnoreStart
306319
\restore_error_handler();
307320
throw $e;
308-
} catch (\Exception $e) {
321+
} catch (\Exception $e) { /** @phpstan-ignore-line */
309322
\restore_error_handler();
310323
throw $e;
311324
} // @codeCoverageIgnoreEnd

Diff for: tests/ExtEventLoopTest.php

-9
Original file line numberDiff line numberDiff line change
@@ -62,15 +62,6 @@ public function createStream()
6262
return $stream;
6363
}
6464

65-
public function writeToStream($stream, $content)
66-
{
67-
if ('Linux' !== PHP_OS) {
68-
return parent::writeToStream($stream, $content);
69-
}
70-
71-
fwrite($stream, $content);
72-
}
73-
7465
/**
7566
* @group epoll-readable-error
7667
*/

Diff for: tests/StreamSelectLoopTest.php

+7-3
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ public function testStreamSelectReportsWarningForStreamWithFilter()
6161
$error = null;
6262
$previous = set_error_handler(function ($_, $errstr) use (&$error) {
6363
$error = $errstr;
64+
return true;
6465
});
6566

6667
try {
@@ -73,7 +74,9 @@ public function testStreamSelectReportsWarningForStreamWithFilter()
7374

7475
$this->assertNotNull($error);
7576

76-
$now = set_error_handler(function () { });
77+
$now = set_error_handler(function () {
78+
return true;
79+
});
7780
restore_error_handler();
7881
$this->assertEquals($previous, $now);
7982
}
@@ -114,7 +117,9 @@ public function testStreamSelectThrowsWhenCustomErrorHandlerThrowsForStreamWithF
114117

115118
$this->assertInstanceOf('RuntimeException', $e);
116119

117-
$now = set_error_handler(function () { });
120+
$now = set_error_handler(function () {
121+
return true;
122+
});
118123
restore_error_handler();
119124
$this->assertEquals($previous, $now);
120125
}
@@ -176,7 +181,6 @@ public function testSignalInterruptWithStream($signal)
176181
$loop = $this->loop;
177182
list($writeStream, $readStream) = $this->createSocketPair();
178183
$loop->addReadStream($readStream, function ($stream) use ($loop) {
179-
/** @var $loop LoopInterface */
180184
$read = fgets($stream);
181185
if ($read === "end loop\n") {
182186
$loop->stop();

Diff for: tests/bin/12-undefined.php

+5
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,9 @@
99
echo 'never';
1010
});
1111

12+
/**
13+
* We're ignore this line because the test using this file relies on the error caused by it.
14+
*
15+
* @phpstan-ignore-next-line
16+
*/
1217
$undefined->foo('bar');

Diff for: tests/bin/22-stop-uncaught.php

+5
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@
99
echo 'never';
1010
});
1111

12+
/**
13+
* Ignoring the next line until we raise the minimum PHP version to 7.1
14+
*
15+
* @phpstan-ignore-next-line
16+
*/
1217
set_exception_handler(function (Exception $e) {
1318
echo 'Uncaught error occured' . PHP_EOL;
1419
Loop::stop();

0 commit comments

Comments
 (0)