4 * This file is part of the Symfony package.
6 * (c) Fabien Potencier <fabien@symfony.com>
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Symfony\Component\Config\Resource;
14 use Symfony\Component\DependencyInjection\ServiceSubscriberInterface;
15 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
18 * @author Nicolas Grekas <p@tchwork.com>
20 class ReflectionClassResource implements SelfCheckingResourceInterface, \Serializable
22 private $files = array();
24 private $classReflector;
25 private $excludedVendors = array();
28 public function __construct(\ReflectionClass $classReflector, $excludedVendors = array())
30 $this->className = $classReflector->name;
31 $this->classReflector = $classReflector;
32 $this->excludedVendors = $excludedVendors;
35 public function isFresh($timestamp)
37 if (null === $this->hash) {
38 $this->hash = $this->computeHash();
39 $this->loadFiles($this->classReflector);
42 foreach ($this->files as $file => $v) {
43 if (false === $filemtime = @filemtime($file)) {
47 if ($filemtime > $timestamp) {
48 return $this->hash === $this->computeHash();
55 public function __toString()
57 return 'reflection.'.$this->className;
60 public function serialize()
62 if (null === $this->hash) {
63 $this->hash = $this->computeHash();
64 $this->loadFiles($this->classReflector);
67 return serialize(array($this->files, $this->className, $this->hash));
70 public function unserialize($serialized)
72 list($this->files, $this->className, $this->hash) = unserialize($serialized);
75 private function loadFiles(\ReflectionClass $class)
77 foreach ($class->getInterfaces() as $v) {
81 $file = $class->getFileName();
82 if (false !== $file && file_exists($file)) {
83 foreach ($this->excludedVendors as $vendor) {
84 if (0 === strpos($file, $vendor) && false !== strpbrk(substr($file, \strlen($vendor), 1), '/'.\DIRECTORY_SEPARATOR)) {
90 $this->files[$file] = null;
93 foreach ($class->getTraits() as $v) {
96 } while ($class = $class->getParentClass());
99 private function computeHash()
101 if (null === $this->classReflector) {
103 $this->classReflector = new \ReflectionClass($this->className);
104 } catch (\ReflectionException $e) {
105 // the class does not exist anymore
109 $hash = hash_init('md5');
111 foreach ($this->generateSignature($this->classReflector) as $info) {
112 hash_update($hash, $info);
115 return hash_final($hash);
118 private function generateSignature(\ReflectionClass $class)
120 yield $class->getDocComment();
121 yield (int) $class->isFinal();
122 yield (int) $class->isAbstract();
124 if ($class->isTrait()) {
125 yield print_r(class_uses($class->name), true);
127 yield print_r(class_parents($class->name), true);
128 yield print_r(class_implements($class->name), true);
129 yield print_r($class->getConstants(), true);
132 if (!$class->isInterface()) {
133 $defaults = $class->getDefaultProperties();
135 foreach ($class->getProperties(\ReflectionProperty::IS_PUBLIC | \ReflectionProperty::IS_PROTECTED) as $p) {
136 yield $p->getDocComment().$p;
137 yield print_r($defaults[$p->name], true);
141 if (\defined('HHVM_VERSION')) {
142 foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC | \ReflectionMethod::IS_PROTECTED) as $m) {
143 // workaround HHVM bug with variadics, see https://github.com/facebook/hhvm/issues/5762
144 yield preg_replace('/^ @@.*/m', '', new ReflectionMethodHhvmWrapper($m->class, $m->name));
147 foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC | \ReflectionMethod::IS_PROTECTED) as $m) {
148 yield preg_replace('/^ @@.*/m', '', $m);
151 foreach ($m->getParameters() as $p) {
152 $defaults[$p->name] = $p->isDefaultValueAvailable() ? $p->getDefaultValue() : null;
154 yield print_r($defaults, true);
158 if ($class->isAbstract() || $class->isInterface() || $class->isTrait()) {
162 if (interface_exists(EventSubscriberInterface::class, false) && $class->isSubclassOf(EventSubscriberInterface::class)) {
163 yield EventSubscriberInterface::class;
164 yield print_r(\call_user_func(array($class->name, 'getSubscribedEvents')), true);
167 if (interface_exists(ServiceSubscriberInterface::class, false) && $class->isSubclassOf(ServiceSubscriberInterface::class)) {
168 yield ServiceSubscriberInterface::class;
169 yield print_r(\call_user_func(array($class->name, 'getSubscribedServices')), true);
177 class ReflectionMethodHhvmWrapper extends \ReflectionMethod
179 public function getParameters()
183 foreach (parent::getParameters() as $i => $p) {
184 $params[] = new ReflectionParameterHhvmWrapper(array($this->class, $this->name), $i);
194 class ReflectionParameterHhvmWrapper extends \ReflectionParameter
196 public function getDefaultValue()
198 return array($this->isVariadic(), $this->isDefaultValueAvailable() ? parent::getDefaultValue() : null);