From 63ad79d2a1be2c9dbe3d18900e4e0758bd92a429 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Wed, 10 Jun 2026 09:33:19 +0100 Subject: [PATCH 1/2] inline symplify/easy-parlallel here, to keep less deps --- composer.json | 8 +- .../EasyCodingStandardApplication.php | 4 +- src/Console/Command/WorkerCommand.php | 4 +- .../Application/ParallelFileProcessor.php | 16 +- .../CommandLine/WorkerCommandLineFactory.php | 172 ++++++++++++++++++ .../Contract/SerializableInterface.php | 18 ++ src/Parallel/CpuCoreCountProvider.php | 28 +++ src/Parallel/Enum/Action.php | 26 +++ src/Parallel/Enum/Content.php | 21 +++ src/Parallel/Enum/ReactCommand.php | 21 +++ src/Parallel/Enum/ReactEvent.php | 31 ++++ .../ParallelShouldNotHappenException.php | 11 ++ .../CommandFromReflectionFactory.php | 40 ++++ src/Parallel/ScheduleFactory.php | 29 +++ src/Parallel/ValueObject/ParallelProcess.php | 156 ++++++++++++++++ src/Parallel/ValueObject/ProcessPool.php | 69 +++++++ src/Parallel/ValueObject/Schedule.php | 36 ++++ src/Parallel/WorkerRunner.php | 8 +- .../ValueObject/Error/CodingStandardError.php | 2 +- src/ValueObject/Error/FileDiff.php | 2 +- src/ValueObject/Error/SystemError.php | 2 +- 21 files changed, 683 insertions(+), 21 deletions(-) create mode 100644 src/Parallel/CommandLine/WorkerCommandLineFactory.php create mode 100644 src/Parallel/Contract/SerializableInterface.php create mode 100644 src/Parallel/CpuCoreCountProvider.php create mode 100644 src/Parallel/Enum/Action.php create mode 100644 src/Parallel/Enum/Content.php create mode 100644 src/Parallel/Enum/ReactCommand.php create mode 100644 src/Parallel/Enum/ReactEvent.php create mode 100644 src/Parallel/Exception/ParallelShouldNotHappenException.php create mode 100644 src/Parallel/Reflection/CommandFromReflectionFactory.php create mode 100644 src/Parallel/ScheduleFactory.php create mode 100644 src/Parallel/ValueObject/ParallelProcess.php create mode 100644 src/Parallel/ValueObject/ProcessPool.php create mode 100644 src/Parallel/ValueObject/Schedule.php diff --git a/composer.json b/composer.json index c5222e3d551..b15321799fe 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "symplify/easy-coding-standard", - "description": "Use Coding Standard with 0-knowledge of PHP-CS-Fixer and PHP_CodeSniffer.", + "description": "The easiest way to use coding standard in a PHP project, runs on PHP 7.2+, prepared sets out of box, step-bystep levels, no-brainer", "license": "MIT", "keywords": [ "static analysis", @@ -13,18 +13,22 @@ ], "require": { "php": ">=8.4", + "clue/ndjson-react": "^1.3", "composer/pcre": "^3.3.2", "composer/xdebug-handler": "^3.0.5", "entropy/entropy": "^0.3", + "fidry/cpu-core-counter": "^1.3", "friendsofphp/php-cs-fixer": "^3.95.5", "illuminate/container": "12.39.*", "nette/utils": "^4.1", + "react/child-process": "^0.6.7", + "react/event-loop": "^1.6", + "react/socket": "^1.17", "sebastian/diff": "^9.0", "squizlabs/php_codesniffer": "^4.0.1", "symfony/console": "^6.4.24", "symfony/finder": "^7.4", "symplify/coding-standard": "^13.1", - "symplify/easy-parallel": "^11.2", "webmozart/assert": "^2.4" }, "require-dev": { diff --git a/src/Application/EasyCodingStandardApplication.php b/src/Application/EasyCodingStandardApplication.php index 07fcdfa813a..6e5000911a9 100644 --- a/src/Application/EasyCodingStandardApplication.php +++ b/src/Application/EasyCodingStandardApplication.php @@ -15,6 +15,8 @@ use Symplify\EasyCodingStandard\FileSystem\StaticRelativeFilePathHelper; use Symplify\EasyCodingStandard\Finder\SourceFinder; use Symplify\EasyCodingStandard\Parallel\Application\ParallelFileProcessor; +use Symplify\EasyCodingStandard\Parallel\CpuCoreCountProvider; +use Symplify\EasyCodingStandard\Parallel\ScheduleFactory; use Symplify\EasyCodingStandard\Parallel\ValueObject\Bridge; use Symplify\EasyCodingStandard\SniffRunner\ValueObject\Error\CodingStandardError; use Symplify\EasyCodingStandard\Utils\ParametersMerger; @@ -22,8 +24,6 @@ use Symplify\EasyCodingStandard\ValueObject\Error\FileDiff; use Symplify\EasyCodingStandard\ValueObject\Error\SystemError; use Symplify\EasyCodingStandard\ValueObject\Option; -use Symplify\EasyParallel\CpuCoreCountProvider; -use Symplify\EasyParallel\ScheduleFactory; final readonly class EasyCodingStandardApplication { diff --git a/src/Console/Command/WorkerCommand.php b/src/Console/Command/WorkerCommand.php index 31e7dd83872..1f8251d632a 100644 --- a/src/Console/Command/WorkerCommand.php +++ b/src/Console/Command/WorkerCommand.php @@ -14,9 +14,9 @@ use Symfony\Component\Console\Output\OutputInterface; use Symplify\EasyCodingStandard\Configuration\ConfigurationFactory; use Symplify\EasyCodingStandard\MemoryLimitter; +use Symplify\EasyCodingStandard\Parallel\Enum\Action; +use Symplify\EasyCodingStandard\Parallel\Enum\ReactCommand; use Symplify\EasyCodingStandard\Parallel\WorkerRunner; -use Symplify\EasyParallel\Enum\Action; -use Symplify\EasyParallel\Enum\ReactCommand; /** * Inspired at: https://github.com/phpstan/phpstan-src/commit/9124c66dcc55a222e21b1717ba5f60771f7dda92 diff --git a/src/Parallel/Application/ParallelFileProcessor.php b/src/Parallel/Application/ParallelFileProcessor.php index f62eeb6f34a..b4ba40e0969 100644 --- a/src/Parallel/Application/ParallelFileProcessor.php +++ b/src/Parallel/Application/ParallelFileProcessor.php @@ -14,19 +14,19 @@ use Symfony\Component\Console\Input\InputInterface; use Symplify\EasyCodingStandard\Console\Command\CheckCommand; use Symplify\EasyCodingStandard\DependencyInjection\SimpleParameterProvider; +use Symplify\EasyCodingStandard\Parallel\CommandLine\WorkerCommandLineFactory; +use Symplify\EasyCodingStandard\Parallel\Enum\Action; +use Symplify\EasyCodingStandard\Parallel\Enum\Content; +use Symplify\EasyCodingStandard\Parallel\Enum\ReactCommand; +use Symplify\EasyCodingStandard\Parallel\Enum\ReactEvent; use Symplify\EasyCodingStandard\Parallel\ValueObject\Bridge; +use Symplify\EasyCodingStandard\Parallel\ValueObject\ParallelProcess; +use Symplify\EasyCodingStandard\Parallel\ValueObject\ProcessPool; +use Symplify\EasyCodingStandard\Parallel\ValueObject\Schedule; use Symplify\EasyCodingStandard\SniffRunner\ValueObject\Error\CodingStandardError; use Symplify\EasyCodingStandard\ValueObject\Error\FileDiff; use Symplify\EasyCodingStandard\ValueObject\Error\SystemError; use Symplify\EasyCodingStandard\ValueObject\Option; -use Symplify\EasyParallel\CommandLine\WorkerCommandLineFactory; -use Symplify\EasyParallel\Enum\Action; -use Symplify\EasyParallel\Enum\Content; -use Symplify\EasyParallel\Enum\ReactCommand; -use Symplify\EasyParallel\Enum\ReactEvent; -use Symplify\EasyParallel\ValueObject\ParallelProcess; -use Symplify\EasyParallel\ValueObject\ProcessPool; -use Symplify\EasyParallel\ValueObject\Schedule; use Throwable; /** diff --git a/src/Parallel/CommandLine/WorkerCommandLineFactory.php b/src/Parallel/CommandLine/WorkerCommandLineFactory.php new file mode 100644 index 00000000000..afa78e91b74 --- /dev/null +++ b/src/Parallel/CommandLine/WorkerCommandLineFactory.php @@ -0,0 +1,172 @@ +commandFromReflectionFactory = new CommandFromReflectionFactory(); + } + + /** + * @param class-string $mainCommandClass + */ + public function create( + string $baseScript, + string $mainCommandClass, + string $workerCommandName, + string $pathsOptionName, + ?string $projectConfigFile, + InputInterface $input, + string $identifier, + int $port + ): string { + $commandArguments = array_slice($_SERVER['argv'], 1); + $args = array_merge([PHP_BINARY, $baseScript], $commandArguments); + + $mainCommand = $this->commandFromReflectionFactory->create($mainCommandClass); + + if ($mainCommand->getName() === null) { + $errorMessage = sprintf('The command name for "%s" is missing', $mainCommand::class); + throw new ParallelShouldNotHappenException($errorMessage); + } + + $mainCommandName = $mainCommand->getName(); + + $processCommandArray = []; + + foreach ($args as $arg) { + // skip command name + if ($arg === $mainCommandName) { + break; + } + + $processCommandArray[] = escapeshellarg((string) $arg); + } + + $processCommandArray[] = $workerCommandName; + if ($projectConfigFile !== null) { + $processCommandArray[] = '--config'; + $processCommandArray[] = escapeshellarg($projectConfigFile); + } + + $mainCommandOptionNames = $this->getCommandOptionNames($mainCommand); + $processCommandOptions = $this->mirrorCommandOptions($input, $mainCommandOptionNames); + $processCommandArray = array_merge($processCommandArray, $processCommandOptions); + + // for TCP local server + $processCommandArray[] = '--port'; + $processCommandArray[] = $port; + + $processCommandArray[] = '--identifier'; + $processCommandArray[] = escapeshellarg($identifier); + + /** @var string[] $paths */ + $paths = (array) $input->getArgument($pathsOptionName); + foreach ($paths as $path) { + $processCommandArray[] = escapeshellarg($path); + } + + // set json output + $processCommandArray[] = '--output-format'; + $processCommandArray[] = escapeshellarg('json'); + + // explicitly disable colors, breaks json_decode() otherwise + // @see https://github.com/symfony/symfony/issues/1238 + $processCommandArray[] = '--no-ansi'; + + return implode(' ', $processCommandArray); + } + + /** + * @return string[] + */ + private function getCommandOptionNames(Command $command): array + { + $inputDefinition = $command->getDefinition(); + + $optionNames = []; + foreach ($inputDefinition->getOptions() as $inputOption) { + $optionNames[] = $inputOption->getName(); + } + + return $optionNames; + } + + /** + * Keeps all options that are allowed in check command options + * + * @param string[] $mainCommandOptionNames + * @return string[] + */ + private function mirrorCommandOptions(InputInterface $input, array $mainCommandOptionNames): array + { + $processCommandOptions = []; + + foreach ($mainCommandOptionNames as $mainCommandOptionName) { + if ($this->shouldSkipOption($input, $mainCommandOptionName)) { + continue; + } + + /** @var bool|string|null $optionValue */ + $optionValue = $input->getOption($mainCommandOptionName); + + // skip clutter + if ($optionValue === null) { + continue; + } + + if (is_bool($optionValue)) { + if ($optionValue) { + $processCommandOptions[] = self::OPTION_DASHES . $mainCommandOptionName; + } + + continue; + } + + if ($mainCommandOptionName === 'memory-limit') { + // symfony/console does not accept -1 as value without assign + $processCommandOptions[] = '--' . $mainCommandOptionName . '=' . $optionValue; + } else { + $processCommandOptions[] = self::OPTION_DASHES . $mainCommandOptionName; + $processCommandOptions[] = escapeshellarg($optionValue); + } + } + + return $processCommandOptions; + } + + private function shouldSkipOption(InputInterface $input, string $optionName): bool + { + if (! $input->hasOption($optionName)) { + return true; + } + + return in_array($optionName, self::EXCLUDED_OPTION_NAMES, true); + } +} diff --git a/src/Parallel/Contract/SerializableInterface.php b/src/Parallel/Contract/SerializableInterface.php new file mode 100644 index 00000000000..8f7871e0aa1 --- /dev/null +++ b/src/Parallel/Contract/SerializableInterface.php @@ -0,0 +1,18 @@ + $json + */ + public static function decode(array $json): self; +} diff --git a/src/Parallel/CpuCoreCountProvider.php b/src/Parallel/CpuCoreCountProvider.php new file mode 100644 index 00000000000..b1af80c7228 --- /dev/null +++ b/src/Parallel/CpuCoreCountProvider.php @@ -0,0 +1,28 @@ +getCount(); + } catch (NumberOfCpuCoreNotFound) { + return self::DEFAULT_CORE_COUNT; + } + } +} diff --git a/src/Parallel/Enum/Action.php b/src/Parallel/Enum/Action.php new file mode 100644 index 00000000000..f95316b4de2 --- /dev/null +++ b/src/Parallel/Enum/Action.php @@ -0,0 +1,26 @@ + $className + */ + public function create(string $className): Command + { + $commandReflectionClass = new ReflectionClass($className); + + $command = $commandReflectionClass->newInstanceWithoutConstructor(); + $parentClassReflection = $commandReflectionClass->getParentClass(); + + if (! $parentClassReflection instanceof ReflectionClass) { + throw new ParallelShouldNotHappenException(); + } + + $parentConstructorReflectionMethod = $parentClassReflection->getConstructor(); + if (! $parentConstructorReflectionMethod instanceof ReflectionMethod) { + throw new ParallelShouldNotHappenException(); + } + + $parentConstructorReflectionMethod->invoke($command); + + return $command; + } +} diff --git a/src/Parallel/ScheduleFactory.php b/src/Parallel/ScheduleFactory.php new file mode 100644 index 00000000000..9c8d18390d8 --- /dev/null +++ b/src/Parallel/ScheduleFactory.php @@ -0,0 +1,29 @@ + $files + */ + public function create(int $cpuCores, int $jobSize, int $maxNumberOfProcesses, array $files): Schedule + { + $jobs = array_chunk($files, $jobSize); + $numberOfProcesses = min(count($jobs), $cpuCores); + + $numberOfProcesses = min($maxNumberOfProcesses, $numberOfProcesses); + + return new Schedule($numberOfProcesses, $jobs); + } +} diff --git a/src/Parallel/ValueObject/ParallelProcess.php b/src/Parallel/ValueObject/ParallelProcess.php new file mode 100644 index 00000000000..d53399162cd --- /dev/null +++ b/src/Parallel/ValueObject/ParallelProcess.php @@ -0,0 +1,156 @@ +stdErr = $tmp; + $this->process = new Process($this->command, null, null, [ + 2 => $this->stdErr, + // todo is it fine to not have 0 and 1 FD? + ]); + $this->process->start($this->loop); + + $this->onData = $onData; + $this->onError = $onError; + + $this->process->on(ReactEvent::EXIT, function ($exitCode) use ($onExit): void { + if ($this->stdErr === null) { + throw new ParallelShouldNotHappenException(); + } + + $this->cancelTimer(); + + rewind($this->stdErr); + + /** @var string $streamContents */ + $streamContents = stream_get_contents($this->stdErr); + $onExit($exitCode, $streamContents); + + fclose($this->stdErr); + }); + } + + /** + * @param mixed[] $data + */ + public function request(array $data): void + { + $this->cancelTimer(); + $this->encoder->write($data); + $this->timer = $this->loop->addTimer($this->timetoutInSeconds, function (): void { + $onError = $this->onError; + + $errorMessage = sprintf('Child process timed out after %d seconds', $this->timetoutInSeconds); + $onError(new Exception($errorMessage)); + }); + } + + public function quit(): void + { + $this->cancelTimer(); + if (! $this->process->isRunning()) { + return; + } + + foreach ($this->process->pipes as $pipe) { + $pipe->close(); + } + + $this->encoder->end(); + } + + public function bindConnection(Decoder $decoder, Encoder $encoder): void + { + $decoder->on(ReactEvent::DATA, function (array $json): void { + $this->cancelTimer(); + if ($json[ReactCommand::ACTION] !== Action::RESULT) { + return; + } + + $onData = $this->onData; + $onData($json[Content::RESULT]); + }); + $this->encoder = $encoder; + + $decoder->on(ReactEvent::ERROR, function (Throwable $throwable): void { + $onError = $this->onError; + $onError($throwable); + }); + + $encoder->on(ReactEvent::ERROR, function (Throwable $throwable): void { + $onError = $this->onError; + $onError($throwable); + }); + } + + private function cancelTimer(): void + { + if (! $this->timer instanceof TimerInterface) { + return; + } + + $this->loop->cancelTimer($this->timer); + $this->timer = null; + } +} diff --git a/src/Parallel/ValueObject/ProcessPool.php b/src/Parallel/ValueObject/ProcessPool.php new file mode 100644 index 00000000000..efb12fa8c11 --- /dev/null +++ b/src/Parallel/ValueObject/ProcessPool.php @@ -0,0 +1,69 @@ + + */ + private array $processes = []; + + public function __construct( + private readonly TcpServer $tcpServer + ) { + } + + public function getProcess(string $identifier): ParallelProcess + { + if (! \array_key_exists($identifier, $this->processes)) { + throw new ParallelShouldNotHappenException(\sprintf('Process "%s" not found.', $identifier)); + } + + return $this->processes[$identifier]; + } + + public function attachProcess(string $identifier, ParallelProcess $parallelProcess): void + { + $this->processes[$identifier] = $parallelProcess; + } + + public function tryQuitProcess(string $identifier): void + { + if (! \array_key_exists($identifier, $this->processes)) { + return; + } + + $this->quitProcess($identifier); + } + + public function quitProcess(string $identifier): void + { + $parallelProcess = $this->getProcess($identifier); + $parallelProcess->quit(); + + unset($this->processes[$identifier]); + if ($this->processes !== []) { + return; + } + + $this->tcpServer->close(); + } + + public function quitAll(): void + { + foreach (\array_keys($this->processes) as $identifier) { + $this->quitProcess($identifier); + } + } +} diff --git a/src/Parallel/ValueObject/Schedule.php b/src/Parallel/ValueObject/Schedule.php new file mode 100644 index 00000000000..2da2cbf1f9c --- /dev/null +++ b/src/Parallel/ValueObject/Schedule.php @@ -0,0 +1,36 @@ +> $jobs + */ + public function __construct( + private readonly int $numberOfProcesses, + private readonly array $jobs + ) { + } + + public function getNumberOfProcesses(): int + { + return $this->numberOfProcesses; + } + + /** + * @return array> + */ + public function getJobs(): array + { + return $this->jobs; + } +} diff --git a/src/Parallel/WorkerRunner.php b/src/Parallel/WorkerRunner.php index 4991517c4a0..e4c71a20fe1 100644 --- a/src/Parallel/WorkerRunner.php +++ b/src/Parallel/WorkerRunner.php @@ -7,14 +7,14 @@ use Clue\React\NDJson\Decoder; use Clue\React\NDJson\Encoder; use Symplify\EasyCodingStandard\Application\SingleFileProcessor; +use Symplify\EasyCodingStandard\Parallel\Enum\Action; +use Symplify\EasyCodingStandard\Parallel\Enum\Content; +use Symplify\EasyCodingStandard\Parallel\Enum\ReactCommand; +use Symplify\EasyCodingStandard\Parallel\Enum\ReactEvent; use Symplify\EasyCodingStandard\Parallel\ValueObject\Bridge; use Symplify\EasyCodingStandard\Utils\ParametersMerger; use Symplify\EasyCodingStandard\ValueObject\Configuration; use Symplify\EasyCodingStandard\ValueObject\Error\SystemError; -use Symplify\EasyParallel\Enum\Action; -use Symplify\EasyParallel\Enum\Content; -use Symplify\EasyParallel\Enum\ReactCommand; -use Symplify\EasyParallel\Enum\ReactEvent; use Throwable; final readonly class WorkerRunner diff --git a/src/SniffRunner/ValueObject/Error/CodingStandardError.php b/src/SniffRunner/ValueObject/Error/CodingStandardError.php index 82f356b959a..c17aa4f1e08 100644 --- a/src/SniffRunner/ValueObject/Error/CodingStandardError.php +++ b/src/SniffRunner/ValueObject/Error/CodingStandardError.php @@ -4,8 +4,8 @@ namespace Symplify\EasyCodingStandard\SniffRunner\ValueObject\Error; +use Symplify\EasyCodingStandard\Parallel\Contract\SerializableInterface; use Symplify\EasyCodingStandard\Parallel\ValueObject\Name; -use Symplify\EasyParallel\Contract\SerializableInterface; final readonly class CodingStandardError implements SerializableInterface { diff --git a/src/ValueObject/Error/FileDiff.php b/src/ValueObject/Error/FileDiff.php index e962384e0e6..dc72810fff2 100644 --- a/src/ValueObject/Error/FileDiff.php +++ b/src/ValueObject/Error/FileDiff.php @@ -6,8 +6,8 @@ use PHP_CodeSniffer\Sniffs\Sniff; use PhpCsFixer\Fixer\FixerInterface; +use Symplify\EasyCodingStandard\Parallel\Contract\SerializableInterface; use Symplify\EasyCodingStandard\Parallel\ValueObject\Name; -use Symplify\EasyParallel\Contract\SerializableInterface; final class FileDiff implements SerializableInterface { diff --git a/src/ValueObject/Error/SystemError.php b/src/ValueObject/Error/SystemError.php index ac756810bd7..122cec38d4c 100644 --- a/src/ValueObject/Error/SystemError.php +++ b/src/ValueObject/Error/SystemError.php @@ -4,8 +4,8 @@ namespace Symplify\EasyCodingStandard\ValueObject\Error; +use Symplify\EasyCodingStandard\Parallel\Contract\SerializableInterface; use Symplify\EasyCodingStandard\Parallel\ValueObject\Name; -use Symplify\EasyParallel\Contract\SerializableInterface; final readonly class SystemError implements SerializableInterface { From 7489a7e26bf5d5b1e3149533ea8bc2e62ba3dca1 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Wed, 10 Jun 2026 10:08:37 +0100 Subject: [PATCH 2/2] update hcangelog --- CHANGELOG.md | 19 ++++++---------- composer.json | 6 ++--- phpstan.neon | 2 +- .../CommandLine/WorkerCommandLineFactory.php | 7 ++---- src/Parallel/CpuCoreCountProvider.php | 5 +---- src/Parallel/Enum/Action.php | 17 ++++---------- src/Parallel/Enum/Content.php | 12 +++------- src/Parallel/Enum/ReactCommand.php | 12 +++------- src/Parallel/Enum/ReactEvent.php | 22 +++++-------------- src/Parallel/ScheduleFactory.php | 2 +- src/Parallel/ValueObject/ParallelProcess.php | 9 ++++---- 11 files changed, 35 insertions(+), 78 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b91cf7eedb0..0e6fc198785 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -76,26 +76,21 @@ guidance away from dangerous sets. ->withDocblockLevel(1); ``` - Each level applies the same number of rules to your code, safest first: + Example from the array set (`tests/Set/Array/Fixture/nested_array.php.inc`): ```diff - -$values = array(1, 2, 3,); - +$values = [1, 2, 3]; + -$test = ['key' => ['keyA' => 'valueA']]; + +$test = [ + + 'key' => [ + + 'keyA' => 'valueA', + + ], + +]; ``` ### Changed - Reconfigure `OrderedImportsFixer` to sort imports by `class`, `function`, then `const`, avoiding a mixed import order (#321) - ```diff - use App\Service\SomeService; - -use const PHP_EOL; - use App\Service\AnotherService; - -use function strlen; - +use function strlen; - +use const PHP_EOL; - ``` - ```php // config/set/clean-code.php use PhpCsFixer\Fixer\Import\OrderedImportsFixer; diff --git a/composer.json b/composer.json index b15321799fe..b8bfb05b2a1 100644 --- a/composer.json +++ b/composer.json @@ -34,16 +34,16 @@ "require-dev": { "phpstan/extension-installer": "^1.4.3", "phpstan/phpstan": "^2.2", - "phpstan/phpstan-phpunit": "^2.0.16", + "phpstan/phpstan-phpunit": "^2.0", "phpstan/phpstan-webmozart-assert": "^2.0", - "phpunit/phpunit": "^13.0", + "phpunit/phpunit": "^13.2", "rector/jack": "^1.0", "rector/rector": "^2.4", "rector/type-perfect": "^2.1", "symplify/phpstan-rules": "^14.11", "symplify/vendor-patches": "^11.5", "tomasvotruba/class-leak": "^2.1.6", - "tomasvotruba/type-coverage": "^2.1", + "tomasvotruba/type-coverage": "^2.2", "tomasvotruba/unused-public": "^2.2", "tracy/tracy": "^2.12" }, diff --git a/phpstan.neon b/phpstan.neon index db893ee7f90..bbf54ce7db5 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -42,7 +42,7 @@ parameters: # set above - path: src/Parallel/Application/ParallelFileProcessor.php - message: '#Cannot call method (.*?)\(\) on Symplify\\EasyParallel\\ValueObject\\ProcessPool\|null#' + message: '#Cannot call method (.*?)\(\) on Symplify\\EasyCodingStandard\\Parallel\\ValueObject\\ProcessPool\|null#' - '#Method Symplify\\EasyCodingStandard\\Console\\Command\\ListCheckersCommand\:\:getObjectClasses\(\) should return (.*?)#' diff --git a/src/Parallel/CommandLine/WorkerCommandLineFactory.php b/src/Parallel/CommandLine/WorkerCommandLineFactory.php index afa78e91b74..9cb05844a63 100644 --- a/src/Parallel/CommandLine/WorkerCommandLineFactory.php +++ b/src/Parallel/CommandLine/WorkerCommandLineFactory.php @@ -14,17 +14,14 @@ */ final class WorkerCommandLineFactory { - /** - * @var string - */ - private const OPTION_DASHES = '--'; + private const string OPTION_DASHES = '--'; /** * These options are not relevant for nested worker command line. * * @var string[] */ - private const EXCLUDED_OPTION_NAMES = ['output-format']; + private const array EXCLUDED_OPTION_NAMES = ['output-format']; private readonly CommandFromReflectionFactory $commandFromReflectionFactory; diff --git a/src/Parallel/CpuCoreCountProvider.php b/src/Parallel/CpuCoreCountProvider.php index b1af80c7228..e9f7ae73a7d 100644 --- a/src/Parallel/CpuCoreCountProvider.php +++ b/src/Parallel/CpuCoreCountProvider.php @@ -12,10 +12,7 @@ */ final class CpuCoreCountProvider { - /** - * @var int - */ - private const DEFAULT_CORE_COUNT = 2; + private const int DEFAULT_CORE_COUNT = 2; public function provide(): int { diff --git a/src/Parallel/Enum/Action.php b/src/Parallel/Enum/Action.php index f95316b4de2..943c7ab99a7 100644 --- a/src/Parallel/Enum/Action.php +++ b/src/Parallel/Enum/Action.php @@ -5,22 +5,13 @@ namespace Symplify\EasyCodingStandard\Parallel\Enum; /** - * @api + * @enum */ final class Action { - /** - * @var string - */ - public const HELLO = 'hello'; + public const string HELLO = 'hello'; - /** - * @var string - */ - public const MAIN = 'main'; + public const string MAIN = 'main'; - /** - * @var string - */ - public const RESULT = 'result'; + public const string RESULT = 'result'; } diff --git a/src/Parallel/Enum/Content.php b/src/Parallel/Enum/Content.php index 131cbb64b67..30c9a97812b 100644 --- a/src/Parallel/Enum/Content.php +++ b/src/Parallel/Enum/Content.php @@ -5,17 +5,11 @@ namespace Symplify\EasyCodingStandard\Parallel\Enum; /** - * @api + * @enum */ final class Content { - /** - * @var string - */ - public const RESULT = 'result'; + public const string RESULT = 'result'; - /** - * @var string - */ - public const FILES = 'files'; + public const string FILES = 'files'; } diff --git a/src/Parallel/Enum/ReactCommand.php b/src/Parallel/Enum/ReactCommand.php index 7d3b7f3b618..e4d897bb34c 100644 --- a/src/Parallel/Enum/ReactCommand.php +++ b/src/Parallel/Enum/ReactCommand.php @@ -5,17 +5,11 @@ namespace Symplify\EasyCodingStandard\Parallel\Enum; /** - * @api + * @enum */ final class ReactCommand { - /** - * @var string - */ - public const ACTION = 'action'; + public const string ACTION = 'action'; - /** - * @var string - */ - public const IDENTIFIER = 'identifier'; + public const string IDENTIFIER = 'identifier'; } diff --git a/src/Parallel/Enum/ReactEvent.php b/src/Parallel/Enum/ReactEvent.php index 69409d1a65e..5ccd759cb95 100644 --- a/src/Parallel/Enum/ReactEvent.php +++ b/src/Parallel/Enum/ReactEvent.php @@ -5,27 +5,15 @@ namespace Symplify\EasyCodingStandard\Parallel\Enum; /** - * @api + * @enum */ final class ReactEvent { - /** - * @var string - */ - public const EXIT = 'exit'; + public const string EXIT = 'exit'; - /** - * @var string - */ - public const DATA = 'data'; + public const string DATA = 'data'; - /** - * @var string - */ - public const ERROR = 'error'; + public const string ERROR = 'error'; - /** - * @var string - */ - public const CONNECTION = 'connection'; + public const string CONNECTION = 'connection'; } diff --git a/src/Parallel/ScheduleFactory.php b/src/Parallel/ScheduleFactory.php index 9c8d18390d8..14be1fb3318 100644 --- a/src/Parallel/ScheduleFactory.php +++ b/src/Parallel/ScheduleFactory.php @@ -19,7 +19,7 @@ final class ScheduleFactory */ public function create(int $cpuCores, int $jobSize, int $maxNumberOfProcesses, array $files): Schedule { - $jobs = array_chunk($files, $jobSize); + $jobs = array_chunk($files, max(1, $jobSize)); $numberOfProcesses = min(count($jobs), $cpuCores); $numberOfProcesses = min($maxNumberOfProcesses, $numberOfProcesses); diff --git a/src/Parallel/ValueObject/ParallelProcess.php b/src/Parallel/ValueObject/ParallelProcess.php index d53399162cd..e9cdaaadf37 100644 --- a/src/Parallel/ValueObject/ParallelProcess.php +++ b/src/Parallel/ValueObject/ParallelProcess.php @@ -75,19 +75,20 @@ public function start(callable $onData, callable $onError, callable $onExit): vo $this->onError = $onError; $this->process->on(ReactEvent::EXIT, function ($exitCode) use ($onExit): void { - if ($this->stdErr === null) { + $stdErr = $this->stdErr; + if ($stdErr === null) { throw new ParallelShouldNotHappenException(); } $this->cancelTimer(); - rewind($this->stdErr); + rewind($stdErr); /** @var string $streamContents */ - $streamContents = stream_get_contents($this->stdErr); + $streamContents = stream_get_contents($stdErr); $onExit($exitCode, $streamContents); - fclose($this->stdErr); + fclose($stdErr); }); }