Last active
February 25, 2023 08:42
-
-
Save jacmkno/dc13c089c3d641a2c3d48f7cde5c377b to your computer and use it in GitHub Desktop.
Promises in PHP with Asyncronous Bash Execution
This file contains 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 | |
namespace Promises; | |
class BashPromise extends Promise { | |
public $outputTmpFile; | |
public $inputTmpFile; | |
function __construct($process, $inputData=NULL, $inputAsStdIn = FALSE){ | |
$inputExtra = ''; | |
if($inputData){ | |
$this->inputTmpFile = tempnam("/tmp", "PHPBashPromiseIn"); | |
file_put_contents($this->inputTmpFile, $inputData); | |
if($inputAsStdIn){ | |
$inputExtra = " <<< \"$(cat $this->inputTmpFile)\""; | |
}else{ | |
$inputExtra = " $this->inputTmpFile"; | |
} | |
} | |
$this->outputTmpFile = tempnam("/tmp", "PHPBashPromiseOut"); | |
unlink($this->outputTmpFile); | |
shell_exec('/bin/bash -c \'a=$('.$process.$inputExtra.'); echo "${a}" > '.$this->outputTmpFile.'\' > /dev/null 2>&1 &'); | |
} | |
function next(){ | |
if($this->outputTmpFile){ | |
if(file_exists($this->outputTmpFile)){ | |
$this->result = file_get_contents($this->outputTmpFile); | |
unlink($this->outputTmpFile); | |
$this->outputTmpFile = NULL; | |
if($this->inputTmpFile) unlink($this->inputTmpFile); | |
}else{ | |
return [$this]; | |
} | |
} | |
return parent::next(); | |
} | |
} |
This file contains 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 | |
namespace Promises; | |
class Promise { | |
public $callbacks = []; | |
public $result = NULL; | |
public $queue = []; | |
public $promiseGroupCnt = 0; | |
public $promiseGroup = NULL; | |
function __construct($process /* function || Array<Promise> */){ | |
if(is_array($process)){ | |
$this->result = []; | |
$this->promiseGroup = $process; | |
$this->promiseGroupCnt = count($process); | |
array_map(function($promise){ | |
$idx = count($this->result); | |
$this->result[] = NULL; | |
$promise->then(function($result) use ($idx) { | |
$this->result[$idx] = $result; | |
$this->promiseGroupCnt -= 1; | |
}); | |
}, $process); | |
}else{ | |
$this->callbacks[] = $process; | |
} | |
} | |
public function then($callback){ | |
$this->callbacks[] = $callback; | |
return $this; | |
} | |
public static function all($promises){ | |
return new Promise($promises); | |
} | |
public function next(){ | |
$nxts = []; | |
if(is_a($this->result, Promise::class)) { | |
$nxt = $this->result->next(); | |
if(count($nxt)){ | |
$nxts = array_merge($nxts, $nxt); | |
}else{ | |
$this->result = $this->result->result; | |
} | |
}else{ | |
if($this->promiseGroup !== NULL && $this->promiseGroupCnt){ | |
$nxts = array_merge($nxts, $this->promiseGroup); | |
$this->promiseGroup = []; | |
}else{ | |
$callback = array_shift($this->callbacks); | |
if (is_callable($callback)) { | |
$result = $callback($this->result); | |
if($result !== NULL){ | |
$this->result = $result; | |
} | |
} | |
} | |
} | |
if($this->pending()){ | |
$nxts[] = $this; | |
} | |
return $nxts; | |
} | |
public function pending(){ | |
return $this->promiseGroupCnt || count($this->callbacks) || is_a($this->result, Promise::class) || count($this->queue); | |
} | |
public function await(){ | |
$this->queue = [$this]; | |
while($p = array_shift($this->queue)){ | |
$nxts = $p->next(); | |
$this->queue = array_merge($this->queue, $nxts); | |
usleep(10*1000000/1000); | |
} | |
return $this->result; | |
} | |
function toString($direct=FALSE){ | |
if($direct){ | |
return json_encode($this, JSON_PRETTY_PRINT)."\n\n"; | |
} | |
$data = [ | |
'callbacks' => count($this->callbacks), | |
'result' => json_encode($this->result), | |
'queue' => count($this->queue), | |
'promiseGroupCnt' => $this->promiseGroupCnt, | |
'promiseGroup' => gettype($this->promiseGroup), | |
]; | |
return json_encode($data, JSON_PRETTY_PRINT)."\n\n"; | |
} | |
} |
This file contains 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 | |
namespace Example; | |
use Promises\Promise; | |
use Promises\BashPromise; | |
$a = (new BashPromise('sleep 3; head -n 2', json_encode(['xxx'=>[1,2,34]], JSON_PRETTY_PRINT), TRUE))->then(function($out){ | |
return [strlen($out), '"'.$out.'"']; | |
}); | |
$b = new BashPromise('sleep 4; echo 2'); | |
$c = new BashPromise('sleep 4; echo 3'); | |
$d = new Promise(function(){ | |
return Promise::all([ | |
Promise::all([]), | |
new Promise(function(){return 4;}), | |
(new BashPromise('sleep 4; ls -la'))->then(function($out){ | |
return [strlen($out), substr($out, 0, 20)]; | |
}), | |
new BashPromise('sleep 4; echo 6') | |
]); | |
}); | |
$e = Promise::all([$a, $b, $c, $d]); | |
$f = $e->await(); | |
print_r($f); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment