Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature #21419 [DI][Config] Add & use ReflectionClassResource (nicola…
…s-grekas) This PR was merged into the 3.3-dev branch. Discussion ---------- [DI][Config] Add & use ReflectionClassResource | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | yes | Tests pass? | yes | Fixed tickets | #21079 | License | MIT | Doc PR | - With new changes comming to 3.3, we need a more generic reflection tracking logic than the one already managed by the autowiring subsystem. This PR adds a new ReflectionClassResource in the Config component, and a new ContainerBuilder::getReflectionClass() method in the DI one (for fetching+tracking reflection-related info). ReflectionClassResource tracks changes to any public or protected properties/method. PR updated and ready, best viewed [ignoring whitespaces](https://github.com/symfony/symfony/pull/21419/files?w=1). changelog: * added `ReflectionClassResource` class * added second `$exists` constructor argument to `ClassExistenceResource` - with a special mode that prevents fatal errors from happening when some parent class is broken (logic generalized from AutowiringPass) * made `ClassExistenceResource` also work with interfaces and traits * added `ContainerBuilder::getReflectionClass()` for retrieving and tracking reflection class info * deprecated `ContainerBuilder::getClassResource()`, use `ContainerBuilder::getReflectionClass()` or `ContainerBuilder::addObjectResource()` instead Commits ------- 37e4493 [DI][Config] Add & use ReflectionClassResource
- Loading branch information
Showing
26 changed files
with
616 additions
and
176 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
171 changes: 171 additions & 0 deletions
171
src/Symfony/Component/Config/Resource/ReflectionClassResource.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
<?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; | ||
|
||
/** | ||
* @author Nicolas Grekas <p@tchwork.com> | ||
*/ | ||
class ReflectionClassResource implements SelfCheckingResourceInterface, \Serializable | ||
{ | ||
private $files = array(); | ||
private $className; | ||
private $classReflector; | ||
private $hash; | ||
|
||
public function __construct(\ReflectionClass $classReflector) | ||
{ | ||
$this->className = $classReflector->name; | ||
$this->classReflector = $classReflector; | ||
} | ||
|
||
public function isFresh($timestamp) | ||
{ | ||
if (null === $this->hash) { | ||
$this->hash = $this->computeHash(); | ||
$this->loadFiles($this->classReflector); | ||
} | ||
|
||
foreach ($this->files as $file => $v) { | ||
if (!file_exists($file)) { | ||
return false; | ||
} | ||
|
||
if (@filemtime($file) > $timestamp) { | ||
return $this->hash === $this->computeHash(); | ||
} | ||
} | ||
|
||
return true; | ||
} | ||
|
||
public function __toString() | ||
{ | ||
return 'reflection.'.$this->className; | ||
} | ||
|
||
public function serialize() | ||
{ | ||
if (null === $this->hash) { | ||
$this->hash = $this->computeHash(); | ||
$this->loadFiles($this->classReflector); | ||
} | ||
|
||
return serialize(array($this->files, $this->className, $this->hash)); | ||
} | ||
|
||
public function unserialize($serialized) | ||
{ | ||
list($this->files, $this->className, $this->hash) = unserialize($serialized); | ||
} | ||
|
||
private function loadFiles(\ReflectionClass $class) | ||
{ | ||
foreach ($class->getInterfaces() as $v) { | ||
$this->loadFiles($v); | ||
} | ||
do { | ||
$file = $class->getFileName(); | ||
if (false !== $file && file_exists($file)) { | ||
$this->files[$file] = null; | ||
} | ||
foreach ($class->getTraits() as $v) { | ||
$this->loadFiles($v); | ||
} | ||
} while ($class = $class->getParentClass()); | ||
} | ||
|
||
private function computeHash() | ||
{ | ||
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) | ||
{ | ||
yield $class->getDocComment().$class->getModifiers(); | ||
|
||
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().$p; | ||
yield print_r($defaults[$p->name], true); | ||
} | ||
} | ||
|
||
if (defined('HHVM_VERSION')) { | ||
foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC | \ReflectionMethod::IS_PROTECTED) as $m) { | ||
// workaround HHVM bug with variadics, see https://github.com/facebook/hhvm/issues/5762 | ||
yield preg_replace('/^ @@.*/m', '', new ReflectionMethodHhvmWrapper($m->class, $m->name)); | ||
} | ||
} else { | ||
foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC | \ReflectionMethod::IS_PROTECTED) as $m) { | ||
yield preg_replace('/^ @@.*/m', '', $m); | ||
|
||
$defaults = array(); | ||
foreach ($m->getParameters() as $p) { | ||
$defaults[$p->name] = $p->isDefaultValueAvailable() ? $p->getDefaultValue() : null; | ||
} | ||
yield print_r($defaults, true); | ||
} | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* @internal | ||
*/ | ||
class ReflectionMethodHhvmWrapper extends \ReflectionMethod | ||
{ | ||
public function getParameters() | ||
{ | ||
$params = array(); | ||
|
||
foreach (parent::getParameters() as $i => $p) { | ||
$params[] = new ReflectionParameterHhvmWrapper(array($this->class, $this->name), $i); | ||
} | ||
|
||
return $params; | ||
} | ||
} | ||
|
||
/** | ||
* @internal | ||
*/ | ||
class ReflectionParameterHhvmWrapper extends \ReflectionParameter | ||
{ | ||
public function getDefaultValue() | ||
{ | ||
return array($this->isVariadic(), $this->isDefaultValueAvailable() ? parent::getDefaultValue() : null); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.