Multiple context arguments

Multiple arguments may be passed to with():

1
2
3
with($cm1, $cm2, ...)(function ($arg1, $arg2, ...) {
   # body of the user-provided callback ...
});

For every value $cm1, $cm2, …, passed to with() a corresponding value is passed as an argument to the user-provided callback. Assuming, $cm1, $cm2, …, are Context Managers, the corresponding arguments of the user-provided callback will receive

  • $arg1 = $cm1->enterContext(),
  • $arg2 = $cm2->enterContext(),

The context managers cm1, cm2, …, are invoked in the same order as they appear on the argument list to with() when entering the context (enterContext()) and in the reverse order when exiting the context (exitContext()).

Let’s use the following simple context manager to illustrate this

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
class MyInt implements ContextManagerInterface
{
    public $value;

    public function __construct(int $value)
    {
        $this->value = $value;
    }

    public function enterContext()
    {
        echo "enter: " . $this->value . "\n";
        return $this->value;
    }

    public function exitContext(?\Throwable $exception = null) : bool
    {
        echo "exit: " . $this->value . "\n";
        return false;
    }
}

The order or argument processing may be then illustrated by the following test

1
2
3
with(new MyInt(1), new MyInt(2), new MyInt(3))(function (int ...$args) {
    echo '$args: ' . implode(', ', $args) . "\n";
});

The output from above snippet will be

enter: 1
enter: 2
enter: 3
$args: 1, 2, 3
exit: 3
exit: 2
exit: 1