Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 79cf689

Browse filesBrowse files
[DI][Config] Add & use ReflectionClassResource
1 parent b9b6ebd commit 79cf689
Copy full SHA for 79cf689

14 files changed

+235
-78
lines changed

‎src/Symfony/Component/Config/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Component/Config/CHANGELOG.md
+5Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
3.3.0
5+
-----
6+
7+
* added `ReflectionClassResource` class
8+
49
3.0.0
510
-----
611

+101Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Config\Resource;
13+
14+
/**
15+
* @author Nicolas Grekas <p@tchwork.com>
16+
*/
17+
class ReflectionClassResource implements SelfCheckingResourceInterface, \Serializable
18+
{
19+
private $file;
20+
private $className;
21+
private $classReflector;
22+
private $hash;
23+
24+
public function __construct(\ReflectionClass $classReflector)
25+
{
26+
$this->file = $classReflector->getFileName();
27+
$this->className = $classReflector->name;
28+
$this->classReflector = $classReflector;
29+
$this->hash = $this->computeHash();
30+
}
31+
32+
public function isFresh($timestamp)
33+
{
34+
if (false !== $this->file) {
35+
if (!file_exists($this->file)) {
36+
return false;
37+
}
38+
39+
if (@filemtime($this->file) <= $timestamp) {
40+
return true;
41+
}
42+
}
43+
44+
return $this->hash === $this->computeHash();
45+
}
46+
47+
public function __toString()
48+
{
49+
return 'reflection.'.$this->className;
50+
}
51+
52+
public function serialize()
53+
{
54+
return serialize(array($this->file, $this->className, $this->hash));
55+
}
56+
57+
public function unserialize($serialized)
58+
{
59+
list($this->file, $this->className, $this->hash) = unserialize($serialized);
60+
}
61+
62+
private function computeHash()
63+
{
64+
if (null === $this->classReflector) {
65+
try {
66+
$this->classReflector = new \ReflectionClass($this->className);
67+
} catch (\ReflectionException $e) {
68+
// the class does not exist anymore
69+
return false;
70+
}
71+
}
72+
73+
$class = $this->classReflector;
74+
$hash = hash_init('md5');
75+
76+
hash_update($hash, $class->getDocComment().$class->getModifiers());
77+
hash_update($hash, print_r(class_parents($class->name), true));
78+
hash_update($hash, print_r(class_implements($class->name), true));
79+
hash_update($hash, print_r($class->getConstants(), true));
80+
81+
$defaults = $class->getDefaultProperties();
82+
83+
foreach ($class->getProperties(\ReflectionProperty::IS_PUBLIC | \ReflectionProperty::IS_PROTECTED) as $r) {
84+
hash_update($hash, $r->getDocComment().$r);
85+
hash_update($hash, print_r($defaults[$r->name], true));
86+
}
87+
88+
foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC | \ReflectionMethod::IS_PROTECTED) as $r) {
89+
hash_update($hash, preg_replace('/^ @@.*/m', '', $r));
90+
91+
$defaults = array();
92+
foreach ($r->getParameters() as $r) {
93+
$defaults[$r->name] = $r->isDefaultValueAvailable() ? $r->getDefaultValue() : null;
94+
}
95+
96+
hash_update($hash, print_r($defaults, true));
97+
}
98+
99+
return hash_final($hash);
100+
}
101+
}
+57Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Config\Tests\Resource;
13+
14+
use Symfony\Component\Config\Resource\ReflectionClassResource;
15+
16+
class ReflectionClassResourceTest extends \PHPUnit_Framework_TestCase
17+
{
18+
public function testToString()
19+
{
20+
$res = new ReflectionClassResource(new \ReflectionClass('ErrorException'));
21+
22+
$this->assertSame('reflection.ErrorException', (string) $res);
23+
}
24+
25+
public function testSerializeUnserialize()
26+
{
27+
$res = new ReflectionClassResource(new \ReflectionClass('ErrorException'));
28+
$ser = unserialize(serialize($res));
29+
30+
$this->assertTrue($ser->isFresh(0));
31+
$this->assertEquals($res, $ser);
32+
}
33+
34+
public function testIsFresh()
35+
{
36+
$res = new ReflectionClassResource(new \ReflectionClass(__CLASS__));
37+
$mtime = filemtime(__FILE__);
38+
39+
$this->assertTrue($res->isFresh($mtime), '->isFresh() returns true if the resource has not changed in same second');
40+
$this->assertTrue($res->isFresh($mtime + 10), '->isFresh() returns true if the resource has not changed');
41+
$this->assertTrue($res->isFresh($mtime - 86400), '->isFresh() returns true if the resource has not changed');
42+
}
43+
44+
public function testIsFreshForDeletedResources()
45+
{
46+
$now = time();
47+
$tmp = sys_get_temp_dir().'/tmp.php';
48+
file_put_contents($tmp, '<?php class ReflectionClassResourceTestClass {}');
49+
require $tmp;
50+
51+
$res = new ReflectionClassResource(new \ReflectionClass('ReflectionClassResourceTestClass'));
52+
$this->assertTrue($res->isFresh($now));
53+
54+
unlink($tmp);
55+
$this->assertFalse($res->isFresh($now), '->isFresh() returns false if the resource does not exist');
56+
}
57+
}

‎src/Symfony/Component/DependencyInjection/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ CHANGELOG
44
3.3.0
55
-----
66

7+
* added method `ContainerBuilder::getReflectionClass()` for retrieving and tracking reflection class info
78
* added support for omitting the factory class name in a service definition if the definition class is set
89
* deprecated case insensitivity of service identifiers
910
* added "iterator" argument type for lazy iteration over a set of values and services

‎src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php
+10-42Lines changed: 10 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Component\DependencyInjection\Compiler;
1313

14+
use Symfony\Component\Config\Resource\ReflectionClassResource;
1415
use Symfony\Component\DependencyInjection\Config\AutowireServiceResource;
1516
use Symfony\Component\DependencyInjection\ContainerBuilder;
1617
use Symfony\Component\DependencyInjection\Definition;
@@ -24,7 +25,6 @@
2425
*/
2526
class AutowirePass extends AbstractRecursivePass implements CompilerPassInterface
2627
{
27-
private $reflectionClasses = array();
2828
private $definedTypes = array();
2929
private $types;
3030
private $ambiguousServiceTypes = array();
@@ -43,7 +43,6 @@ public function process(ContainerBuilder $container)
4343
spl_autoload_unregister($throwingAutoloader);
4444

4545
// Free memory and remove circular reference to container
46-
$this->reflectionClasses = array();
4746
$this->definedTypes = array();
4847
$this->types = null;
4948
$this->ambiguousServiceTypes = array();
@@ -56,9 +55,13 @@ public function process(ContainerBuilder $container)
5655
* @param \ReflectionClass $reflectionClass
5756
*
5857
* @return AutowireServiceResource
58+
*
59+
* @deprecated since version 3.3, to be removed in 4.0. Use ContainerBuilder::getReflectionClass() instead.
5960
*/
6061
public static function createResourceForClass(\ReflectionClass $reflectionClass)
6162
{
63+
@trigger_error('The '.__METHOD__.'() method is deprecated since version 3.3 and will be removed in 4.0. Use ContainerBuilder::getReflectionClass() instead.', E_USER_DEPRECATED);
64+
6265
$metadata = array();
6366

6467
foreach ($reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $reflectionMethod) {
@@ -79,14 +82,10 @@ protected function processValue($value, $isRoot = false)
7982
return parent::processValue($value, $isRoot);
8083
}
8184

82-
if (!$reflectionClass = $this->getReflectionClass($isRoot ? $this->currentId : null, $value)) {
85+
if (!$reflectionClass = $this->container->getReflectionClass($value->getClass())) {
8386
return parent::processValue($value, $isRoot);
8487
}
8588

86-
if ($this->container->isTrackingResources()) {
87-
$this->container->addResource(static::createResourceForClass($reflectionClass));
88-
}
89-
9089
$autowiredMethods = $this->getMethodsToAutowire($reflectionClass, $autowiredMethods);
9190
$methodCalls = $value->getMethodCalls();
9291

@@ -321,7 +320,7 @@ private function populateAvailableType($id, Definition $definition)
321320
$this->types[$type] = $id;
322321
}
323322

324-
if (!$reflectionClass = $this->getReflectionClass($id, $definition)) {
323+
if (!$reflectionClass = $this->container->getReflectionClass($definition->getClass())) {
325324
return;
326325
}
327326

@@ -414,40 +413,6 @@ private function createAutowiredDefinition(\ReflectionClass $typeHint)
414413
return new Reference($argumentId);
415414
}
416415

417-
/**
418-
* Retrieves the reflection class associated with the given service.
419-
*
420-
* @param string|null $id
421-
* @param Definition $definition
422-
*
423-
* @return \ReflectionClass|false
424-
*/
425-
private function getReflectionClass($id, Definition $definition)
426-
{
427-
if (null !== $id && isset($this->reflectionClasses[$id])) {
428-
return $this->reflectionClasses[$id];
429-
}
430-
431-
// Cannot use reflection if the class isn't set
432-
if (!$class = $definition->getClass()) {
433-
return false;
434-
}
435-
436-
$class = $this->container->getParameterBag()->resolveValue($class);
437-
438-
try {
439-
$reflector = new \ReflectionClass($class);
440-
} catch (\ReflectionException $e) {
441-
$reflector = false;
442-
}
443-
444-
if (null !== $id) {
445-
$this->reflectionClasses[$id] = $reflector;
446-
}
447-
448-
return $reflector;
449-
}
450-
451416
private function addServiceToAmbiguousType($id, $type)
452417
{
453418
// keep an array of all services matching this type
@@ -459,6 +424,9 @@ private function addServiceToAmbiguousType($id, $type)
459424
$this->ambiguousServiceTypes[$type][] = $id;
460425
}
461426

427+
/**
428+
* @deprecated since version 3.3, to be removed in 4.0.
429+
*/
462430
private static function getResourceMetadataForMethod(\ReflectionMethod $method)
463431
{
464432
$methodArgumentsMetadata = array();

‎src/Symfony/Component/DependencyInjection/Config/AutowireServiceResource.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Config/AutowireServiceResource.php
+5Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,14 @@
1111

1212
namespace Symfony\Component\DependencyInjection\Config;
1313

14+
@trigger_error('The '.__NAMESPACE__.'\AutowireServiceResource class is deprecated since version 3.3 and will be removed in 4.0. Use ContainerBuilder::getReflectionClass() instead.', E_USER_DEPRECATED);
15+
1416
use Symfony\Component\Config\Resource\SelfCheckingResourceInterface;
1517
use Symfony\Component\DependencyInjection\Compiler\AutowirePass;
1618

19+
/**
20+
* @deprecated since version 3.3, to be removed in 4.0. Use ContainerBuilder::getReflectionClass() instead.
21+
*/
1722
class AutowireServiceResource implements SelfCheckingResourceInterface, \Serializable
1823
{
1924
private $class;

‎src/Symfony/Component/DependencyInjection/ContainerBuilder.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/ContainerBuilder.php
+38-2Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
2727
use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag;
2828
use Symfony\Component\Config\Resource\FileResource;
29+
use Symfony\Component\Config\Resource\ReflectionClassResource;
2930
use Symfony\Component\Config\Resource\ResourceInterface;
3031
use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\InstantiatorInterface;
3132
use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\RealServiceInstantiator;
@@ -103,6 +104,11 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
103104
*/
104105
private $envCounters = array();
105106

107+
/**
108+
* @var \ReflectionClass[]
109+
*/
110+
private $classReflectors = array();
111+
106112
/**
107113
* Sets the track resources flag.
108114
*
@@ -278,6 +284,36 @@ public function addClassResource(\ReflectionClass $class)
278284
return $this;
279285
}
280286

287+
/**
288+
* Retrieves the requested reflection class and registers it for resource tracking.
289+
*
290+
* @param string $class
291+
*
292+
* @return \ReflectionClass|false
293+
*/
294+
public function getReflectionClass($class)
295+
{
296+
if (!$class = $this->getParameterBag()->resolveValue($class)) {
297+
return false;
298+
}
299+
300+
if (isset($this->classReflectors[$class])) {
301+
return $this->classReflectors[$class];
302+
}
303+
304+
try {
305+
$classReflector = new \ReflectionClass($class);
306+
307+
if ($this->trackResources) {
308+
$this->addResource(new ReflectionClassResource($classReflector));
309+
}
310+
} catch (\ReflectionException $e) {
311+
$classReflector = false;
312+
}
313+
314+
return $this->classReflectors[$class] = $classReflector;
315+
}
316+
281317
/**
282318
* Loads the configuration for an extension.
283319
*
@@ -571,8 +607,8 @@ public function compile()
571607
if (!$definition->isPublic()) {
572608
$this->privates[$id] = true;
573609
}
574-
if ($this->trackResources && $definition->isLazy() && ($class = $definition->getClass()) && class_exists($class)) {
575-
$this->addClassResource(new \ReflectionClass($class));
610+
if ($this->trackResources && $definition->isLazy()) {
611+
$this->getReflectionClass($definition->getClass());
576612
}
577613
}
578614

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.