-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds
once
memoization function (#550)
* Adds once memoization function * Delete test-results cache file * Add .phpunit.cache to .gitignore * Add null return statement in Onceable::create() method --------- Co-authored-by: Deeka Wong <[email protected]>
- Loading branch information
1 parent
f4a3220
commit a57b9d1
Showing
3 changed files
with
201 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
/** | ||
* This file is part of friendsofhyperf/components. | ||
* | ||
* @link https://github.com/friendsofhyperf/components | ||
* @document https://github.com/friendsofhyperf/components/blob/main/README.md | ||
* @contact [email protected] | ||
*/ | ||
|
||
namespace FriendsOfHyperf\Support; | ||
|
||
use WeakMap; | ||
|
||
class Once | ||
{ | ||
/** | ||
* The current globally used instance. | ||
* | ||
* @var static|null | ||
*/ | ||
protected static ?self $instance = null; | ||
|
||
/** | ||
* Indicates if the once instance is enabled. | ||
*/ | ||
protected static bool $enabled = true; | ||
|
||
/** | ||
* Create a new once instance. | ||
* | ||
* @param WeakMap<object, array<string, mixed>> $values | ||
*/ | ||
protected function __construct(protected WeakMap $values) | ||
{ | ||
} | ||
|
||
/** | ||
* Create a new once instance. | ||
* | ||
* @return static | ||
*/ | ||
public static function instance() | ||
{ | ||
return static::$instance ??= new static(new WeakMap()); | ||
} | ||
|
||
/** | ||
* Get the value of the given onceable. | ||
* | ||
* @return mixed | ||
*/ | ||
public function value(Onceable $onceable) | ||
{ | ||
if (! static::$enabled) { | ||
return call_user_func($onceable->callable); | ||
} | ||
|
||
$object = $onceable->object ?: $this; | ||
|
||
$hash = $onceable->hash; | ||
|
||
if (isset($this->values[$object][$hash])) { | ||
return $this->values[$object][$hash]; | ||
} | ||
|
||
if (! isset($this->values[$object])) { | ||
$this->values[$object] = []; | ||
} | ||
|
||
return $this->values[$object][$hash] = call_user_func($onceable->callable); | ||
} | ||
|
||
/** | ||
* Re-enable the once instance if it was disabled. | ||
*/ | ||
public static function enable() | ||
{ | ||
static::$enabled = true; | ||
} | ||
|
||
/** | ||
* Disable the once instance. | ||
*/ | ||
public static function disable() | ||
{ | ||
static::$enabled = false; | ||
} | ||
|
||
/** | ||
* Flush the once instance. | ||
*/ | ||
public static function flush() | ||
{ | ||
static::$instance = null; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
/** | ||
* This file is part of friendsofhyperf/components. | ||
* | ||
* @link https://github.com/friendsofhyperf/components | ||
* @document https://github.com/friendsofhyperf/components/blob/main/README.md | ||
* @contact [email protected] | ||
*/ | ||
|
||
namespace FriendsOfHyperf\Support; | ||
|
||
use Closure; | ||
use Laravel\SerializableClosure\Support\ReflectionClosure; | ||
|
||
class Onceable | ||
{ | ||
/** | ||
* Create a new onceable instance. | ||
* | ||
* @param callable $callable | ||
*/ | ||
public function __construct( | ||
public string $hash, | ||
public object|null $object, | ||
public $callable | ||
) { | ||
} | ||
|
||
/** | ||
* Tries to create a new onceable instance from the given trace. | ||
* | ||
* @param array<int, array<string, mixed>> $trace | ||
* @return static|null | ||
*/ | ||
public static function tryFromTrace(array $trace, callable $callable) | ||
{ | ||
if (! is_null($hash = static::hashFromTrace($trace, $callable))) { | ||
$object = static::objectFromTrace($trace); | ||
|
||
return new static($hash, $object, $callable); | ||
} | ||
|
||
return null; | ||
} | ||
|
||
/** | ||
* Computes the object of the onceable from the given trace, if any. | ||
* | ||
* @param array<int, array<string, mixed>> $trace | ||
* @return object|null | ||
*/ | ||
protected static function objectFromTrace(array $trace) | ||
{ | ||
return $trace[1]['object'] ?? null; | ||
} | ||
|
||
/** | ||
* Computes the hash of the onceable from the given trace. | ||
* | ||
* @param array<int, array<string, mixed>> $trace | ||
* @return string|null | ||
*/ | ||
protected static function hashFromTrace(array $trace, callable $callable) | ||
{ | ||
if (str_contains($trace[0]['file'] ?? '', 'eval()\'d code')) { | ||
return null; | ||
} | ||
|
||
$uses = array_map( | ||
fn (mixed $argument) => is_object($argument) ? spl_object_hash($argument) : $argument, | ||
$callable instanceof Closure ? (new ReflectionClosure($callable))->getClosureUsedVariables() : [], | ||
); | ||
|
||
return md5(sprintf( | ||
'%s@%s%s:%s (%s)', | ||
$trace[0]['file'], | ||
isset($trace[1]['class']) ? ($trace[1]['class'] . '@') : '', | ||
$trace[1]['function'], | ||
$trace[0]['line'], | ||
serialize($uses), | ||
)); | ||
} | ||
} |