98 lines
2.8 KiB
PHP
98 lines
2.8 KiB
PHP
<?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;
|
|
}
|
|
}
|