|
11 | 11 |
|
12 | 12 | namespace Symfony\Component\DependencyInjection\Dumper;
|
13 | 13 |
|
| 14 | +use Symfony\Component\DependencyInjection\Argument\ClosureProxyArgument; |
14 | 15 | use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
|
15 | 16 | use Symfony\Component\DependencyInjection\Variable;
|
16 | 17 | use Symfony\Component\DependencyInjection\Definition;
|
@@ -62,6 +63,8 @@ class PhpDumper extends Dumper
|
62 | 63 | private $docStar;
|
63 | 64 | private $serviceIdToMethodNameMap;
|
64 | 65 | private $usedMethodNames;
|
| 66 | + private $classResources = array(); |
| 67 | + private $baseClass; |
65 | 68 |
|
66 | 69 | /**
|
67 | 70 | * @var \Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface
|
@@ -117,7 +120,9 @@ public function dump(array $options = array())
|
117 | 120 | 'debug' => true,
|
118 | 121 | ), $options);
|
119 | 122 |
|
| 123 | + $this->classResources = array(); |
120 | 124 | $this->initializeMethodNamesMap($options['base_class']);
|
| 125 | + $this->baseClass = $options['base_class']; |
121 | 126 |
|
122 | 127 | $this->docStar = $options['debug'] ? '*' : '';
|
123 | 128 |
|
@@ -164,6 +169,11 @@ public function dump(array $options = array())
|
164 | 169 | ;
|
165 | 170 | $this->targetDirRegex = null;
|
166 | 171 |
|
| 172 | + foreach ($this->classResources as $r) { |
| 173 | + $this->container->addClassResource($r); |
| 174 | + } |
| 175 | + $this->classResources = array(); |
| 176 | + |
167 | 177 | $unusedEnvs = array();
|
168 | 178 | foreach ($this->container->getEnvCounters() as $env => $use) {
|
169 | 179 | if (!$use) {
|
@@ -1418,6 +1428,25 @@ private function dumpValue($value, $interpolate = true)
|
1418 | 1428 | }
|
1419 | 1429 |
|
1420 | 1430 | return sprintf('new %s(%s)', $this->dumpLiteralClass($this->dumpValue($class)), implode(', ', $arguments));
|
| 1431 | + } elseif ($value instanceof ClosureProxyArgument) { |
| 1432 | + list($reference, $method) = $value->getValues(); |
| 1433 | + |
| 1434 | + if ('service_container' === (string) $reference) { |
| 1435 | + $class = $this->baseClass; |
| 1436 | + } elseif (!$this->container->hasDefinition((string) $reference) && ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $reference->getInvalidBehavior()) { |
| 1437 | + return 'null'; |
| 1438 | + } else { |
| 1439 | + $class = $this->container->findDefinition((string) $reference)->getClass(); |
| 1440 | + } |
| 1441 | + if (!isset($this->classResources[$class])) { |
| 1442 | + $this->classResources[$class] = new \ReflectionClass($class); |
| 1443 | + } |
| 1444 | + $r = $this->classResources[$class]->getMethod($method); |
| 1445 | + if (!$r->isPublic()) { |
| 1446 | + throw new InvalidArgumentException(sprintf('Cannot create closure-proxy for non-public method "%s" of the "%s".', $method, $reference)); |
| 1447 | + } |
| 1448 | + |
| 1449 | + return sprintf("/** @closure-proxy %s::%s */ function %s {\n return %s->%s;\n }", $class, $method, $this->generateSignature($r), $this->dumpValue($reference), $this->generateCall($r)); |
1421 | 1450 | } elseif ($value instanceof Variable) {
|
1422 | 1451 | return '$'.$value;
|
1423 | 1452 | } elseif ($value instanceof Reference) {
|
@@ -1674,4 +1703,95 @@ private function doExport($value)
|
1674 | 1703 |
|
1675 | 1704 | return $export;
|
1676 | 1705 | }
|
| 1706 | + |
| 1707 | + private function generateSignature(\ReflectionFunctionAbstract $r) |
| 1708 | + { |
| 1709 | + $signature = array(); |
| 1710 | + |
| 1711 | + foreach ($r->getParameters() as $p) { |
| 1712 | + $k = '$'.$p->name; |
| 1713 | + if (method_exists($p, 'isVariadic') && $p->isVariadic()) { |
| 1714 | + $k = '...'.$k; |
| 1715 | + } |
| 1716 | + if ($p->isPassedByReference()) { |
| 1717 | + $k = '&'.$k; |
| 1718 | + } |
| 1719 | + if (method_exists($p, 'getType')) { |
| 1720 | + $type = $p->getType(); |
| 1721 | + } elseif (preg_match('/^(?:[^ ]++ ){4}([a-zA-Z_\x7F-\xFF][^ ]++)/', $p, $type)) { |
| 1722 | + $type = $type[1]; |
| 1723 | + } |
| 1724 | + if ($type && $type = $this->generateTypeHint($type, $r)) { |
| 1725 | + $k = $type.' '.$k; |
| 1726 | + } |
| 1727 | + if ($type && $p->allowsNull()) { |
| 1728 | + $k = '?'.$k; |
| 1729 | + } |
| 1730 | + |
| 1731 | + try { |
| 1732 | + $k .= ' = '.$this->dumpValue($p->getDefaultValue(), false); |
| 1733 | + if ($type && $p->allowsNull() && null === $p->getDefaultValue()) { |
| 1734 | + $k = substr($k, 1); |
| 1735 | + } |
| 1736 | + } catch (\ReflectionException $e) { |
| 1737 | + if ($type && $p->allowsNull() && !class_exists('ReflectionNamedType', false)) { |
| 1738 | + $k .= ' = null'; |
| 1739 | + $k = substr($k, 1); |
| 1740 | + } |
| 1741 | + } |
| 1742 | + |
| 1743 | + $signature[] = $k; |
| 1744 | + } |
| 1745 | + |
| 1746 | + return ($r->returnsReference() ? '&(' : '(').implode(', ', $signature).')'; |
| 1747 | + } |
| 1748 | + |
| 1749 | + private function generateCall(\ReflectionFunctionAbstract $r) |
| 1750 | + { |
| 1751 | + $call = array(); |
| 1752 | + |
| 1753 | + foreach ($r->getParameters() as $p) { |
| 1754 | + $k = '$'.$p->name; |
| 1755 | + if (method_exists($p, 'isVariadic') && $p->isVariadic()) { |
| 1756 | + $k = '...'.$k; |
| 1757 | + } |
| 1758 | + |
| 1759 | + $call[] = $k; |
| 1760 | + } |
| 1761 | + |
| 1762 | + return ($r->isClosure() ? '' : $r->name).'('.implode(', ', $call).')'; |
| 1763 | + } |
| 1764 | + |
| 1765 | + private function generateTypeHint($type, \ReflectionFunctionAbstract $r) |
| 1766 | + { |
| 1767 | + if (is_string($type)) { |
| 1768 | + $name = $type; |
| 1769 | + |
| 1770 | + if ('callable' === $name || 'array' === $name) { |
| 1771 | + return $name; |
| 1772 | + } |
| 1773 | + } else { |
| 1774 | + $name = $type instanceof \ReflectionNamedType ? $type->getName() : $type->__toString(); |
| 1775 | + |
| 1776 | + if ($type->isBuiltin()) { |
| 1777 | + return $name; |
| 1778 | + } |
| 1779 | + } |
| 1780 | + $lcName = strtolower($name); |
| 1781 | + |
| 1782 | + if ('self' !== $lcName && 'parent' !== $lcName) { |
| 1783 | + return '\\'.$name; |
| 1784 | + } |
| 1785 | + if (!$r instanceof \ReflectionMethod) { |
| 1786 | + return null; |
| 1787 | + } |
| 1788 | + if ('self' === $lcName) { |
| 1789 | + return '\\'.$r->getDeclaringClass()->name; |
| 1790 | + } |
| 1791 | + if (!$parent = $r->getDeclaringClass()->getParentClass()) { |
| 1792 | + return null; |
| 1793 | + } |
| 1794 | + |
| 1795 | + return '\\'.$parent->name; |
| 1796 | + } |
1677 | 1797 | }
|
0 commit comments