Skip to content

Commit

Permalink
✨ Add generics templating
Browse files Browse the repository at this point in the history
  • Loading branch information
matyo91 committed Sep 10, 2023
1 parent da6d3f8 commit 263359d
Show file tree
Hide file tree
Showing 32 changed files with 442 additions and 41 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## v1.1.x

- Add generics templating from
- https://gpb.moe/doc/slides/Gestion_Erreur_Toutes_Ses_Couleurs_FR.pdf
- https://slides.com/kpn13/les-generiques-en-php
- Add Flow\Driver\RevoltDriver
- Add more quality tools from https://github.com/IngeniozIT/php-skeleton

Expand Down
12 changes: 12 additions & 0 deletions examples/Data.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace Flow\Examples;

class Data
{
public function __construct(public int $id, public ?int $number)
{
}
}
42 changes: 25 additions & 17 deletions examples/flow.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
use Flow\Driver\ReactDriver;
use Flow\Driver\RevoltDriver;
use Flow\Driver\SwooleDriver;
use Flow\Examples\Data;
use Flow\ExceptionInterface;
use Flow\Flow\Flow;
use Flow\Ip;
use Flow\IpStrategy\MaxIpStrategy;
Expand All @@ -22,54 +24,60 @@
};
printf("Use %s\n", $driver::class);

