@@ -11,7 +11,7 @@ trait PreventsCircularRecursion
11
11
/**
12
12
* The cache of objects processed to prevent infinite recursion.
13
13
*
14
- * @var \ WeakMap<static, array<string, mixed>>
14
+ * @var WeakMap<static, array<string, mixed>>
15
15
*/
16
16
protected static $ recursionCache ;
17
17
@@ -28,31 +28,40 @@ protected function withoutRecursion($callback, $default = null)
28
28
29
29
$ onceable = Onceable::tryFromTrace ($ trace , $ callback );
30
30
31
- $ object = $ onceable ->object ?? $ this ;
32
-
33
- $ stack = static ::getRecursiveCallStack ($ object );
31
+ $ stack = static ::getRecursiveCallStack ($ this );
34
32
35
33
if (array_key_exists ($ onceable ->hash , $ stack )) {
36
- return $ stack [$ onceable ->hash ];
34
+ return is_callable ($ stack [$ onceable ->hash ])
35
+ ? static ::setRecursiveCallValue ($ this , $ onceable ->hash , call_user_func ($ stack [$ onceable ->hash ]))
36
+ : $ stack [$ onceable ->hash ];
37
37
}
38
38
39
39
try {
40
- $ stack [$ onceable ->hash ] = is_callable ($ default ) ? call_user_func ($ default ) : $ default ;
41
-
42
- static ::getRecursionCache ()->offsetSet ($ object , $ stack );
40
+ static ::setRecursiveCallValue ($ this , $ onceable ->hash , $ default );
43
41
44
42
return call_user_func ($ onceable ->callable );
45
43
} finally {
46
- if ($ stack = Arr::except ($ this ->getRecursiveCallStack ($ object ), $ onceable ->hash )) {
47
- static ::getRecursionCache ()->offsetSet ($ object , $ stack );
48
- } elseif (static ::getRecursionCache ()->offsetExists ($ object )) {
49
- static ::getRecursionCache ()->offsetUnset ($ object );
50
- }
44
+ static ::clearRecursiveCallValue ($ this , $ onceable ->hash );
51
45
}
52
46
}
53
47
54
48
/**
55
- * Get the current stack of methods being called recursively.
49
+ * Remove an entry from the recursion cache for an object.
50
+ *
51
+ * @param object $object
52
+ * @param string $hash
53
+ */
54
+ protected static function clearRecursiveCallValue ($ object , string $ hash )
55
+ {
56
+ if ($ stack = Arr::except (static ::getRecursiveCallStack ($ object ), $ hash )) {
57
+ static ::getRecursionCache ()->offsetSet ($ object , $ stack );
58
+ } elseif (static ::getRecursionCache ()->offsetExists ($ object )) {
59
+ static ::getRecursionCache ()->offsetUnset ($ object );
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Get the stack of methods being called recursively for the current object.
56
65
*
57
66
* @param object $object
58
67
* @return array
@@ -67,10 +76,28 @@ protected static function getRecursiveCallStack($object): array
67
76
/**
68
77
* Get the current recursion cache being used by the model.
69
78
*
70
- * @return \ WeakMap
79
+ * @return WeakMap
71
80
*/
72
81
protected static function getRecursionCache ()
73
82
{
74
83
return static ::$ recursionCache ??= new WeakMap ();
75
84
}
85
+
86
+ /**
87
+ * Set a value in the recursion cache for the given object and method.
88
+ *
89
+ * @param object $object
90
+ * @param string $hash
91
+ * @param mixed $value
92
+ * @return mixed
93
+ */
94
+ protected static function setRecursiveCallValue ($ object , string $ hash , $ value )
95
+ {
96
+ static ::getRecursionCache ()->offsetSet (
97
+ $ object ,
98
+ tap (static ::getRecursiveCallStack ($ object ), fn (&$ stack ) => $ stack [$ hash ] = $ value ),
99
+ );
100
+
101
+ return static ::getRecursiveCallStack (($ object ))[$ hash ];
102
+ }
76
103
}
0 commit comments