[Back] <?php
use Illuminate\Support\Traits\ReflectsClosures;
if (! function_exists('lazy')) {
/**
* Create a lazy instance.
*
* @template TValue of object
*
* @param class-string<TValue>|(\Closure(TValue): mixed) $class
* @param (\Closure(TValue): mixed)|int $callback
* @param int $options
* @param array<string, mixed> $eager
* @return TValue
*/
function lazy($class, $callback = 0, $options = 0, $eager = [])
{
static $closureReflector;
$closureReflector ??= new class
{
use ReflectsClosures;
public function typeFromParameter($callback)
{
return $this->firstClosureParameterType($callback);
}
};
[$class, $callback, $options] = is_string($class)
? [$class, $callback, $options]
: [$closureReflector->typeFromParameter($class), $class, $callback ?: $options];
$reflectionClass = new ReflectionClass($class);
$instance = $reflectionClass->newLazyGhost(function ($instance) use ($callback) {
$result = $callback($instance);
if (is_array($result)) {
$instance->__construct(...$result);
}
}, $options);
foreach ($eager as $property => $value) {
$reflectionClass->getProperty($property)->setRawValueWithoutLazyInitialization($instance, $value);
}
return $instance;
}
}
if (! function_exists('proxy')) {
/**
* Create a lazy proxy instance.
*
* @template TValue of object
*
* @param class-string<TValue>|(\Closure(TValue): TValue) $class
* @param (\Closure(TValue): TValue)|int $callback
* @param int $options
* @param array<string, mixed> $eager
* @return TValue
*/
function proxy($class, $callback = 0, $options = 0, $eager = [])
{
static $closureReflector;
$closureReflector = new class
{
use ReflectsClosures;
public function get($callback)
{
return $this->closureReturnTypes($callback)[0] ?? $this->firstClosureParameterType($callback);
}
};
[$class, $callback, $options] = is_string($class)
? [$class, $callback, $options]
: [$closureReflector->get($class), $class, $callback ?: $options];
$reflectionClass = new ReflectionClass($class);
$proxy = $reflectionClass->newLazyProxy(function () use ($callback, $eager, &$proxy) {
$instance = $callback($proxy, $eager);
return $instance;
}, $options);
foreach ($eager as $property => $value) {
$reflectionClass->getProperty($property)->setRawValueWithoutLazyInitialization($proxy, $value);
}
return $proxy;
}
}