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-12-13 10:53:28 UTC


README

Closure unwrapper especially suited for Laravel PDO.

Requirements

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

(A) $value

$value(mixed ...$initialArgs): mixed

(B) $callback

$callback(mixed $value, ...$args): mixed

(C) Return Value

*(mixed ...$initialArgs): mixed

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

(A) &$value

*(): mixed

(B) $configurator

$configurator(mixed $value): ?callable

(C) $configurator Return Value

*(mixed $value): void

(D) $callback

$callback(...$args): mixed