|
11 | 11 |
|
12 | 12 | namespace Symfony\Component\DependencyInjection\Dumper;
|
13 | 13 |
|
| 14 | +use Symfony\Component\DependencyInjection\Argument\ClosureProxyArgument; |
14 | 15 | use Symfony\Component\DependencyInjection\Variable;
|
15 | 16 | use Symfony\Component\DependencyInjection\Definition;
|
16 | 17 | use Symfony\Component\DependencyInjection\ContainerBuilder;
|
@@ -61,6 +62,8 @@ class PhpDumper extends Dumper
|
61 | 62 | private $docStar;
|
62 | 63 | private $serviceIdToMethodNameMap;
|
63 | 64 | private $usedMethodNames;
|
| 65 | + private $classResources = array(); |
| 66 | + private $baseClass; |
64 | 67 |
|
65 | 68 | /**
|
66 | 69 | * @var \Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface
|
@@ -112,7 +115,9 @@ public function dump(array $options = array())
|
112 | 115 | 'debug' => true,
|
113 | 116 | ), $options);
|
114 | 117 |
|
| 118 | + $this->classResources = array(); |
115 | 119 | $this->initializeMethodNamesMap($options['base_class']);
|
| 120 | + $this->baseClass = $options['base_class']; |
116 | 121 |
|
117 | 122 | $this->docStar = $options['debug'] ? '*' : '';
|
118 | 123 |
|
@@ -159,6 +164,11 @@ public function dump(array $options = array())
|
159 | 164 | ;
|
160 | 165 | $this->targetDirRegex = null;
|
161 | 166 |
|
| 167 | + foreach ($this->classResources as $r) { |
| 168 | + $this->container->addClassResource($r); |
| 169 | + } |
| 170 | + $this->classResources = array(); |
| 171 | + |
162 | 172 | $unusedEnvs = array();
|
163 | 173 | foreach ($this->container->getEnvCounters() as $env => $use) {
|
164 | 174 | if (!$use) {
|
@@ -1398,6 +1408,25 @@ private function dumpValue($value, $interpolate = true)
|
1398 | 1408 | }
|
1399 | 1409 |
|
1400 | 1410 | return sprintf('new %s(%s)', $this->dumpLiteralClass($this->dumpValue($class)), implode(', ', $arguments));
|
| 1411 | + } elseif ($value instanceof ClosureProxyArgument) { |
| 1412 | + list($reference, $method) = $value->getValues(); |
| 1413 | + |
| 1414 | + if ('service_container' === (string) $reference) { |
| 1415 | + $class = $this->baseClass; |
| 1416 | + } elseif (!$this->hasDefinition((string) $reference) && ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $reference->getInvalidBehavior()) { |
| 1417 | + return 'null'; |
| 1418 | + } else { |
| 1419 | + $class = $this->container->findDefinition((string) $reference)->getClass(); |
| 1420 | + } |
| 1421 | + if (!isset($this->classResources[$class])) { |
| 1422 | + $this->classResources[$class] = new \ReflectionClass($class); |
| 1423 | + } |
| 1424 | + $r = $this->classResources[$class]->getMethod($method); |
| 1425 | + if (!$r->isPublic()) { |
| 1426 | + throw new InvalidArgumentException(sprintf('Cannot create closure-proxy for non-public method "%s" of the "%s".', $method, $reference)); |
| 1427 | + } |
| 1428 | + |
| 1429 | + return sprintf('/** @closure-proxy %s::%s */ function %s { return %s->%s; }', $class, $method, $this->generateSignature($r), $this->dumpValue($reference), $this->generateCall($r)); |
1401 | 1430 | } elseif ($value instanceof Variable) {
|
1402 | 1431 | return '$'.$value;
|
1403 | 1432 | } elseif ($value instanceof Reference) {
|
@@ -1654,4 +1683,97 @@ private function doExport($value)
|
1654 | 1683 |
|
1655 | 1684 | return $export;
|
1656 | 1685 | }
|
| 1686 | + |
| 1687 | + private function generateSignature(\ReflectionFunctionAbstract $r) |
| 1688 | + { |
| 1689 | + $signature = array(); |
| 1690 | + |
| 1691 | + foreach ($r->getParameters() as $p) { |
| 1692 | + $k = '$'.$p->name; |
| 1693 | + if (method_exists($p, 'isVariadic') && $p->isVariadic()) { |
| 1694 | + $k = '...'.$k; |
| 1695 | + } |
| 1696 | + if ($p->isPassedByReference()) { |
| 1697 | + $k = '&'.$k; |
| 1698 | + } |
| 1699 | + if (method_exists($p, 'getType')) { |
| 1700 | + if ($type = $p->getType()) { |
| 1701 | + $k = $this->generateTypeHint($type, $r).' '.$k; |
| 1702 | + } |
| 1703 | + } elseif (preg_match('/^(?:[^ ]++ ){4}([a-zA-Z_\x7F-\xFF][^ ]++)/', $p, $type)) { |
| 1704 | + $k = $type[1].' '.$k; |
| 1705 | + } |
| 1706 | + if ($type && $p->allowsNull()) { |
| 1707 | + $k = '?'.$k; |
| 1708 | + } |
| 1709 | + |
| 1710 | + try { |
| 1711 | + $k .= ' = '.$this->dumpValue($p->getDefaultValue(), false); |
| 1712 | + if ($type && $p->allowsNull() && null === $p->getDefaultValue()) { |
| 1713 | + $k = substr($k, 1); |
| 1714 | + } |
| 1715 | + } catch (\ReflectionException $e) { |
| 1716 | + if ($type && $p->allowsNull() && !class_exists('ReflectionNamedType', false)) { |
| 1717 | + $k .= ' = null'; |
| 1718 | + $k = substr($k, 1); |
| 1719 | + } |
| 1720 | + } |
| 1721 | + |
| 1722 | + $signature[] = $k; |
| 1723 | + } |
| 1724 | + |
| 1725 | + $signature = ($r->returnsReference() ? '&(' : '(').implode(', ', $signature).')'; |
| 1726 | + |
| 1727 | + if (method_exists($r, 'getReturnType') && $type = $r->getReturnType()) { |
| 1728 | + $signature .= ': '.($type->allowsNull() ? '?' : '').$this->generateTypeHint($type, $r); |
| 1729 | + } |
| 1730 | + |
| 1731 | + return $signature; |
| 1732 | + } |
| 1733 | + |
| 1734 | + private function generateCall(\ReflectionFunctionAbstract $r) |
| 1735 | + { |
| 1736 | + $call = array(); |
| 1737 | + |
| 1738 | + foreach ($r->getParameters() as $p) { |
| 1739 | + $k = '$'.$p->name; |
| 1740 | + if (method_exists($p, 'isVariadic') && $p->isVariadic()) { |
| 1741 | + $k = '...'.$k; |
| 1742 | + } |
| 1743 | + |
| 1744 | + $call[] = $k; |
| 1745 | + } |
| 1746 | + |
| 1747 | + return ($r->isClosure() ? '' : $r->name).'('.implode(', ', $call).')'; |
| 1748 | + } |
| 1749 | + |
| 1750 | + private function generateTypeHint($type, \ReflectionFunctionAbstract $r) |
| 1751 | + { |
| 1752 | + $type = $type instanceof \ReflectionNamedType ? $type->getName() : $type->__toString(); |
| 1753 | + |
| 1754 | + switch (strtolower($type)) { |
| 1755 | + case 'parent': |
| 1756 | + if ($r instanceof \ReflectionMethod) { |
| 1757 | + $type = $r->getDeclaringClass()->getParentClass()->name; |
| 1758 | + } |
| 1759 | + break; |
| 1760 | + |
| 1761 | + case 'self': |
| 1762 | + if ($r instanceof \ReflectionMethod) { |
| 1763 | + $type = $r->getDeclaringClass()->name; |
| 1764 | + } |
| 1765 | + break; |
| 1766 | + |
| 1767 | + case 'array': |
| 1768 | + case 'bool': |
| 1769 | + case 'float': |
| 1770 | + case 'int': |
| 1771 | + case 'iterable': |
| 1772 | + case 'string': |
| 1773 | + case 'void': |
| 1774 | + return $type; |
| 1775 | + } |
| 1776 | + |
| 1777 | + return '\\'.$type; |
| 1778 | + } |
1657 | 1779 | }
|
0 commit comments