From d806fe457dc74ef7c4331a4f38b58afac50abed6 Mon Sep 17 00:00:00 2001 From: Petr Levtonov Date: Fri, 29 Nov 2019 23:50:07 +0100 Subject: [PATCH 1/2] Add phpstan and remove unsupported class --- .gitattributes | 1 + .gitignore | 1 + .travis.yml | 4 +- composer.json | 2 + phpstan.neon.dist | 6 ++ src/Spork/Batch/Strategy/ChunkStrategy.php | 2 +- .../Batch/Strategy/DoctrineMongoStrategy.php | 17 ---- src/Spork/Batch/Strategy/MongoStrategy.php | 63 --------------- src/Spork/Deferred/Deferred.php | 5 ++ src/Spork/Deferred/DeferredInterface.php | 15 ++-- src/Spork/Deferred/PromiseInterface.php | 2 +- src/Spork/EventDispatcher/EventDispatcher.php | 3 +- .../WrappedEventDispatcher.php | 12 +-- src/Spork/Fork.php | 6 +- src/Spork/ProcessManager.php | 6 +- src/Spork/SharedMemory.php | 19 +++-- .../Batch/Strategy/ChunkStrategyTest.php | 5 +- .../Batch/Strategy/MongoStrategyTest.php | 79 ------------------- tests/Spork/SignalTest.php | 3 - 19 files changed, 56 insertions(+), 195 deletions(-) create mode 100644 phpstan.neon.dist delete mode 100644 src/Spork/Batch/Strategy/DoctrineMongoStrategy.php delete mode 100644 src/Spork/Batch/Strategy/MongoStrategy.php delete mode 100644 tests/Spork/Batch/Strategy/MongoStrategyTest.php diff --git a/.gitattributes b/.gitattributes index 6f17b71..4c195c4 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3,5 +3,6 @@ /.gitignore export-ignore /.travis.yml export-ignore /php_cs.dist export-ignore +/phpstan.neon.dist export-ignore /phpunit.xml.dist export-ignore /tests export-ignore diff --git a/.gitignore b/.gitignore index 856e229..0965958 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ /.php_cs /.phpunit.result.cache /composer.lock +/phpstan.neon /phpunit.xml /vendor diff --git a/.travis.yml b/.travis.yml index 49f6aa8..b0508af 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ cache: php: - 7.2 - 7.3 + - 7.4 - nightly matrix: @@ -20,5 +21,6 @@ install: - composer install --no-progress --no-scripts --no-suggest --no-interaction script: - - vendor/bin/phpunit --coverage-text - vendor/bin/phpcs --standard=PSR12 src/ tests/ + - vendor/bin/phpstan analyse --no-progress --no-ansi --no-interaction + - vendor/bin/phpunit --no-interaction --colors=never diff --git a/composer.json b/composer.json index 9861cbf..46704cb 100644 --- a/composer.json +++ b/composer.json @@ -43,6 +43,7 @@ "ext-posix": "*", "ext-shmop": "*", "friendsofphp/php-cs-fixer": "^2.16", + "phpstan/phpstan": "^0.11.19", "phpunit/phpunit": "^8.4", "squizlabs/php_codesniffer": "^3.5" }, @@ -68,6 +69,7 @@ "/.gitignore", "/.travis.yml", "/php_cs.dist", + "/phpstan.neon.dist", "/phpunit.xml.dist", "/tests" ] diff --git a/phpstan.neon.dist b/phpstan.neon.dist new file mode 100644 index 0000000..986dc22 --- /dev/null +++ b/phpstan.neon.dist @@ -0,0 +1,6 @@ +parameters: + level: max + paths: + - src + - tests + inferPrivatePropertyTypeFromConstructor: true diff --git a/src/Spork/Batch/Strategy/ChunkStrategy.php b/src/Spork/Batch/Strategy/ChunkStrategy.php index 69d348c..6f529c0 100644 --- a/src/Spork/Batch/Strategy/ChunkStrategy.php +++ b/src/Spork/Batch/Strategy/ChunkStrategy.php @@ -37,7 +37,7 @@ public function createBatches($data) $data = iterator_to_array($data); } - $size = ceil(count($data) / $this->forks); + $size = (int)ceil(count($data) / $this->forks); return array_chunk($data, $size, $this->preserveKeys); } diff --git a/src/Spork/Batch/Strategy/DoctrineMongoStrategy.php b/src/Spork/Batch/Strategy/DoctrineMongoStrategy.php deleted file mode 100644 index eab64a7..0000000 --- a/src/Spork/Batch/Strategy/DoctrineMongoStrategy.php +++ /dev/null @@ -1,17 +0,0 @@ -addListener(Events::PRE_FORK, array($mongo, 'close')); - */ -class MongoStrategy extends AbstractStrategy -{ - public const DATA_CLASS = 'MongoCursor'; - - private $size; - private $skip; - - /** - * Constructor. - * - * @param integer $size The number of batches to create - * @param integer $skip The number of documents to skip - */ - public function __construct($size = 3, $skip = 0) - { - $this->size = $size; - $this->skip = $skip; - } - - public function createBatches($cursor) - { - $expected = static::DATA_CLASS; - if (!$cursor instanceof $expected) { - throw new UnexpectedTypeException($cursor, $expected); - } - - $skip = $this->skip; - $limit = ceil(($cursor->count(true) - $skip) / $this->size); - - $batches = []; - for ($i = 0; $i < $this->size; $i++) { - $batches[] = function () use ($cursor, $skip, $i, $limit) { - return $cursor->skip($skip + $i * $limit)->limit($limit); - }; - } - - return $batches; - } -} diff --git a/src/Spork/Deferred/Deferred.php b/src/Spork/Deferred/Deferred.php index 183e305..d2cacf2 100644 --- a/src/Spork/Deferred/Deferred.php +++ b/src/Spork/Deferred/Deferred.php @@ -15,10 +15,15 @@ class Deferred implements DeferredInterface { + /** @var string $state */ private $state; + /** @var array $progressCallbacks */ private $progressCallbacks; + /** @var array $alwaysCallbacks */ private $alwaysCallbacks; + /** @var array $doneCallbacks */ private $doneCallbacks; + /** @var array $failCallbacks */ private $failCallbacks; private $callbackArgs; diff --git a/src/Spork/Deferred/DeferredInterface.php b/src/Spork/Deferred/DeferredInterface.php index 3c6ede5..6934925 100644 --- a/src/Spork/Deferred/DeferredInterface.php +++ b/src/Spork/Deferred/DeferredInterface.php @@ -14,9 +14,8 @@ interface DeferredInterface extends PromiseInterface { /** - * Notifies the promise of progress. - * - * @param mixed $args Any arguments will be passed along to the callbacks + * Notifies the promise of progress. Any arguments will be passed along to + * the callbacks. * * @throws \LogicException If the promise is not pending * @return DeferredInterface The current promise @@ -26,9 +25,8 @@ public function notify(); /** * Marks the current promise as successful. * - * Calls "always" callbacks first, followed by "done" callbacks. - * - * @param mixed $args Any arguments will be passed along to the callbacks + * Calls "always" callbacks first, followed by "done" callbacks. Any + * arguments will be passed along to the callbacks * * @throws \LogicException If the promise was previously rejected * @return DeferredInterface The current promise @@ -38,9 +36,8 @@ public function resolve(); /** * Marks the current promise as failed. * - * Calls "always" callbacks first, followed by "fail" callbacks. - * - * @param mixed $args Any arguments will be passed along to the callbacks + * Calls "always" callbacks first, followed by "fail" callbacks. Any + * arguments will be passed along to the callbacks. * * @throws \LogicException If the promise was previously resolved * @return DeferredInterface The current promise diff --git a/src/Spork/Deferred/PromiseInterface.php b/src/Spork/Deferred/PromiseInterface.php index dd92a54..e41f520 100644 --- a/src/Spork/Deferred/PromiseInterface.php +++ b/src/Spork/Deferred/PromiseInterface.php @@ -65,7 +65,7 @@ public function done($done); * * The callback will be called immediately if the promise state is rejected. * - * @param callable $done The callback + * @param callable $fail The callback * * @return PromiseInterface The current promise */ diff --git a/src/Spork/EventDispatcher/EventDispatcher.php b/src/Spork/EventDispatcher/EventDispatcher.php index 93b7c20..d3c57b6 100644 --- a/src/Spork/EventDispatcher/EventDispatcher.php +++ b/src/Spork/EventDispatcher/EventDispatcher.php @@ -14,6 +14,7 @@ namespace Spork\EventDispatcher; use Symfony\Component\EventDispatcher\EventDispatcher as BaseEventDispatcher; +use Symfony\Contracts\EventDispatcher\Event; /** * Adds support for listening to signals. @@ -22,7 +23,7 @@ class EventDispatcher extends BaseEventDispatcher implements EventDispatcherInte { public function dispatchSignal($signal) { - $this->dispatch('spork.signal.' . $signal); + $this->dispatch(new Event(), 'spork.signal.' . $signal); } public function addSignalListener($signal, $callable, $priority = 0) diff --git a/src/Spork/EventDispatcher/WrappedEventDispatcher.php b/src/Spork/EventDispatcher/WrappedEventDispatcher.php index 3636b23..81871c9 100644 --- a/src/Spork/EventDispatcher/WrappedEventDispatcher.php +++ b/src/Spork/EventDispatcher/WrappedEventDispatcher.php @@ -13,22 +13,22 @@ namespace Spork\EventDispatcher; -use Symfony\Component\EventDispatcher\Event; -use Symfony\Component\EventDispatcher\EventDispatcherInterface as BaseEventDispatcherInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface as BaseInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Contracts\EventDispatcher\Event; class WrappedEventDispatcher implements EventDispatcherInterface { private $delegate; - public function __construct(BaseEventDispatcherInterface $delegate) + public function __construct(BaseInterface $delegate) { $this->delegate = $delegate; } public function dispatchSignal($signal) { - $this->delegate->dispatch('spork.signal.' . $signal); + $this->dispatch(new Event(), 'spork.signal.' . $signal); } public function addSignalListener($signal, $callable, $priority = 0) @@ -42,9 +42,9 @@ public function removeSignalListener($signal, $callable) $this->delegate->removeListener('spork.signal.' . $signal, $callable); } - public function dispatch($eventName, Event $event = null) + public function dispatch($event, string $eventName = null) { - return $this->delegate->dispatch($eventName, $event); + return call_user_func([$this->delegate, 'dispatch'], ...func_get_args()); } public function addListener($eventName, $listener, $priority = 0) diff --git a/src/Spork/Fork.php b/src/Spork/Fork.php index 29e4167..fcb22ed 100644 --- a/src/Spork/Fork.php +++ b/src/Spork/Fork.php @@ -221,7 +221,7 @@ public function notify() $args = func_get_args(); array_unshift($args, $this); - call_user_func_array([$this->defer, 'notify'], $args); + call_user_func_array([$this->defer, 'notify'], array_values($args)); return $this; } @@ -231,7 +231,7 @@ public function resolve() $args = func_get_args(); array_unshift($args, $this); - call_user_func_array([$this->defer, 'resolve'], $args); + call_user_func_array([$this->defer, 'resolve'], array_values($args)); return $this; } @@ -241,7 +241,7 @@ public function reject() $args = func_get_args(); array_unshift($args, $this); - call_user_func_array([$this->defer, 'reject'], $args); + call_user_func_array([$this->defer, 'reject'], array_values($args)); return $this; } diff --git a/src/Spork/ProcessManager.php b/src/Spork/ProcessManager.php index f9a749f..0355874 100644 --- a/src/Spork/ProcessManager.php +++ b/src/Spork/ProcessManager.php @@ -20,12 +20,14 @@ use Spork\Exception\UnexpectedTypeException; use Spork\Util\Error; use Spork\Util\ExitMessage; +use Symfony\Contracts\EventDispatcher\Event; class ProcessManager { private $dispatcher; private $factory; private $debug; + /** @var bool $zombieOkay */ private $zombieOkay; private $signal; @@ -92,7 +94,7 @@ public function fork($callable) } // allow the system to cleanup before forking - $this->dispatcher->dispatch(Events::PRE_FORK); + call_user_func([$this->dispatcher, 'dispatch'], new Event(), Events::PRE_FORK); if (-1 === $pid = pcntl_fork()) { throw new ProcessControlException('Unable to fork a new process'); @@ -124,7 +126,7 @@ public function fork($callable) }); // dispatch an event so the system knows it's in a new process - $this->dispatcher->dispatch(Events::POST_FORK); + call_user_func([$this->dispatcher, 'dispatch'], new Event(), Events::POST_FORK); if (!$this->debug) { ob_start(); diff --git a/src/Spork/SharedMemory.php b/src/Spork/SharedMemory.php index 254c252..e7650a1 100644 --- a/src/Spork/SharedMemory.php +++ b/src/Spork/SharedMemory.php @@ -18,7 +18,9 @@ */ class SharedMemory { + /** @var int $pid */ private $pid; + /** @var int|null $pid */ private $ppid; private $signal; @@ -51,7 +53,7 @@ public function __construct($pid = null, $signal = null) */ public function receive() { - if (($shmId = @shmop_open($this->pid, 'a', 0, 0)) > 0) { + if ($shmId = @shmop_open($this->pid, 'a', 0, 0)) { $serializedMessages = shmop_read($shmId, 0, shmop_size($shmId)); shmop_delete($shmId); shmop_close($shmId); @@ -65,15 +67,15 @@ public function receive() /** * Writes a message to the shared memory. * - * @param mixed $message The message to send - * @param integer $signal The signal to send afterward - * @param integer $pause The number of microseconds to pause after signalling + * @param mixed $message The message to send + * @param int|null|false $signal The signal to send afterward. Null to use + * @param int $pause The number of microseconds to pause after signalling */ public function send($message, $signal = null, $pause = 500) { $messageArray = []; - if (($shmId = @shmop_open($this->pid, 'a', 0, 0)) > 0) { + if ($shmId = @shmop_open($this->pid, 'a', 0, 0)) { // Read any existing messages in shared memory $readMessage = shmop_read($shmId, 0, shmop_size($shmId)); $messageArray[] = unserialize($readMessage); @@ -87,14 +89,14 @@ public function send($message, $signal = null, $pause = 500) // Write new serialized message to shared memory $shmId = shmop_open($this->pid, 'c', 0644, strlen($serializedMessage)); - if (!$shmId) { + if (!is_resource($shmId)) { throw new ProcessControlException(sprintf( 'Not able to create shared memory segment for PID: %s', $this->pid )); } elseif (shmop_write($shmId, $serializedMessage, 0) !== strlen($serializedMessage)) { throw new ProcessControlException( - sprintf('Not able to write message to shared memory segment for segment ID: %s', $shmId) + 'Not able to write message to shared memory segment.' ); } @@ -102,7 +104,8 @@ public function send($message, $signal = null, $pause = 500) return; } - $this->signal($signal ?: $this->signal); + $this->signal(null === $signal ? $this->signal : $signal); + usleep($pause); } diff --git a/tests/Spork/Batch/Strategy/ChunkStrategyTest.php b/tests/Spork/Batch/Strategy/ChunkStrategyTest.php index b589f73..7890ffc 100644 --- a/tests/Spork/Batch/Strategy/ChunkStrategyTest.php +++ b/tests/Spork/Batch/Strategy/ChunkStrategyTest.php @@ -23,10 +23,13 @@ public function testChunkArray($number, $expectedCounts) $strategy = new ChunkStrategy($number); $batches = $strategy->createBatches(range(1, 100)); - $this->assertEquals(count($expectedCounts), count($batches)); + $batchesCount = 0; foreach ($batches as $i => $batch) { + ++$batchesCount; $this->assertCount($expectedCounts[$i], $batch); } + + $this->assertEquals(count($expectedCounts), $batchesCount); } public function provideNumber() diff --git a/tests/Spork/Batch/Strategy/MongoStrategyTest.php b/tests/Spork/Batch/Strategy/MongoStrategyTest.php deleted file mode 100644 index 568a7b3..0000000 --- a/tests/Spork/Batch/Strategy/MongoStrategyTest.php +++ /dev/null @@ -1,79 +0,0 @@ -markTestSkipped('Mongo extension is not loaded'); - } - - try { - $this->mongo = new \MongoClient(); - } catch (\MongoConnectionException $e) { - $this->markTestSkipped($e->getMessage()); - } - - $this->manager = new ProcessManager(); - $this->manager->setDebug(true); - - // close the connection prior to forking - $mongo = $this->mongo; - $this->manager->addListener(Events::PRE_FORK, function () use ($mongo) { - $mongo->close(); - }); - } - - protected function tearDown(): void - { - if ($this->mongo) { - $this->mongo->close(); - } - - unset($this->mongo, $this->manager); - } - - public function testBatchJob() - { - $coll = $this->mongo->spork->widgets; - - $coll->remove(); - $coll->batchInsert([ - ['name' => 'Widget 1'], - ['name' => 'Widget 2'], - ['name' => 'Widget 3'], - ]); - - $this->manager->createBatchJob($coll->find(), new MongoStrategy()) - ->execute(function ($doc) use ($coll) { - $coll->update( - ['_id' => $doc['_id']], - ['$set' => ['seen' => true]] - ); - }); - - $this->manager->wait(); - - foreach ($coll->find() as $doc) { - $this->assertArrayHasKey('seen', $doc); - } - } -} diff --git a/tests/Spork/SignalTest.php b/tests/Spork/SignalTest.php index aae25b6..331a58c 100644 --- a/tests/Spork/SignalTest.php +++ b/tests/Spork/SignalTest.php @@ -15,10 +15,7 @@ class SignalTest extends TestCase { - /** @var \Spork\ProcessManager $manager */ private $manager; - - /** @var bool $async */ private $async; protected function setUp(): void From 19b5f8eba03bedf96e381f6bec6b3d2a31b7d8ed Mon Sep 17 00:00:00 2001 From: Petr Levtonov Date: Sun, 8 Dec 2019 22:43:51 +0100 Subject: [PATCH 2/2] Update CHANGELOG.md --- CHANGELOG.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 66565a8..625e899 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.0.0] - 2019-11-29 +### Added + +- d806fe4: Added phpstan to travis for static code analysis. + ### Changed - #1: PHP 7.2 min requirement and updated library to support it. @@ -17,7 +21,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed -- #1: Removed support for PHP <7.2 +- #1: Removed support for PHP <7.2. +- d806fe4: Removed deprecated mongo db support. + +### Fixed + +- d806fe4: Fixed static code analysis issues. ## [0.3.0] - 2015-05-18 @@ -29,4 +38,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added serializable objects for exit and error messages. [Unreleased]: https://github.com/TheLevti/spork/compare/0.3.0...HEAD +[1.0.0]: https://github.com/TheLevti/spork/releases/1.0.0 [0.3.0]: https://github.com/TheLevti/spork/releases/0.3.0