Skip to content

gnikyt/with

Repository files navigation

With

This function simply mocks Python's with statement for PHP.

Tests codecov License

Installation

The recommended way to install is through composer.

composer require gnikyt/with

Usage

The with statement is used to wrap the execution of code with methods defined by a object. This allows common try...except...finally usage patterns to be encapsulated for convenient reuse.

A with statement is defined as followed: with([object], [callback]);.

The executation of a with statement is done as followed:

  1. The [object]'s __enter() method is invoked
  2. The return value from __enter() is assigned to the first argument of the [callback]

Note: The with statement guarantees that if the __enter() method returns without an error, then __exit() will always be called. Thus, if an error occurs during __enter(), it will be treated the same as an error occurring within the [callback] would be. See step 4 below

  1. The [callback] is executed
  2. The [object]'s __exit() method is invoked. If an exception caused the [callback] to be exited, the return value from __enter() and the [callback]'s exception are passed as arguments to __exit(). Otherwise, only the return value from __enter() is passed and the exception is set to null

If the [callback] was exited due to an exception, and the return value from the __exit() method was false, the exception is rethrown. If the return value was true, the exception is suppressed, and execution continues with the statement following the with statement.

Here is a sample object and a with-statement:

class Foo
{
    private $db;

    //.. other code ..//

    public function __enter()
    {
        $db = new PDO(
                sprintf('%s:host=%s;dbname=%s', $this->config['driver'], $this->config['host'], $this->config['db']),
                $this->config['user'],
                $this->config['pass']
        );

        $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

        return $db;
    }

    public function __exit($db, $error = null)
    {
        if ($error instanceof Exception) {
            $this->log('We had en error; Rolling back.');

            $db->rollback();
        } else {
            $this->log('Code ran fine. Committed.');

            $db->commit();
        }

        return true;
    }
}

$foo = new Foo;
Gnikyt\with($foo, function($db) {
    $db->beginTransaction();

    $foo = 'osiset';
    $sql = $db->prepare("INSERT INTO non_existant_table SET name = :foo");
    $sql->bindParam('foo', $foo, PDO::PARAM_STR);
    $sql->execute();
});

You're also free to implement the interface provided to ensure you're classes are compatible:

use Gnikyt\Withable;

class Foo implements Withable
{
    // ...
}

The above example is processed as follows:

  • with will call $foo->__enter()
  • $foo->__enter() will setup the database, and return the PDO object
  • with will now pass the PDO object to the callback as $db for use within the closure
  • with now executes the callback closure
  • The callback will throw an exception because the table does not exist
  • with now calls $foo->__exit() and passed the $db object and the exception from the callback to it
  • $foo->__exit() now checks for a exception and rollsback the changes. It returns true to suppress re-throwing the exception
  • with now checks the return from $foo->__exit(), it sees it returns a true value, and does not re-throw the exception

Requirements

Usage

See examples/ for some basic usage code or this README.

About

A Python with-statement clone for PHP.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages