@@ -24,16 +24,16 @@ class DeferredCallChain implements \JsonSerializable, \ArrayAccess
2424 use FunctionCallTrait;
2525 use ArrayAccessTrait;
2626 use ExportTrait;
27-
27+
2828 /** @var array $stack The stack of deferred calls */
2929 protected $ stack = [];
3030
3131 /** @var mixed $expectedTarget The stack of deferred calls */
3232 protected $ expectedTarget ;
3333
3434 /**
35- * Constructor
36- *
35+ * Constructor
36+ *
3737 * @param string $class_type_interface_or_instance The expected target class/type/interface/instance
3838 */
3939 public function __construct ($ class_type_interface_or_instance =null )
@@ -54,7 +54,7 @@ public function __construct($class_type_interface_or_instance=null)
5454 public final function __call ($ method , array $ arguments )
5555 {
5656 $ caller = debug_backtrace (DEBUG_BACKTRACE_IGNORE_ARGS , 1 )[0 ];
57-
57+
5858 $ this ->stack [] = [
5959 'method ' => $ method ,
6060 'arguments ' => $ arguments ,
@@ -73,7 +73,7 @@ public final function __call($method, array $arguments)
7373 public function &offsetGet ($ key )
7474 {
7575 $ caller = debug_backtrace (DEBUG_BACKTRACE_IGNORE_ARGS , 1 )[0 ];
76-
76+
7777 $ this ->stack [] = [
7878 'entry ' => $ key ,
7979 'file ' => isset ($ caller ['file ' ]) ? $ caller ['file ' ] : null ,
@@ -86,7 +86,7 @@ public function &offsetGet($key)
8686 /**
8787 * Checks that the provided target matches the type/class/interface
8888 * given during construction.
89- *
89+ *
9090 * @param mixed $target
9191 * @return mixed $target Checked
9292 */
@@ -96,7 +96,7 @@ protected function checkTarget($target)
9696 if ($ target ) {
9797 throw new TargetAlreadyDefinedException ($ this , $ this ->expectedTarget , $ target );
9898 }
99-
99+
100100 $ out = $ this ->expectedTarget ;
101101 }
102102 elseif (is_string ($ this ->expectedTarget )) {
@@ -118,30 +118,30 @@ protected function checkTarget($target)
118118 else {
119119 throw new UndefinedTargetClassException ($ this , $ this ->expectedTarget );
120120 }
121-
121+
122122 $ out = $ target ;
123123 }
124124 else {
125125 $ out = $ target ;
126126 }
127-
127+
128128 return $ out ;
129129 }
130130
131131 /**
132- * Calling a method coded inside a magic __call can produce a
132+ * Calling a method coded inside a magic __call can produce a
133133 * BadMethodCallException and thus not be a callable.
134- *
134+ *
135135 * @param string $method_type '->' or '::'
136136 * @param mixed $current_chained_subject
137137 * @param string $method_name
138138 * @param array $arguments
139- *
139+ *
140140 * @return bool $is_called
141141 */
142142 protected function checkMethodIsReallyCallable (
143143 $ method_type ,
144- &$ current_chained_subject ,
144+ &$ current_chained_subject ,
145145 $ method_name ,
146146 $ arguments
147147 ) {
@@ -157,12 +157,12 @@ protected function checkMethodIsReallyCallable(
157157 elseif (is_string ($ current_chained_subject )) {
158158 $ class = $ current_chained_subject ;
159159 }
160-
160+
161161 $ callable = $ class .':: ' . $ method_name ;
162162 }
163-
163+
164164 $ current_chained_subject = call_user_func_array (
165- $ callable ,
165+ $ callable ,
166166 $ arguments
167167 );
168168 }
@@ -194,36 +194,39 @@ protected function checkMethodIsReallyCallable(
194194 throw $ e ;
195195 }
196196 }
197-
197+
198198 return $ is_called ;
199199 }
200200
201201 /**
202202 * Checks if the exception having $trace is thrown from à __call
203203 * magic method.
204- *
204+ *
205205 * @param array $trace
206206 * @param object $current_chained_subject
207207 * @param string $method_name
208- *
208+ *
209209 * @return bool Whether or not the exception having the $trace has been
210210 * thrown from a __call() method.
211211 */
212212 protected function exceptionTrownFromMagicCall (
213- $ trace ,
213+ $ trace ,
214214 $ current_chained_subject ,
215215 $ method_name
216216 ) {
217217 // Before PHP 7, there is a raw for the non existing method called
218218 $ call_user_func_array_position = PHP_VERSION_ID < 70000 ? 2 : 1 ;
219-
220- return
221- ($ trace [0 ]['function ' ] == '__call ' || $ trace [0 ]['function ' ] == '__callStatic ' )
222- && $ trace [0 ]['class ' ] == (is_string ($ current_chained_subject )
223- ? $ current_chained_subject
224- : get_class ($ current_chained_subject ))
225- && isset ($ trace [0 ]['args ' ][0 ])
226- && $ trace [0 ]['args ' ][0 ] == $ method_name
219+
220+ $ is_magic_call = $ trace [0 ]['function ' ] == '__call '
221+ || $ trace [0 ]['function ' ] == '__callStatic ' ;
222+
223+ $ current_object_class = (is_string ($ current_chained_subject )
224+ ? $ current_chained_subject
225+ : get_class ($ current_chained_subject ));
226+
227+ return true
228+ && $ is_magic_call
229+ && $ trace [0 ]['class ' ] == $ current_object_class
227230 && (
228231 $ trace [$ call_user_func_array_position ]['file ' ] == __FILE__
229232 && $ trace [$ call_user_func_array_position ]['function ' ] == 'call_user_func_array '
@@ -240,48 +243,42 @@ protected function exceptionTrownFromMagicCall(
240243 public function __invoke ($ target =null )
241244 {
242245 $ out = $ this ->checkTarget ($ target );
243-
246+
244247 foreach ($ this ->stack as $ i => $ call ) {
245248 $ is_called = false ;
246249 try {
247250 if (isset ($ call ['method ' ])) {
248251 $ method = $ call ['method ' ];
249252 $ arguments = $ call ['arguments ' ];
250-
251- if (is_object ($ out )) {
252- if (is_callable ([$ out , $ method ])) {
253- $ is_called = $ this ->checkMethodIsReallyCallable (
254- '-> ' ,
255- $ out ,
256- $ method ,
257- $ arguments
258- );
259- }
260-
261- if (! $ is_called && is_callable (get_class ($ out ) . ':: ' . $ method )) {
262- $ is_called = $ this ->checkMethodIsReallyCallable (
263- ':: ' ,
264- $ out ,
265- $ method ,
266- $ arguments
267- );
268- }
253+
254+ if (is_callable ([$ out , $ call ['method ' ]])) {
255+ $ is_called = $ this ->checkMethodIsReallyCallable (
256+ '-> ' ,
257+ $ out ,
258+ $ method ,
259+ $ arguments
260+ );
269261 }
270- elseif (is_string ($ out ) && is_callable ($ out . ':: ' . $ method )) {
262+
263+ if (! $ is_called && (
264+ (is_string ($ out ) && is_callable ($ out .':: ' .$ call ['method ' ]))
265+ || (is_object ($ out ) && is_callable (get_class ($ out ) .':: ' .$ call ['method ' ]))
266+ )
267+ ) {
271268 $ is_called = $ this ->checkMethodIsReallyCallable (
272269 ':: ' ,
273270 $ out ,
274271 $ method ,
275272 $ arguments
276273 );
277274 }
278-
275+
279276 if (! $ is_called && is_callable ($ method )) {
280277 $ arguments = $ this ->prepareArgs ($ arguments , $ out );
281278 $ out = call_user_func_array ($ method , $ arguments );
282279 $ is_called = true ;
283280 }
284-
281+
285282 if (! $ is_called ) {
286283 throw new \BadMethodCallException (
287284 $ method . "() is neither a method of "
@@ -295,20 +292,20 @@ public function __invoke($target=null)
295292 }
296293 }
297294 catch (\Exception $ e ) {
298-
295+
299296 $ callchain_description = $ this ->toString ([
300297 'target ' => $ target ,
301298 'limit ' => $ i ,
302299 ]);
303-
300+
304301 VisibilityViolator::setHiddenProperty (
305302 $ e ,
306303 'message ' ,
307304 $ e ->getMessage ()
308305 . "\nWhen applying $ callchain_description defined at "
309306 . $ call ['file ' ] . ': ' . $ call ['line ' ]
310307 );
311-
308+
312309 // Throw $e with the good stack (usage exception)
313310 throw $ e ;
314311 }
0 commit comments