ReflectsClosures.php 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. <?php
  2. namespace Illuminate\Support\Traits;
  3. use Closure;
  4. use Illuminate\Support\Reflector;
  5. use ReflectionFunction;
  6. use RuntimeException;
  7. trait ReflectsClosures
  8. {
  9. /**
  10. * Get the class name of the first parameter of the given Closure.
  11. *
  12. * @param \Closure $closure
  13. * @return string
  14. *
  15. * @throws \ReflectionException
  16. * @throws \RuntimeException
  17. */
  18. protected function firstClosureParameterType(Closure $closure)
  19. {
  20. $types = array_values($this->closureParameterTypes($closure));
  21. if (! $types) {
  22. throw new RuntimeException('The given Closure has no parameters.');
  23. }
  24. if ($types[0] === null) {
  25. throw new RuntimeException('The first parameter of the given Closure is missing a type hint.');
  26. }
  27. return $types[0];
  28. }
  29. /**
  30. * Get the class names of the first parameter of the given Closure, including union types.
  31. *
  32. * @param \Closure $closure
  33. * @return array
  34. *
  35. * @throws \ReflectionException
  36. * @throws \RuntimeException
  37. */
  38. protected function firstClosureParameterTypes(Closure $closure)
  39. {
  40. $reflection = new ReflectionFunction($closure);
  41. $types = collect($reflection->getParameters())->mapWithKeys(function ($parameter) {
  42. if ($parameter->isVariadic()) {
  43. return [$parameter->getName() => null];
  44. }
  45. return [$parameter->getName() => Reflector::getParameterClassNames($parameter)];
  46. })->filter()->values()->all();
  47. if (empty($types)) {
  48. throw new RuntimeException('The given Closure has no parameters.');
  49. }
  50. if (isset($types[0]) && empty($types[0])) {
  51. throw new RuntimeException('The first parameter of the given Closure is missing a type hint.');
  52. }
  53. return $types[0];
  54. }
  55. /**
  56. * Get the class names / types of the parameters of the given Closure.
  57. *
  58. * @param \Closure $closure
  59. * @return array
  60. *
  61. * @throws \ReflectionException
  62. */
  63. protected function closureParameterTypes(Closure $closure)
  64. {
  65. $reflection = new ReflectionFunction($closure);
  66. return collect($reflection->getParameters())->mapWithKeys(function ($parameter) {
  67. if ($parameter->isVariadic()) {
  68. return [$parameter->getName() => null];
  69. }
  70. return [$parameter->getName() => Reflector::getParameterClassName($parameter)];
  71. })->all();
  72. }
  73. }