With
This function simply mocks Python's with statement for PHP., (*1)
, (*2)
Installation
The recommended way to install is through composer., (*3)
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., (*4)
A with statement is defined as followed: with([object], [callback]);., (*5)
The executation of a with statement is done as followed:, (*6)
- The
[object]'s __enter() method is invoked
- 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
- The
[callback] is executed
- 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:, (*7)
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:, (*8)
use Gnikyt\Withable;
class Foo implements Withable
{
// ...
}
The above example is processed as follows:, (*9)
-
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., (*10)