vendor/symfony/config/Resource/ReflectionClassResource.php line 103

Open in your IDE?
  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\Config\Resource;
  11. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  12. use Symfony\Component\Messenger\Handler\MessageSubscriberInterface;
  13. use Symfony\Contracts\Service\ServiceSubscriberInterface;
  14. /**
  15.  * @author Nicolas Grekas <p@tchwork.com>
  16.  *
  17.  * @final
  18.  */
  19. class ReflectionClassResource implements SelfCheckingResourceInterface
  20. {
  21.     private array $files = [];
  22.     private string $className;
  23.     private \ReflectionClass $classReflector;
  24.     private array $excludedVendors = [];
  25.     private string $hash;
  26.     public function __construct(\ReflectionClass $classReflector, array $excludedVendors = [])
  27.     {
  28.         $this->className $classReflector->name;
  29.         $this->classReflector $classReflector;
  30.         $this->excludedVendors $excludedVendors;
  31.     }
  32.     /**
  33.      * {@inheritdoc}
  34.      */
  35.     public function isFresh(int $timestamp): bool
  36.     {
  37.         if (!isset($this->hash)) {
  38.             $this->hash $this->computeHash();
  39.             $this->loadFiles($this->classReflector);
  40.         }
  41.         foreach ($this->files as $file => $v) {
  42.             if (false === $filemtime = @filemtime($file)) {
  43.                 return false;
  44.             }
  45.             if ($filemtime $timestamp) {
  46.                 return $this->hash === $this->computeHash();
  47.             }
  48.         }
  49.         return true;
  50.     }
  51.     public function __toString(): string
  52.     {
  53.         return 'reflection.'.$this->className;
  54.     }
  55.     /**
  56.      * @internal
  57.      */
  58.     public function __sleep(): array
  59.     {
  60.         if (!isset($this->hash)) {
  61.             $this->hash $this->computeHash();
  62.             $this->loadFiles($this->classReflector);
  63.         }
  64.         return ['files''className''hash'];
  65.     }
  66.     private function loadFiles(\ReflectionClass $class)
  67.     {
  68.         foreach ($class->getInterfaces() as $v) {
  69.             $this->loadFiles($v);
  70.         }
  71.         do {
  72.             $file $class->getFileName();
  73.             if (false !== $file && is_file($file)) {
  74.                 foreach ($this->excludedVendors as $vendor) {
  75.                     if (str_starts_with($file$vendor) && false !== strpbrk(substr($file\strlen($vendor), 1), '/'.\DIRECTORY_SEPARATOR)) {
  76.                         $file false;
  77.                         break;
  78.                     }
  79.                 }
  80.                 if ($file) {
  81.                     $this->files[$file] = null;
  82.                 }
  83.             }
  84.             foreach ($class->getTraits() as $v) {
  85.                 $this->loadFiles($v);
  86.             }
  87.         } while ($class $class->getParentClass());
  88.     }
  89.     private function computeHash(): string
  90.     {
  91.         try {
  92.             $this->classReflector ??= new \ReflectionClass($this->className);
  93.         } catch (\ReflectionException) {
  94.             // the class does not exist anymore
  95.             return false;
  96.         }
  97.         $hash hash_init('md5');
  98.         foreach ($this->generateSignature($this->classReflector) as $info) {
  99.             hash_update($hash$info);
  100.         }
  101.         return hash_final($hash);
  102.     }
  103.     private function generateSignature(\ReflectionClass $class): iterable
  104.     {
  105.         $attributes = [];
  106.         foreach ($class->getAttributes() as $a) {
  107.             $attributes[] = [$a->getName(), (string) $a];
  108.         }
  109.         yield print_r($attributestrue);
  110.         $attributes = [];
  111.         yield $class->getDocComment();
  112.         yield (int) $class->isFinal();
  113.         yield (int) $class->isAbstract();
  114.         if ($class->isTrait()) {
  115.             yield print_r(class_uses($class->name), true);
  116.         } else {
  117.             yield print_r(class_parents($class->name), true);
  118.             yield print_r(class_implements($class->name), true);
  119.             yield print_r($class->getConstants(), true);
  120.         }
  121.         if (!$class->isInterface()) {
  122.             $defaults $class->getDefaultProperties();
  123.             foreach ($class->getProperties(\ReflectionProperty::IS_PUBLIC \ReflectionProperty::IS_PROTECTED) as $p) {
  124.                 foreach ($p->getAttributes() as $a) {
  125.                     $attributes[] = [$a->getName(), (string) $a];
  126.                 }
  127.                 yield print_r($attributestrue);
  128.                 $attributes = [];
  129.                 yield $p->getDocComment();
  130.                 yield $p->isDefault() ? '<default>' '';
  131.                 yield $p->isPublic() ? 'public' 'protected';
  132.                 yield $p->isStatic() ? 'static' '';
  133.                 yield '$'.$p->name;
  134.                 yield print_r(isset($defaults[$p->name]) && !\is_object($defaults[$p->name]) ? $defaults[$p->name] : nulltrue);
  135.             }
  136.         }
  137.         $defined \Closure::bind(static function ($c) { return \defined($c); }, null$class->name);
  138.         foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC \ReflectionMethod::IS_PROTECTED) as $m) {
  139.             foreach ($m->getAttributes() as $a) {
  140.                 $attributes[] = [$a->getName(), (string) $a];
  141.             }
  142.             yield print_r($attributestrue);
  143.             $attributes = [];
  144.             $defaults = [];
  145.             foreach ($m->getParameters() as $p) {
  146.                 foreach ($p->getAttributes() as $a) {
  147.                     $attributes[] = [$a->getName(), (string) $a];
  148.                 }
  149.                 yield print_r($attributestrue);
  150.                 $attributes = [];
  151.                 if (!$p->isDefaultValueAvailable()) {
  152.                     $defaults[$p->name] = null;
  153.                     continue;
  154.                 }
  155.                 $defaults[$p->name] = (string) $p;
  156.             }
  157.             yield preg_replace('/^  @@.*/m'''$m);
  158.             yield print_r($defaultstrue);
  159.         }
  160.         if ($class->isAbstract() || $class->isInterface() || $class->isTrait()) {
  161.             return;
  162.         }
  163.         if (interface_exists(EventSubscriberInterface::class, false) && $class->isSubclassOf(EventSubscriberInterface::class)) {
  164.             yield EventSubscriberInterface::class;
  165.             yield print_r($class->name::getSubscribedEvents(), true);
  166.         }
  167.         if (interface_exists(MessageSubscriberInterface::class, false) && $class->isSubclassOf(MessageSubscriberInterface::class)) {
  168.             yield MessageSubscriberInterface::class;
  169.             foreach ($class->name::getHandledMessages() as $key => $value) {
  170.                 yield $key.print_r($valuetrue);
  171.             }
  172.         }
  173.         if (interface_exists(ServiceSubscriberInterface::class, false) && $class->isSubclassOf(ServiceSubscriberInterface::class)) {
  174.             yield ServiceSubscriberInterface::class;
  175.             yield print_r($class->name::getSubscribedServices(), true);
  176.         }
  177.     }
  178. }