Skip to content

Commit 2eb132f

Browse files
committed
Add lazy and proxy helpers
1 parent b4d8576 commit 2eb132f

File tree

3 files changed

+665
-0
lines changed

3 files changed

+665
-0
lines changed

src/Illuminate/Support/helpers.php

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use Illuminate\Support\Sleep;
1414
use Illuminate\Support\Str;
1515
use Illuminate\Support\Stringable as SupportStringable;
16+
use Illuminate\Support\Traits\ReflectsClosures;
1617

1718
if (! function_exists('append_config')) {
1819
/**
@@ -196,6 +197,60 @@ function literal(...$arguments)
196197
}
197198
}
198199

200+
if (! function_exists('lazy')) {
201+
/**
202+
* Create a lazy instance.
203+
*
204+
* @template TValue of object
205+
*
206+
* @param class-string<TValue>|(\Closure(TValue): mixed) $class
207+
* @param (\Closure(TValue): mixed)|int $callback
208+
* @param int $options
209+
* @param array<string, mixed> $eager
210+
* @return TValue
211+
*/
212+
function lazy($class, $callback = 0, $options = 0, $eager = [])
213+
{
214+
static $supported = version_compare(phpversion(), '8.4.0', '>=');
215+
216+
if (! $supported) {
217+
throw new RuntimeException('The `lazy` helper is only supported in PHP 8.4 or higher.');
218+
}
219+
220+
static $closureReflector = null;
221+
222+
$closureReflector ??= new class
223+
{
224+
use ReflectsClosures;
225+
226+
public function typeFromParameter($callback)
227+
{
228+
return $this->firstClosureParameterType($callback);
229+
}
230+
};
231+
232+
[$class, $callback, $options] = is_string($class)
233+
? [$class, $callback, $options]
234+
: [$closureReflector->typeFromParameter($class), $class, $callback ?: $options];
235+
236+
$reflectionClass = new ReflectionClass($class);
237+
238+
$instance = $reflectionClass->newLazyGhost(function ($instance) use ($callback) {
239+
$result = $callback($instance);
240+
241+
if (is_array($result)) {
242+
$instance->__construct(...$result);
243+
}
244+
}, $options);
245+
246+
foreach ($eager as $property => $value) {
247+
$reflectionClass->getProperty($property)->setRawValueWithoutLazyInitialization($instance, $value);
248+
}
249+
250+
return $instance;
251+
}
252+
}
253+
199254
if (! function_exists('object_get')) {
200255
/**
201256
* Get an item from an object using "dot" notation.
@@ -295,6 +350,45 @@ function preg_replace_array($pattern, array $replacements, $subject): string
295350
}
296351
}
297352

353+
if (! function_exists('proxy')) {
354+
/**
355+
* Create a lazy proxy instance.
356+
*
357+
* @template TValue of object
358+
*
359+
* @param class-string<TValue>|(\Closure(TValue): TValue) $class
360+
* @param (\Closure(TValue): TValue)|int $callback
361+
* @param int $options
362+
* @return TValue
363+
*/
364+
function proxy($class, $callback = 0, $options = 0)
365+
{
366+
static $supported = version_compare(phpversion(), '8.4.0', '>=');
367+
368+
if (! $supported) {
369+
throw new RuntimeException('The `lazy` helper is only supported in PHP 8.4 or higher.');
370+
}
371+
372+
static $clousreReflector = null;
373+
374+
$clousreReflector ??= new class
375+
{
376+
use ReflectsClosures;
377+
378+
public function typeFromParameter($callback)
379+
{
380+
return $this->firstClosureParameterType($callback);
381+
}
382+
};
383+
384+
[$class, $callback, $options] = is_string($class)
385+
? [$class, $callback, $options]
386+
: [$clousreReflector->typeFromParameter($class), $class, $callback ?: $options];
387+
388+
return (new ReflectionClass($class))->newLazyProxy($callback, $options);
389+
}
390+
}
391+
298392
if (! function_exists('retry')) {
299393
/**
300394
* Retry an operation a given number of times.

0 commit comments

Comments
 (0)