PluginProbe
Packeta / 1.6.1
Packeta v1.6.1
2.3.2 2.3.1 trunk 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.3.0 1.3.1 1.3.2 1.4 1.4.1 1.4.2 1.4.3 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 All 56 releases
packeta / deps / nette / php-generator / src / PhpGenerator / Printer.php

Printer.php in Packeta 1.6.1, at deps/nette/php-generator/src/PhpGenerator/Printer.php

191 lines 11.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * This file is part of the Nette Framework (https://nette.org)
5 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
6 */
7 declare (strict_types=1);
8 namespace Packetery\Nette\PhpGenerator;
9
10 use Packetery\Nette;
11 use Packetery\Nette\Utils\Strings;
12 /**
13 * Generates PHP code.
14 */
15 class Printer
16 {
17 use \Packetery\Nette\SmartObject;
18 /** @var string */
19 protected $indentation = "\t";
20 /** @var int */
21 protected $linesBetweenProperties = 0;
22 /** @var int */
23 protected $linesBetweenMethods = 2;
24 /** @var string */
25 protected $returnTypeColon = ': ';
26 /** @var bool */
27 private $resolveTypes = \true;
28 public function printFunction(GlobalFunction $function, PhpNamespace $namespace = null) : string
29 {
30 $line = 'function ' . ($function->getReturnReference() ? '&' : '') . $function->getName();
31 $returnType = $this->printReturnType($function, $namespace);
32 return Helpers::formatDocComment($function->getComment() . "\n") . self::printAttributes($function->getAttributes(), $namespace) . $line . $this->printParameters($function, $namespace, \strlen($line) + \strlen($returnType) + 2) . $returnType . "\n{\n" . $this->indent(\ltrim(\rtrim($function->getBody()) . "\n")) . "}\n";
33 }
34 public function printClosure(Closure $closure) : string
35 {
36 $uses = [];
37 foreach ($closure->getUses() as $param) {
38 $uses[] = ($param->isReference() ? '&' : '') . '$' . $param->getName();
39 }
40 $useStr = \strlen($tmp = \implode(', ', $uses)) > (new Dumper())->wrapLength && \count($uses) > 1 ? "\n" . $this->indentation . \implode(",\n" . $this->indentation, $uses) . "\n" : $tmp;
41 return self::printAttributes($closure->getAttributes(), null, \true) . 'function ' . ($closure->getReturnReference() ? '&' : '') . $this->printParameters($closure, null) . ($uses ? " use ({$useStr})" : '') . $this->printReturnType($closure, null) . " {\n" . $this->indent(\ltrim(\rtrim($closure->getBody()) . "\n")) . '}';
42 }
43 public function printArrowFunction(Closure $closure) : string
44 {
45 foreach ($closure->getUses() as $use) {
46 if ($use->isReference()) {
47 throw new \Packetery\Nette\InvalidArgumentException('Arrow function cannot bind variables by-reference.');
48 }
49 }
50 return self::printAttributes($closure->getAttributes(), null) . 'fn' . ($closure->getReturnReference() ? '&' : '') . $this->printParameters($closure, null) . $this->printReturnType($closure, null) . ' => ' . \trim($closure->getBody()) . ';';
51 }
52 public function printMethod(Method $method, PhpNamespace $namespace = null) : string
53 {
54 $method->validate();
55 $line = ($method->isAbstract() ? 'abstract ' : '') . ($method->isFinal() ? 'final ' : '') . ($method->getVisibility() ? $method->getVisibility() . ' ' : '') . ($method->isStatic() ? 'static ' : '') . 'function ' . ($method->getReturnReference() ? '&' : '') . $method->getName();
56 $returnType = $this->printReturnType($method, $namespace);
57 return Helpers::formatDocComment($method->getComment() . "\n") . self::printAttributes($method->getAttributes(), $namespace) . $line . ($params = $this->printParameters($method, $namespace, \strlen($line) + \strlen($returnType) + \strlen($this->indentation) + 2)) . $returnType . ($method->isAbstract() || $method->getBody() === null ? ";\n" : (\strpos($params, "\n") === \false ? "\n" : ' ') . "{\n" . $this->indent(\ltrim(\rtrim($method->getBody()) . "\n")) . "}\n");
58 }
59 public function printClass(ClassType $class, PhpNamespace $namespace = null) : string
60 {
61 $class->validate();
62 $resolver = $this->resolveTypes && $namespace ? [$namespace, 'unresolveUnionType'] : function ($s) {
63 return $s;
64 };
65 $traits = [];
66 foreach ($class->getTraitResolutions() as $trait => $resolutions) {
67 $traits[] = 'use ' . $resolver($trait) . ($resolutions ? " {\n" . $this->indentation . \implode(";\n" . $this->indentation, $resolutions) . ";\n}\n" : ";\n");
68 }
69 $consts = [];
70 foreach ($class->getConstants() as $const) {
71 $def = ($const->getVisibility() ? $const->getVisibility() . ' ' : '') . 'const ' . $const->getName() . ' = ';
72 $consts[] = Helpers::formatDocComment((string) $const->getComment()) . self::printAttributes($const->getAttributes(), $namespace) . $def . $this->dump($const->getValue(), \strlen($def)) . ";\n";
73 }
74 $properties = [];
75 foreach ($class->getProperties() as $property) {
76 $type = $property->getType();
77 $def = ($property->getVisibility() ?: 'public') . ($property->isStatic() ? ' static' : '') . ' ' . \ltrim($this->printType($type, $property->isNullable(), $namespace) . ' ') . '$' . $property->getName();
78 $properties[] = Helpers::formatDocComment((string) $property->getComment()) . self::printAttributes($property->getAttributes(), $namespace) . $def . ($property->getValue() === null && !$property->isInitialized() ? '' : ' = ' . $this->dump($property->getValue(), \strlen($def) + 3)) . ";\n";
79 }
80 $methods = [];
81 foreach ($class->getMethods() as $method) {
82 $methods[] = $this->printMethod($method, $namespace);
83 }
84 $members = \array_filter([\implode('', $traits), $this->joinProperties($consts), $this->joinProperties($properties), ($methods && $properties ? \str_repeat("\n", $this->linesBetweenMethods - 1) : '') . \implode(\str_repeat("\n", $this->linesBetweenMethods), $methods)]);
85 return Strings::normalize(Helpers::formatDocComment($class->getComment() . "\n") . self::printAttributes($class->getAttributes(), $namespace) . ($class->isAbstract() ? 'abstract ' : '') . ($class->isFinal() ? 'final ' : '') . ($class->getName() ? $class->getType() . ' ' . $class->getName() . ' ' : '') . ($class->getExtends() ? 'extends ' . \implode(', ', \array_map($resolver, (array) $class->getExtends())) . ' ' : '') . ($class->getImplements() ? 'implements ' . \implode(', ', \array_map($resolver, $class->getImplements())) . ' ' : '') . ($class->getName() ? "\n" : '') . "{\n" . ($members ? $this->indent(\implode("\n", $members)) : '') . '}') . ($class->getName() ? "\n" : '');
86 }
87 public function printNamespace(PhpNamespace $namespace) : string
88 {
89 $name = $namespace->getName();
90 $uses = $this->printUses($namespace);
91 $classes = [];
92 foreach ($namespace->getClasses() as $class) {
93 $classes[] = $this->printClass($class, $namespace);
94 }
95 $body = ($uses ? $uses . "\n\n" : '') . \implode("\n", $classes);
96 if ($namespace->hasBracketedSyntax()) {
97 return 'namespace' . ($name ? " {$name}" : '') . "\n{\n" . $this->indent($body) . "}\n";
98 } else {
99 return ($name ? "namespace {$name};\n\n" : '') . $body;
100 }
101 }
102 public function printFile(PhpFile $file) : string
103 {
104 $namespaces = [];
105 foreach ($file->getNamespaces() as $namespace) {
106 $namespaces[] = $this->printNamespace($namespace);
107 }
108 return Strings::normalize("<?php\n" . ($file->getComment() ? "\n" . Helpers::formatDocComment($file->getComment() . "\n") : '') . "\n" . ($file->hasStrictTypes() ? "declare(strict_types=1);\n\n" : '') . \implode("\n\n", $namespaces)) . "\n";
109 }
110 /** @return static */
111 public function setTypeResolving(bool $state = \true) : self
112 {
113 $this->resolveTypes = $state;
114 return $this;
115 }
116 protected function indent(string $s) : string
117 {
118 $s = \str_replace("\t", $this->indentation, $s);
119 return Strings::indent($s, 1, $this->indentation);
120 }
121 protected function dump($var, int $column = 0) : string
122 {
123 return (new Dumper())->dump($var, $column);
124 }
125 protected function printUses(PhpNamespace $namespace) : string
126 {
127 $name = $namespace->getName();
128 $uses = [];
129 foreach ($namespace->getUses() as $alias => $original) {
130 if ($original !== ($name ? $name . '\\' . $alias : $alias)) {
131 $uses[] = $alias === $original || \substr($original, -(\strlen($alias) + 1)) === '\\' . $alias ? "use {$original};" : "use {$original} as {$alias};";
132 }
133 }
134 return \implode("\n", $uses);
135 }
136 /**
137 * @param Closure|GlobalFunction|Method $function
138 */
139 public function printParameters($function, PhpNamespace $namespace = null, int $column = 0) : string
140 {
141 $params = [];
142 $list = $function->getParameters();
143 $special = \false;
144 foreach ($list as $param) {
145 $variadic = $function->isVariadic() && $param === \end($list);
146 $type = $param->getType();
147 $promoted = $param instanceof PromotedParameter ? $param : null;
148 $params[] = ($promoted ? Helpers::formatDocComment((string) $promoted->getComment()) : '') . ($attrs = self::printAttributes($param->getAttributes(), $namespace, \true)) . ($promoted ? ($promoted->getVisibility() ?: 'public') . ' ' : '') . \ltrim($this->printType($type, $param->isNullable(), $namespace) . ' ') . ($param->isReference() ? '&' : '') . ($variadic ? '...' : '') . '$' . $param->getName() . ($param->hasDefaultValue() && !$variadic ? ' = ' . $this->dump($param->getDefaultValue()) : '');
149 $special = $special || $promoted || $attrs;
150 }
151 $line = \implode(', ', $params);
152 return \count($params) > 1 && ($special || \strlen($line) + $column > (new Dumper())->wrapLength) ? "(\n" . $this->indent(\implode(",\n", $params)) . ($special ? ',' : '') . "\n)" : "({$line})";
153 }
154 public function printType(?string $type, bool $nullable = \false, PhpNamespace $namespace = null) : string
155 {
156 if ($type === null) {
157 return '';
158 }
159 if ($this->resolveTypes && $namespace) {
160 $type = $namespace->unresolveUnionType($type);
161 }
162 if ($nullable && \strcasecmp($type, 'mixed')) {
163 $type = \strpos($type, '|') === \false ? '?' . $type : $type . '|null';
164 }
165 return $type;
166 }
167 /**
168 * @param Closure|GlobalFunction|Method $function
169 */
170 private function printReturnType($function, ?PhpNamespace $namespace) : string
171 {
172 return ($tmp = $this->printType($function->getReturnType(), $function->isReturnNullable(), $namespace)) ? $this->returnTypeColon . $tmp : '';
173 }
174 private function printAttributes(array $attrs, ?PhpNamespace $namespace, bool $inline = \false) : string
175 {
176 if (!$attrs) {
177 return '';
178 }
179 $items = [];
180 foreach ($attrs as $attr) {
181 $args = (new Dumper())->format('...?:', $attr->getArguments());
182 $items[] = $this->printType($attr->getName(), \false, $namespace) . ($args ? "({$args})" : '');
183 }
184 return $inline ? '#[' . \implode(', ', $items) . '] ' : '#[' . \implode("]\n#[", $items) . "]\n";
185 }
186 private function joinProperties(array $props)
187 {
188 return $this->linesBetweenProperties ? \implode(\str_repeat("\n", $this->linesBetweenProperties), $props) : \preg_replace('#^(\\w.*\\n)\\n(?=\\w.*;)#m', '$1', \implode("\n", $props));
189 }
190 }
191