Last active
August 29, 2015 14:17
-
-
Save bwoebi/77759ace18b63a4ccdf2 to your computer and use it in GitHub Desktop.
Generic typehints (Generator)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class Fetched { | |
# dummy class | |
} | |
class Fetcher { | |
private $promises; | |
private $stream; | |
private $watcher; | |
public function __construct(Stream $stream) { | |
$this->stream = $stream; | |
} | |
public function fetch(int $param): Promise<Fetched> { | |
# write some things to the $this->stream related to $param | |
$promise = new Promise; // is a Promise<Fetched>, because that's what's returned | |
$this->promises[] = $promise; | |
$this->watcher = $this->stream->enableWatcher([$this, "onReadable"]); | |
return $promise; | |
} | |
public function onReadable(string $streamInput) { | |
# work on $streamInput | |
# if we have all information ... (else return and wait in loop) | |
$this->stream->disableWatcher($this->watcher); | |
$promise = array_unshift($promises); # we can infer it was a Promise<Fetched> in the array, because that's the only thing ever pushed on it | |
$promise->resolve(new Fetched); | |
} | |
} | |
class Promise<T> { | |
protected $resolved = false; | |
protected $value; | |
private $resolver; | |
public function resolved(): bool { | |
return $this->resolved; | |
} | |
public function resolve(T $value): null { | |
$this->resolved = true; | |
$this->value = $value; | |
if (!$resolver) throw new Exception; # ... | |
($this->resolver)($value); | |
} | |
public function setResolver((T $value) $resolver): null { | |
$this->resolver = $resolver; | |
} | |
public function getValue() : T { | |
return $this->value; | |
} | |
} | |
class Success<T> extends Promise<T> { | |
public function __construct(T $success) { | |
$this->resolved = true; | |
$this->value = $success; | |
} | |
} | |
function getNumber(): Promise<int> { | |
return new Success(4); | |
} | |
function gen(Fetcher $fetcher): Generator<null, T, Promise<T>, Fetched> { | |
# Note that you may want to yield other Promises which are not of type Promise<Fetched> here... like e.g. Promise<int> | |
$number = yield getNumber(); | |
$fetched = yield $fetcher->fetch($number); | |
return $fetched; | |
} | |
# ... in generics mark types I'm not interested in, which I don't want to specify | |
function advanceGenerator(Generator<..., T, Promise<T>, ...> $generator): null { | |
$advance = function () use (&$send, $generator) { | |
while ($generator->valid()) { | |
$promise = $generator->current(); | |
if (!$promise->resolved()) { | |
$promise->setResolver($send); | |
return; | |
} | |
$generator->send($promise->getValue()); | |
} | |
} | |
$send = function (T $value) use ($advance, $generator) { | |
$generator->send($value); | |
$advance(); | |
} | |
$advance(); | |
} | |
# get $stream from somewhere here… doesn't matter for the example | |
$gen = gen(new Fetcher($stream)); | |
advanceGenerator(); | |
if ($gen->valid()) { | |
startEventLoop(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment