123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- <?php
- /*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
- namespace Symfony\Component\Config\Resource;
- use Symfony\Component\EventDispatcher\EventSubscriberInterface;
- use Symfony\Component\Messenger\Handler\MessageSubscriberInterface;
- use Symfony\Contracts\Service\ServiceSubscriberInterface;
- /**
- * @author Nicolas Grekas <p@tchwork.com>
- *
- * @final
- */
- class ReflectionClassResource implements SelfCheckingResourceInterface
- {
- private $files = [];
- private $className;
- private $classReflector;
- private $excludedVendors = [];
- private $hash;
- public function __construct(\ReflectionClass $classReflector, array $excludedVendors = [])
- {
- $this->className = $classReflector->name;
- $this->classReflector = $classReflector;
- $this->excludedVendors = $excludedVendors;
- }
- /**
- * {@inheritdoc}
- */
- public function isFresh(int $timestamp): bool
- {
- if (null === $this->hash) {
- $this->hash = $this->computeHash();
- $this->loadFiles($this->classReflector);
- }
- foreach ($this->files as $file => $v) {
- if (false === $filemtime = @filemtime($file)) {
- return false;
- }
- if ($filemtime > $timestamp) {
- return $this->hash === $this->computeHash();
- }
- }
- return true;
- }
- public function __toString(): string
- {
- return 'reflection.'.$this->className;
- }
- /**
- * @internal
- */
- public function __sleep(): array
- {
- if (null === $this->hash) {
- $this->hash = $this->computeHash();
- $this->loadFiles($this->classReflector);
- }
- return ['files', 'className', 'hash'];
- }
- private function loadFiles(\ReflectionClass $class)
- {
- foreach ($class->getInterfaces() as $v) {
- $this->loadFiles($v);
- }
- do {
- $file = $class->getFileName();
- if (false !== $file && is_file($file)) {
- foreach ($this->excludedVendors as $vendor) {
- if (0 === strpos($file, $vendor) && false !== strpbrk(substr($file, \strlen($vendor), 1), '/'.\DIRECTORY_SEPARATOR)) {
- $file = false;
- break;
- }
- }
- if ($file) {
- $this->files[$file] = null;
- }
- }
- foreach ($class->getTraits() as $v) {
- $this->loadFiles($v);
- }
- } while ($class = $class->getParentClass());
- }
- private function computeHash(): string
- {
- if (null === $this->classReflector) {
- try {
- $this->classReflector = new \ReflectionClass($this->className);
- } catch (\ReflectionException $e) {
- // the class does not exist anymore
- return false;
- }
- }
- $hash = hash_init('md5');
- foreach ($this->generateSignature($this->classReflector) as $info) {
- hash_update($hash, $info);
- }
- return hash_final($hash);
- }
- private function generateSignature(\ReflectionClass $class): iterable
- {
- yield $class->getDocComment();
- yield (int) $class->isFinal();
- yield (int) $class->isAbstract();
- if ($class->isTrait()) {
- yield print_r(class_uses($class->name), true);
- } else {
- yield print_r(class_parents($class->name), true);
- yield print_r(class_implements($class->name), true);
- yield print_r($class->getConstants(), true);
- }
- if (!$class->isInterface()) {
- $defaults = $class->getDefaultProperties();
- foreach ($class->getProperties(\ReflectionProperty::IS_PUBLIC | \ReflectionProperty::IS_PROTECTED) as $p) {
- yield $p->getDocComment();
- yield $p->isDefault() ? '<default>' : '';
- yield $p->isPublic() ? 'public' : 'protected';
- yield $p->isStatic() ? 'static' : '';
- yield '$'.$p->name;
- yield print_r(isset($defaults[$p->name]) && !\is_object($defaults[$p->name]) ? $defaults[$p->name] : null, true);
- }
- }
- foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC | \ReflectionMethod::IS_PROTECTED) as $m) {
- $defaults = [];
- $parametersWithUndefinedConstants = [];
- foreach ($m->getParameters() as $p) {
- if (!$p->isDefaultValueAvailable()) {
- $defaults[$p->name] = null;
- continue;
- }
- if (!$p->isDefaultValueConstant() || \defined($p->getDefaultValueConstantName())) {
- $defaults[$p->name] = $p->getDefaultValue();
- continue;
- }
- $defaults[$p->name] = $p->getDefaultValueConstantName();
- $parametersWithUndefinedConstants[$p->name] = true;
- }
- if (!$parametersWithUndefinedConstants) {
- yield preg_replace('/^ @@.*/m', '', $m);
- } else {
- $t = $m->getReturnType();
- $stack = [
- $m->getDocComment(),
- $m->getName(),
- $m->isAbstract(),
- $m->isFinal(),
- $m->isStatic(),
- $m->isPublic(),
- $m->isPrivate(),
- $m->isProtected(),
- $m->returnsReference(),
- $t instanceof \ReflectionNamedType ? ((string) $t->allowsNull()).$t->getName() : (string) $t,
- ];
- foreach ($m->getParameters() as $p) {
- if (!isset($parametersWithUndefinedConstants[$p->name])) {
- $stack[] = (string) $p;
- } else {
- $t = $p->getType();
- $stack[] = $p->isOptional();
- $stack[] = $t instanceof \ReflectionNamedType ? ((string) $t->allowsNull()).$t->getName() : (string) $t;
- $stack[] = $p->isPassedByReference();
- $stack[] = $p->isVariadic();
- $stack[] = $p->getName();
- }
- }
- yield implode(',', $stack);
- }
- yield print_r($defaults, true);
- }
- if ($class->isAbstract() || $class->isInterface() || $class->isTrait()) {
- return;
- }
- if (interface_exists(EventSubscriberInterface::class, false) && $class->isSubclassOf(EventSubscriberInterface::class)) {
- yield EventSubscriberInterface::class;
- yield print_r($class->name::getSubscribedEvents(), true);
- }
- if (interface_exists(MessageSubscriberInterface::class, false) && $class->isSubclassOf(MessageSubscriberInterface::class)) {
- yield MessageSubscriberInterface::class;
- foreach ($class->name::getHandledMessages() as $key => $value) {
- yield $key.print_r($value, true);
- }
- }
- if (interface_exists(ServiceSubscriberInterface::class, false) && $class->isSubclassOf(ServiceSubscriberInterface::class)) {
- yield ServiceSubscriberInterface::class;
- yield print_r($class->name::getSubscribedServices(), true);
- }
- }
- }
|