ReflectsClosures.php 2.6 KB

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