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 8, 2023
1 parent da6d3f8 commit c210b1f
Show file tree
Hide file tree
Showing 9 changed files with 141 additions and 6 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
108 changes: 108 additions & 0 deletions examples/generic-errors.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
<?php

declare(strict_types=1);

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

// https://gpb.moe/doc/slides/Gestion_Erreur_Toutes_Ses_Couleurs_FR.pdf
// https://psalm.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($f): self
{
if ($this->isErr) {
// @var Wrapper<T2, E1> Shut up Psalm
return $this;
}

return $f($this->value);

Check failure on line 42 in examples/generic-errors.php

View workflow job for this annotation

GitHub Actions / Execute PHPStan analysis (8.2)

Method Wrapper::bind() should return Wrapper<T2, E1|E2> but returns Wrapper<T2, E2>.
}
}

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,
},
false => $data->value,
};
5 changes: 4 additions & 1 deletion src/DriverInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@

use Closure;

/**
* @template T of object
*/
interface DriverInterface
{
/**
* @param Closure $onResolve called on resolved and first argument is $callback return or Flow\Exception on Exception
* @param callable(ExceptionInterface|?T): void
*
* @return Closure when called, this start async $callback
*/
Expand Down
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
6 changes: 3 additions & 3 deletions src/Flow/Flow.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use Closure;
use Flow\Driver\ReactDriver;
use Flow\DriverInterface;
use Flow\Exception\RuntimeException;
use Flow\ExceptionInterface;
use Flow\FlowInterface;
use Flow\Ip;
use Flow\IpStrategy\LinearIpStrategy;
Expand Down Expand Up @@ -88,12 +88,12 @@ private function nextIpJob(): void
foreach ($this->jobs as $i => $job) {
$this->driver->async($job, function (mixed $value) use ($ip, &$count, $i, $callback) {
$count--;
if ($count === 0 || $value instanceof RuntimeException) {
if ($count === 0 || $value instanceof ExceptionInterface) {
$count = 0;
$this->ipStrategy->done($ip);
$this->nextIpJob();

if ($value instanceof RuntimeException) {
if ($value instanceof ExceptionInterface) {
if (isset($this->errorJobs[$i])) {
$this->errorJobs[$i]($ip->data, $value->getPrevious());
} else {
Expand Down
14 changes: 14 additions & 0 deletions src/FlowInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,23 @@

use Closure;

/**
* @template T
*/
interface FlowInterface
{
/**
* @param Ip<T> $ip
*/
public function __invoke(Ip $ip, Closure $callback = null): void;

/**
* @template T1 of IP
* @template T2 of IP
*
* @param FlowInterface<T1> $flow
*
* @return FlowInterface<T2>
*/
public function fn(self $flow): self;
}
6 changes: 6 additions & 0 deletions src/Ip.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,14 @@

namespace Flow;

/**
* @template T of object
*/
final readonly class Ip
{
/**
* @param ?T $data
*/
public function __construct(public ?object $data = null)
{
}
Expand Down
2 changes: 1 addition & 1 deletion tools/php-cs-fixer/.php-cs-fixer.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
'import_functions' => true,
'import_classes' => true,
],
'logical_operators' => false, // https://cs.symfony.com/doc/rules/operator/logical_operators.html we keep or and by design
'logical_operators' => false, // https://cs.symfony.com/doc/rules/operator/logical_operators.html prefer use 'or' and 'and' operators by design
'yoda_style' => false, // https://cs.symfony.com/doc/rules/control_structure/yoda_style.html
'increment_style' => ['style' => 'post'],
])
Expand Down

0 comments on commit c210b1f

Please sign in to comment.