$job1 = static function (object $data) use ($driver): void {
printf("*. #%d - Job 1 : Calculating %d + %d\n", $data['id'], $data['number'], $data['number']);
$job1 = static function (Data $data) use ($driver): void {
printf("*. #%d - Job 1 : Calculating %d + %d\n", $data->id, $data->number, $data->number);

// simulating calculating some "light" operation from 0.1 to 1 seconds
$delay = random_int(1, 10) / 10;
$driver->delay($delay);
$result = $data['number'];
$result = $data->number;
$result += $result;

// simulating 1 chance on 5 to produce an exception from the "light" operation
if (1 === random_int(1, 5)) {
throw new Error('Failure when processing "Job1"');
}

printf("*. #%d - Job 1 : Result for %d + %d = %d and took %.01f seconds\n", $data['id'], $data['number'], $data['number'], $result, $delay);
printf("*. #%d - Job 1 : Result for %d + %d = %d and took %.01f seconds\n", $data->id, $data->number, $data->number, $result, $delay);

$data['number'] = $result;
$data->number = $result;
};

$job2 = static function (object $data) use ($driver): void {
printf(".* #%d - Job 2 : Calculating %d * %d\n", $data['id'], $data['number'], $data['number']);
$job2 = static function (Data $data) use ($driver): void {
printf(".* #%d - Job 2 : Calculating %d * %d\n", $data->id, $data->number, $data->number);

// simulating calculating some "heavy" operation from from 1 to 3 seconds
$delay = random_int(1, 3);
$driver->delay($delay);
$result = $data['number'];
$result = $data->number;
$result *= $result;

// simulating 1 chance on 5 to produce an exception from the "heavy" operation
if (1 === random_int(1, 5)) {
throw new Error('Failure when processing "Job2"');
}

printf(".* #%d - Job 2 : Result for %d * %d = %d and took %.01f seconds\n", $data['id'], $data['number'], $data['number'], $result, $delay);
printf(".* #%d - Job 2 : Result for %d * %d = %d and took %.01f seconds\n", $data->id, $data->number, $data->number, $result, $delay);

$data['number'] = $result;
$data->number = $result;
};

$errorJob1 = static function (object $data, Throwable $exception): void {
printf("*. #%d - Error Job : Exception %s\n", $data['id'], $exception->getMessage());
/**
* @param Ip<Data> $ip
*/
$errorJob1 = static function (Ip $ip, ExceptionInterface $exception): void {
printf("*. #%d - Error Job : Exception %s\n", $ip->data->id, $exception->getMessage());

$data['number'] = null;
$ip->data->number = null;
};

$errorJob2 = static function (object $data, Throwable $exception): void {
printf(".* #%d - Error Job : Exception %s\n", $data['id'], $exception->getMessage());
/**
* @param Ip<Data> $ip
*/
$errorJob2 = static function (Ip $ip, ExceptionInterface $exception): void {
printf(".* #%d - Error Job : Exception %s\n", $ip->data->id, $exception->getMessage());

$data['number'] = null;
$ip->data->number = null;
};

$flow = (new Flow($job1, $errorJob1, new MaxIpStrategy(2), $driver))
Expand All @@ -79,6 +87,6 @@
$ipPool = new SplObjectStorage();

for ($i = 1; $i <= 5; $i++) {
$ip = new Ip(new ArrayObject(['id' => $i, 'number' => $i]));
$ip = new Ip(new Data($i, $i));
$flow($ip, static fn ($ip) => $ipPool->offsetUnset($ip));
}
109 changes: 109 additions & 0 deletions examples/generic-errors.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<?php

declare(strict_types=1);

require __DIR__ . '/../vendor/autoload.php';

// https://gpb.moe/doc/slides/Gestion_Erreur_Toutes_Ses_Couleurs_FR.pdf
// https://PHPStan.dev/r/dd8e8f59fe

/**
* #template T1
* #template E1.
*/
class Wrapper
{
/**
* #param T1 $value
* #param E1 $err.
*/
public function __construct(
public mixed $value,
public mixed $err,
public bool $isErr = false,
) {
}

/**
* #template T2
* #template E2.
*
* #param callable(T1): Wrapper<T2, E2> $f
*
* #return Wrapper<T2, E1|E2>
*/
public function bind(callable $f): self
{
if ($this->isErr) {
// #var Wrapper<T2,E1> Shut up PHPStan
return $this;
}

return $f($this->value);
}
}

enum OpenFileErrors
{
case FileDoesNotExist;
case AccessDenied;
case IsDirectory;
}

class File
{
}

enum GetContentErrors
{
case E1;
case E2;
}

enum ParseContentErrors
{
case E1;
case E2;
}

class UnparsedOutput
{
}
class ParsedOutput
{
}

/** #return Wrapper<File, OpenFileErrors> */
function open_file(string $path): Wrapper
{
return new Wrapper(new File(), OpenFileErrors::FileDoesNotExist);
}

/** #return Wrapper<UnparsedOutput, GetContentErrors> */
function get_content_file(File $f): Wrapper
{
return new Wrapper(new UnparsedOutput(), GetContentErrors::E1);
}
/** #return Wrapper<ParsedOutput, ParseContentErrors> */
function parse_content(UnparsedOutput $f): Wrapper
{
return new Wrapper(new ParsedOutput(), ParseContentErrors::E1);
}

$data = open_file('')
->bind(get_content_file(...))
->bind(parse_content(...))
;
$result = match ($data->isErr) {
true => match ($data->err) {
OpenFileErrors::FileDoesNotExist => 1,
OpenFileErrors::AccessDenied => 2,
OpenFileErrors::IsDirectory => 3,
GetContentErrors::E1 => 4,
GetContentErrors::E2 => 5,
ParseContentErrors::E1 => 6,
ParseContentErrors::E2 => 7,
default => 8, // added Shut up PHPStan
},
false => $data->value,
};
6 changes: 6 additions & 0 deletions src/Driver/AmpDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@
use function Amp\delay;
use function function_exists;

/**
* @template TArgs
* @template TReturn
*
* @implements DriverInterface<TArgs,TReturn>
*/
class AmpDriver implements DriverInterface
{
public function __construct()
Expand Down
6 changes: 6 additions & 0 deletions src/Driver/FiberDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@
use Flow\Exception\RuntimeException;
use Throwable;

/**
* @template TArgs
* @template TReturn
*
* @implements DriverInterface<TArgs,TReturn>
*/
class FiberDriver implements DriverInterface
{
/**
Expand Down
6 changes: 6 additions & 0 deletions src/Driver/ReactDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@
use function React\Async\async;
use function React\Async\delay;

/**
* @template TArgs
* @template TReturn
*
* @implements DriverInterface<TArgs,TReturn>
*/
class ReactDriver implements DriverInterface
{
private LoopInterface $eventLoop;
Expand Down
6 changes: 6 additions & 0 deletions src/Driver/RevoltDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@
use RuntimeException as NativeRuntimeException;
use Throwable;

/**
* @template TArgs
* @template TReturn
*
* @implements DriverInterface<TArgs,TReturn>
*/
class RevoltDriver implements DriverInterface
{
private int $counter = 0;
Expand Down
6 changes: 6 additions & 0 deletions src/Driver/SwooleDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@

use function extension_loaded;

/**
* @template TArgs
* @template TReturn
*
* @implements DriverInterface<TArgs,TReturn>
*/
class SwooleDriver implements DriverInterface
{
public function __construct()
Expand Down
13 changes: 10 additions & 3 deletions src/DriverInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,26 @@

use Closure;

/**
* @template TArgs TArgs is supposed to be list of generic templating arguments https://github.com/phpstan/phpstan/issues/6873
* @template TReturn
*/
interface DriverInterface
{
/**
* @param Closure $onResolve called on resolved and first argument is $callback return or Flow\Exception on Exception
* #return Closure(TArgs): void when called this start async $callback.
*
* @return Closure when called, this start async $callback
* @param Closure(TArgs): TReturn $callback
* @param null|Closure(ExceptionInterface|TReturn): void $onResolve
*/
public function async(Closure $callback, Closure $onResolve = null): Closure;

public function delay(float $seconds): void;

/**
* @return Closure when called, this cleanup tick interval
* @param Closure(): void $callback
*
* @return Closure(): void when called, this cleanup tick interval
*/
public function tick(int $interval, Closure $callback): Closure;
}
1 change: 1 addition & 0 deletions src/Exception/RuntimeException.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Flow\Exception;

use Flow\ExceptionInterface;
use RuntimeException as NativeRuntimeException;

class RuntimeException extends NativeRuntimeException implements ExceptionInterface
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

declare(strict_types=1);

namespace Flow\Exception;
namespace Flow;

use Throwable;

Expand Down
Loading

0 comments on commit 263359d

Please sign in to comment.