Skip to content

Instantly share code, notes, and snippets.

@IMSoP
Created March 24, 2021 22:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save IMSoP/a4e316684415413dca8ec5debf51a812 to your computer and use it in GitHub Desktop.
Save IMSoP/a4e316684415413dca8ec5debf51a812 to your computer and use it in GitHub Desktop.
Python's with statement, but for PHP
<?php
class Transaction implements ContextManager
{
public function __construct(private Database $db) {}
public function contextEnter() {
$this->db->beginTransaction();
// Could return some other representation of the transaction if appropriate
return $this;
}
public function contextExit(?Throwable $e) {
if ( $e === null ) {
$this->db->commitTransaction();
return true;
}
else {
$this->db->rollbackTransaction();
return false;
}
}
}
<?php
with ( new Transaction($db) as $transaction ) {
doSomething($to, $library, $thread);
andThenSomethingElse($author, $title, $library_name, $top_post);
}
<?php
// internal values not accessible to the user
$__context = new Transaction($db);
$__exited = false;
try {
// the transaction would be opened in contextEnter(), so you don't need complex logic in the constructor
// this also lets "with ( $existingObject )" work
// $transaction is optional in the with syntax and receives whatever contextEnter returns
$transaction = $__context->contextEnter();
// user's code happens here; no capturing is needed, because we're still in the same scope!
doSomething($to, $library, $thread);
andThenSomethingElse($author, $title, $library_name, $top_post);
}
catch ( Throwable $e ) {
$__exited = true;
// Pass exception to Context Manager, which can indicate whether to re-throw it
if ( ! $__context->contextExit($e) ) {
throw $e;
}
}
finally {
// only call the contextExit() method if it wasn't already called in the catch block
if ( ! $__exited ) {
$__context->contextExit();
}
}
@IMSoP
Copy link
Author

IMSoP commented Mar 24, 2021

This is based on my reading of https://www.python.org/dev/peps/pep-0343/ and may well have some details wrong.

See that document for plenty more examples of how it can be used.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment