mpyw/unclosure

Closure unwrapper especially suited for Laravel PDO

v3.0.0 2021-11-18 12:21 UTC

This package is auto-updated.

Last update: 2024-04-13 09:23:14 UTC


README

Closure unwrapper especially suited for Laravel PDO.

Requirements

Package Version Mandatory
PHP ^7.4 || ^8.0
PHPStan >=1.1

Installing

composer require mpyw/unclosure

Examples

Call PDO::setAttribute() after database connection has been established

<?php

use Mpyw\Unclosure\Value;
use PDO;

function withEmulation(PDO $pdo, bool $enabled): PDO
{
    $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, $enabled);
    return $pdo;
}

$connector = function (string $dsn) {
    return new PDO($dsn);
};

// Eager Evaluation
$pdo = Value::withCallback($connector('sqlite::memory:'), 'withEmulation', true);

// Lazy Evaluation
$pdo = Value::withCallback($connector, 'withEmulation', true);
$pdo = $pdo('sqlite::memory:');

Temporarily change PDO attributes

<?php

use Mpyw\Unclosure\Value;
use PDO;

function switchingEmulationTo(bool $enabled, &$pdo, callable $callback, ...$args)
{
    return Value::withEffect(
        $pdo,
        function (PDO $pdo) use ($enabled) {
            $original = $pdo->getAttribute(PDO::ATTR_EMULATE_PREPARES);
            $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, $enabled);
            
            return function (PDO $pdo) use ($original) {
                $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, $original);
            };
        },
        $callback,
        ...$args
    );
}

$connector = function (string $dsn) {
    return new PDO($dsn);
};

// Eager Evaluation
$pdo = $connector('sqlite::memory:');
switchingEmulationTo(true, $pdo, function () use ($pdo) {
    // Run queries that require prepared statement emulation
});

// Lazy Evaluation
$pdo = $connector;
switchingEmulationTo(true, $pdo, function () use (&$pdo) {
    $pdo = $pdo('sqlite::memory:');
    
    // Run queries that require prepared statement emulation
});

API

Value::withCallback()

static mixed|Closure withCallback(mixed|Closure $value, callable $callback, mixed ...$args)

Call $callback($value, ...$args) or wrap its call into Closure.

  • When you pass $value as Closure:
    • Return wrapped Closure which returns $callback($value(), ...$args).
  • When you pass $value as a raw value:
    • Return $callback($value, ...$args).

Arguments and Return Value

Name Type Description
$value mixed
(A) Closure
First argument for $callback which is unwrappable
$callback (B) callable A callback which takes unwrapped $value as the first argument
...$args mixed Second, third, ... arguments for $callback
<Return Value> mixed
(C) Closure
Decorated Closure or an unwrapped value

(A) $value

$value(mixed ...$initialArgs): mixed
Name Type Description
...$initialArgs mixed Arguments for unwrapping Closure
<Return Value> mixed An unwrapped value

(B) $callback

$callback(mixed $value, ...$args): mixed
Name Type Description
$value mixed An unwrapped value
...$args mixed Arguments from Value::withCallback()
<Return Value> mixed A decorated unwrapped value

(C) Return Value

*(mixed ...$initialArgs): mixed
Name Type Description
...$initialArgs mixed Arguments for unwrapping $value
<Return Value> mixed An unwrapped value which is propagated from $value(...$initialArgs)

Value::withEffect()
Value::withEffectForEach()

public static withEffect(mixed|Closure &$value, callable $configurator, callable $callback, mixed ...$args): mixed
public static withEffectForEach((mixed|Closure)[] &$values, callable $configurator, callable $callback, mixed ...$args): mixed

Call $callback(...$args), watching new assignment on &$value. You can conditionally unwrap $value in your $callback by yourself.

  • When you pass $value as Closure:
    • If $value has been unwrapped, configurations via $configurator are applied.
    • If $value still remains as Closure, all configurations are canceled.
  • When you pass $value as a raw value:
    • Configurations via $conigurator are immediately applied.

Arguments and Return Value

Name Type Description
&$value mixed
(A) Closure
An argument for $configurator which is unwrappable
$configurator (B) callable A configurator callback which takes unwrapped $value as the first argument
$callback (D) callable Any callback function
...$args mixed Arguments for $callback
<Return Value> mixed Return value from $callback(...$args)

(A) &$value

*(): mixed
Name Type Description
<Return Value> mixed An unwrapped value

(B) $configurator

$configurator(mixed $value): ?callable
Name Type Description
mixed mixed An unwrapped value
<Return Value> null
(C) callable
An optional disposer function corresponding to the configurator

(C) $configurator Return Value

*(mixed $value): void
Name Type Description
mixed mixed An unwrapped value

(D) $callback

$callback(...$args): mixed
Name Type Description
...$args mixed Arguments from Value::withEffect()
<Return Value> mixed