Skip to content

Instantly share code, notes, and snippets.

@kourge
Last active August 9, 2023 03:25
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kourge/5824654 to your computer and use it in GitHub Desktop.
Save kourge/5824654 to your computer and use it in GitHub Desktop.
A simple user-space PHP `with` implementation that mimics Python context managers.
<?php
class Context {
private $args = array();
private $func = NULL;
public function __construct() {
$args = func_get_args();
$func = array_pop($args);
$this->args = $args;
$this->func = $func;
}
public function execute() {
$this->enter();
try {
call_user_func_array($this->func, $this->args);
$this->leave();
} catch (Exception $e) {
$exception_handled = $this->leave($e);
if (!$exception_handled) {
throw $e;
}
}
}
private function enter() {
foreach ($this->args as $arg) {
if (method_exists($arg, "__enter")) {
call_user_func(array($arg, "__enter"));
}
}
}
private function leave($error=NULL) {
$exceptions_handled = TRUE;
foreach (array_reverse($this->args) as $arg) {
if (method_exists($arg, "__exit")) {
$result = call_user_func(array($arg, "__exit"), $error);
if (!$result) {
$exceptions_handled = FALSE;
}
}
}
return $exceptions_handled;
}
}
function with() {
$class = new ReflectionClass("Context");
$manager = $class->newInstanceArgs(func_get_args());
$manager->execute();
}
/** Demo **/
class Box {
private $var;
public function __construct($value) {
$this->var = $value;
}
public function __toString() {
return (string)$this->var;
}
public function __enter() {
echo "enter ". (string)$this ."\n";
}
public function __exit($e) {
echo "exit ". (string)$this ."\n";
if ($e != NULL) {
echo "\t$e\n";
return FALSE;
}
}
}
with(new Box(1), new Box(2), function($a, $b) {
echo $a ."\n";
throw new Exception();
echo $b ."\n";
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment