Preloader.php 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\DependencyInjection\Dumper;
  11. /**
  12. * @author Nicolas Grekas <p@tchwork.com>
  13. *
  14. * @internal
  15. */
  16. class Preloader
  17. {
  18. public static function preload(array $classes)
  19. {
  20. set_error_handler(function ($t, $m, $f, $l) {
  21. if (error_reporting() & $t) {
  22. if (__FILE__ !== $f) {
  23. throw new \ErrorException($m, 0, $t, $f, $l);
  24. }
  25. throw new \ReflectionException($m);
  26. }
  27. });
  28. $prev = [];
  29. $preloaded = [];
  30. try {
  31. while ($prev !== $classes) {
  32. $prev = $classes;
  33. foreach ($classes as $c) {
  34. if (!isset($preloaded[$c])) {
  35. self::doPreload($c, $preloaded);
  36. }
  37. }
  38. $classes = array_merge(get_declared_classes(), get_declared_interfaces(), get_declared_traits());
  39. }
  40. } finally {
  41. restore_error_handler();
  42. }
  43. }
  44. private static function doPreload(string $class, array &$preloaded): void
  45. {
  46. if (isset($preloaded[$class]) || \in_array($class, ['self', 'static', 'parent'], true)) {
  47. return;
  48. }
  49. $preloaded[$class] = true;
  50. try {
  51. $r = new \ReflectionClass($class);
  52. if ($r->isInternal()) {
  53. return;
  54. }
  55. $r->getConstants();
  56. $r->getDefaultProperties();
  57. if (\PHP_VERSION_ID >= 70400) {
  58. foreach ($r->getProperties(\ReflectionProperty::IS_PUBLIC) as $p) {
  59. self::preloadType($p->getType(), $preloaded);
  60. }
  61. }
  62. foreach ($r->getMethods(\ReflectionMethod::IS_PUBLIC) as $m) {
  63. foreach ($m->getParameters() as $p) {
  64. if ($p->isDefaultValueAvailable() && $p->isDefaultValueConstant()) {
  65. $c = $p->getDefaultValueConstantName();
  66. if ($i = strpos($c, '::')) {
  67. self::doPreload(substr($c, 0, $i), $preloaded);
  68. }
  69. }
  70. self::preloadType($p->getType(), $preloaded);
  71. }
  72. self::preloadType($m->getReturnType(), $preloaded);
  73. }
  74. } catch (\Throwable $e) {
  75. // ignore missing classes
  76. }
  77. }
  78. private static function preloadType(?\ReflectionType $t, array &$preloaded): void
  79. {
  80. if (!$t) {
  81. return;
  82. }
  83. foreach ($t instanceof \ReflectionUnionType ? $t->getTypes() : [$t] as $t) {
  84. if (!$t->isBuiltin()) {
  85. self::doPreload($t instanceof \ReflectionNamedType ? $t->getName() : $t, $preloaded);
  86. }
  87. }
  88. }
  89. }