Skip to content

Commit

Permalink
Merge pull request #13 from TheLevti/feature/improve-static-typing
Browse files Browse the repository at this point in the history
#12: Comply with phpstan max level
  • Loading branch information
TheLevti authored Mar 28, 2020
2 parents c4fe689 + 4d51222 commit 0fd6096
Show file tree
Hide file tree
Showing 38 changed files with 596 additions and 341 deletions.
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@
/phpstan.neon.dist export-ignore
/phpunit.xml.dist export-ignore
/tests export-ignore
/phan export-ignore
7 changes: 5 additions & 2 deletions .phan/config.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
// (See `backward_compatibility_checks` for additional options)
// Automatically inferred from composer.json requirement for "php" of
// "^7.2.0"
'target_php_version' => '7.4',
'target_php_version' => '7.2',

// If enabled, missing properties will be created when
// they are first seen. If false, we'll report an
Expand Down Expand Up @@ -292,7 +292,10 @@

// Add any issue types (such as `'PhanUndeclaredMethod'`)
// to this black-list to inhibit them from being reported.
'suppress_issue_types' => [],
'suppress_issue_types' => [
'PhanUnreferencedPublicMethod',
'PhanUnreferencedClass',
],

// A regular expression to match files to be excluded
// from parsing and analysis and will not be read at all.
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Changed

- #12: Fix all phpstan errors and general typing improvements.

## [4.0.0] - 2020-02-09

### Changed
Expand Down
8 changes: 5 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@
"ext-posix": "*",
"ext-shmop": "*",
"friendsofphp/php-cs-fixer": "^2.16",
"phan/phan": "^2.4",
"phpstan/phpstan": "^0.12.4",
"phan/phan": "^2.6",
"phpstan/phpstan": "^0.12.18",
"phpunit/phpunit": "^8.5",
"squizlabs/php_codesniffer": "^3.5",
"symfony/var-dumper": "^5.0"
Expand Down Expand Up @@ -74,7 +74,8 @@
"/php_cs.dist",
"/phpstan.neon.dist",
"/phpunit.xml.dist",
"/tests"
"/tests",
"/phan"
]
},
"config": {
Expand All @@ -91,6 +92,7 @@
"cs": "vendor/bin/phpcs --standard=PSR12 src/ tests/",
"csf": "vendor/bin/php-cs-fixer fix",
"static": "vendor/bin/phpstan analyse",
"phan": "vendor/bin/phan --no-progress-bar",
"test": "vendor/bin/phpunit",
"coverage": "vendor/bin/phpunit --coverage-html coverage"
}
Expand Down
4 changes: 2 additions & 2 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
parameters:
level: 5
level: max
paths:
- src
- tests
inferPrivatePropertyTypeFromConstructor: true
treatPhpDocTypesAsCertain: false
74 changes: 54 additions & 20 deletions src/Batch/BatchJob.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,87 +15,121 @@

use TheLevti\phpfork\Batch\Strategy\ChunkStrategy;
use TheLevti\phpfork\Batch\Strategy\StrategyInterface;
use TheLevti\phpfork\Exception\UnexpectedTypeException;
use TheLevti\phpfork\Fork;
use TheLevti\phpfork\ProcessManager;

