@@ -342,33 +342,58 @@ function _checkTypehint(callable $callback, \Throwable $reason): bool
342342 return true ;
343343 }
344344
345- $ type = $ parameters [0 ]->getType ();
346-
347- if (!$ type ) {
348- return true ;
345+ $ expectedException = $ parameters [0 ];
346+
347+ // Extract the type of the argument and handle different possibilities
348+ $ type = $ expectedException ->getType ();
349+
350+ $ isTypeUnion = true ;
351+ $ types = [];
352+
353+ switch (true ) {
354+ case $ type === null :
355+ break ;
356+ case $ type instanceof \ReflectionNamedType:
357+ $ types = [$ type ];
358+ break ;
359+ case $ type instanceof \ReflectionIntersectionType:
360+ $ isTypeUnion = false ;
361+ case $ type instanceof \ReflectionUnionType;
362+ $ types = $ type ->getTypes ();
363+ break ;
364+ default :
365+ throw new \LogicException ('Unexpected return value of ReflectionParameter::getType ' );
349366 }
350367
351- $ types = [$ type ];
352-
353- if ($ type instanceof \ReflectionUnionType) {
354- $ types = $ type ->getTypes ();
368+ // If there is no type restriction, it matches
369+ if (empty ($ types )) {
370+ return true ;
355371 }
356372
357- $ mismatched = false ;
358-
359373 foreach ($ types as $ type ) {
360- if (!$ type || $ type -> isBuiltin () ) {
361- continue ;
374+ if (!$ type instanceof \ReflectionNamedType ) {
375+ throw new \ LogicException ( ' This implementation does not support groups of intersection or union types ' ) ;
362376 }
363377
364- $ expectedClass = $ type ->getName ();
365-
366- if ($ reason instanceof $ expectedClass ) {
367- return true ;
378+ // A named-type can be either a class-name or a built-in type like string, int, array, etc.
379+ $ matches = ($ type ->isBuiltin () && \gettype ($ reason ) === $ type ->getName ())
380+ || (new \ReflectionClass ($ type ->getName ()))->isInstance ($ reason );
381+
382+
383+ // If we look for a single match (union), we can return early on match
384+ // If we look for a full match (intersection), we can return early on mismatch
385+ if ($ matches ) {
386+ if ($ isTypeUnion ) {
387+ return true ;
388+ }
389+ } else {
390+ if (!$ isTypeUnion ) {
391+ return false ;
392+ }
368393 }
369-
370- $ mismatched = true ;
371394 }
372395
373- return !$ mismatched ;
396+ // If we look for a single match (union) and did not return early, we matched no type and are false
397+ // If we look for a full match (intersection) and did not return early, we matched all types and are true
398+ return $ isTypeUnion ? false : true ;
374399}
0 commit comments