class BatchJob
{
private $manager;
/**
* @var \TheLevti\phpfork\ProcessManager $processManager
*/
protected $processManager;

/**
* @var mixed $data
*/
private $data;

/**
* @var \TheLevti\phpfork\Batch\Strategy\StrategyInterface $strategy
*/
private $strategy;

/**
* @var string $name
*/
private $name;

/**
* @var callable $callback
*/
private $callback;

public function __construct(ProcessManager $manager, $data = null, StrategyInterface $strategy = null)
/**
* @param \TheLevti\phpfork\ProcessManager $processManager
* @param mixed|null $data
* @param \TheLevti\phpfork\Batch\Strategy\StrategyInterface|null $strategy
* @return void
*/
public function __construct(ProcessManager $processManager, $data = null, StrategyInterface $strategy = null)
{
$this->manager = $manager;
$this->processManager = $processManager;
$this->data = $data;
$this->strategy = $strategy ?: new ChunkStrategy();
$this->name = '<anonymous>';
}

public function setName($name)
public function setName(string $name): self
{
$this->name = $name;

return $this;
}

public function setStrategy(StrategyInterface $strategy)
public function setStrategy(StrategyInterface $strategy): self
{
$this->strategy = $strategy;

return $this;
}

public function setData($data)
/**
* @param mixed $data
* @return \TheLevti\phpfork\Batch\BatchJob
*/
public function setData($data): self
{
$this->data = $data;

return $this;
}

public function setCallback($callback)
public function setCallback(callable $callback): self
{
if (!is_callable($callback)) {
throw new UnexpectedTypeException($callback, 'callable');
}

$this->callback = $callback;

return $this;
}

public function execute($callback = null)
public function execute(?callable $callback = null): Fork
{
if (null !== $callback) {
$this->setCallback($callback);
}

return $this->manager->fork($this)->setName($this->name . ' batch');
return $this->processManager->fork($this)->setName($this->name . ' batch');
}

/**
* Runs in a child process.
*
* @see execute()
* @see \TheLevti\phpfork\Batch\BatchJob::execute()
*
* @return array<mixed> Result from the batch job.
*/
public function __invoke()
public function __invoke(): array
{
/** @var array<int,\TheLevti\phpfork\Fork> $forks */
$forks = [];
foreach ($this->strategy->createBatches($this->data) as $index => $batch) {
$forks[] = $this->manager
$forks[] = $this->processManager
->fork($this->strategy->createRunner($batch, $this->callback))
->setName(sprintf('%s batch #%d', $this->name, $index))
;
}

// block until all forks have exited
$this->manager->wait();
$this->processManager->wait();

/** @var array<int,mixed> $results */
$results = [];
foreach ($forks as $fork) {
$results = array_merge($results, $fork->getResult());
$batchResult = $fork->getResult();

if (is_array($batchResult)) {
$results = array_merge($results, $batchResult);
} else {
$results[] = $batchResult;
}
}

return $results;
Expand Down
39 changes: 27 additions & 12 deletions src/Batch/BatchRunner.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,19 @@

namespace TheLevti\phpfork\Batch;

use TheLevti\phpfork\Exception\UnexpectedTypeException;
use TheLevti\phpfork\SharedMemory;
use UnexpectedValueException;

class BatchRunner
{
/**
* @var array<int|string,mixed>|callable $batch
*/
private $batch;

/**
* @var callable $callback
*/
private $callback;

/**
Expand All @@ -28,28 +35,36 @@ class BatchRunner
*
* function($item, $index, $batch, $sharedMem)
*
* @param mixed $batch The batch
* @param callable $callback The callback
* @param array<int|string,mixed>|callable $batch
* @param callable $callback
*/
public function __construct($batch, $callback)
public function __construct($batch, callable $callback)
{
if (!is_callable($callback)) {
throw new UnexpectedTypeException($callback, 'callable');
}

$this->batch = $batch;
$this->callback = $callback;
}

public function __invoke(SharedMemory $shm)
/**
* @param \TheLevti\phpfork\SharedMemory $shm
* @throws \UnexpectedValueException
* @return array<int|string,mixed>
*/
public function __invoke(SharedMemory $shm): array
{
// lazy batch...
if ($this->batch instanceof \Closure) {
$this->batch = call_user_func($this->batch);
if (is_callable($this->batch)) {
/** @var array<mixed> $batchArray */
$batchArray = call_user_func($this->batch);
} elseif (is_array($this->batch)) {
/** @var array<mixed> $batchArray */
$batchArray = $this->batch;
} else {
throw new UnexpectedValueException('Batch is not an array nor a callable.');
}

/** @var array<int|string,mixed> $results */
$results = [];
foreach ($this->batch as $index => $item) {
foreach ($batchArray as $index => $item) {
$results[$index] = call_user_func($this->callback, $item, $index, $this->batch, $shm);
}

Expand Down
2 changes: 1 addition & 1 deletion src/Batch/Strategy/AbstractStrategy.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

abstract class AbstractStrategy implements StrategyInterface
{
public function createRunner($batch, $callback)
public function createRunner($batch, $callback): callable
{
return new BatchRunner($batch, $callback);
}
Expand Down
13 changes: 5 additions & 8 deletions src/Batch/Strategy/CallbackStrategy.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,19 @@

namespace TheLevti\phpfork\Batch\Strategy;

use TheLevti\phpfork\Exception\UnexpectedTypeException;

class CallbackStrategy extends AbstractStrategy
{
/**
* @var callable $callback
*/
private $callback;

public function __construct($callback)
public function __construct(callable $callback)
{
if (!is_callable($callback)) {
throw new UnexpectedTypeException($callback, 'callable');
}

$this->callback = $callback;
}

public function createBatches($data)
public function createBatches($data): iterable
{
return call_user_func($this->callback, $data);
}
Expand Down
11 changes: 9 additions & 2 deletions src/Batch/Strategy/ChunkStrategy.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,23 @@
*/
class ChunkStrategy extends AbstractStrategy
{
/**
* @var int $forks
*/
private $forks;

/**
* @var bool $preserveKeys
*/
private $preserveKeys;

public function __construct($forks = 3, $preserveKeys = false)
public function __construct(int $forks = 3, bool $preserveKeys = false)
{
$this->forks = $forks;
$this->preserveKeys = $preserveKeys;
}

public function createBatches($data)
public function createBatches($data): iterable
{
if (!is_array($data) && !$data instanceof \Traversable) {
throw new UnexpectedTypeException($data, 'array or Traversable');
Expand Down
8 changes: 4 additions & 4 deletions src/Batch/Strategy/StrategyInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,20 @@ interface StrategyInterface
*
* @param mixed $data The raw batch data
*
* @return array|\Traversable An iterator of batches
* @return iterable<int|string,mixed> An iterator of batches
*/
public function createBatches($data);
public function createBatches($data): iterable;

/**
* Creates a batch runner for the supplied list.
*
* A batch runner is a callable that is passed to ProcessManager::fork()
* that should run each item in the supplied batch through a callable.
*
* @param mixed $batch A batch of items
* @param array<int|string,mixed>|callable $batch A batch of items
* @param callable $callback The batch callback
*
* @return callable A callable for the child process
*/
public function createRunner($batch, $callback);
public function createRunner($batch, $callback): callable;
}
Loading

0 comments on commit 0fd6096

Please sign in to comment.