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 12namespace Symfony\Component\DependencyInjection\Compiler; 13 14use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; 15 16/** 17 * Compiler Pass Configuration. 18 * 19 * This class has a default configuration embedded. 20 * 21 * @author Johannes M. Schmitt <schmittjoh@gmail.com> 22 */ 23class PassConfig 24{ 25 public const TYPE_AFTER_REMOVING = 'afterRemoving'; 26 public const TYPE_BEFORE_OPTIMIZATION = 'beforeOptimization'; 27 public const TYPE_BEFORE_REMOVING = 'beforeRemoving'; 28 public const TYPE_OPTIMIZE = 'optimization'; 29 public const TYPE_REMOVE = 'removing'; 30 31 private $mergePass; 32 private $afterRemovingPasses = []; 33 private $beforeOptimizationPasses = []; 34 private $beforeRemovingPasses = []; 35 private $optimizationPasses; 36 private $removingPasses; 37 38 public function __construct() 39 { 40 $this->mergePass = new MergeExtensionConfigurationPass(); 41 42 $this->beforeOptimizationPasses = [ 43 100 => [ 44 new ResolveClassPass(), 45 new ResolveInstanceofConditionalsPass(), 46 new RegisterEnvVarProcessorsPass(), 47 ], 48 -1000 => [new ExtensionCompilerPass()], 49 ]; 50 51 $this->optimizationPasses = [[ 52 new ValidateEnvPlaceholdersPass(), 53 new ResolveChildDefinitionsPass(), 54 new RegisterServiceSubscribersPass(), 55 new ResolveParameterPlaceHoldersPass(false, false), 56 new ResolveFactoryClassPass(), 57 new ResolveNamedArgumentsPass(), 58 new AutowireRequiredMethodsPass(), 59 new ResolveBindingsPass(), 60 new ServiceLocatorTagPass(), 61 new DecoratorServicePass(), 62 new CheckDefinitionValidityPass(), 63 new AutowirePass(false), 64 new ResolveTaggedIteratorArgumentPass(), 65 new ResolveServiceSubscribersPass(), 66 new ResolveReferencesToAliasesPass(), 67 new ResolveInvalidReferencesPass(), 68 new AnalyzeServiceReferencesPass(true), 69 new CheckCircularReferencesPass(), 70 new CheckReferenceValidityPass(), 71 new CheckArgumentsValidityPass(false), 72 ]]; 73 74 $this->beforeRemovingPasses = [ 75 -100 => [ 76 new ResolvePrivatesPass(), 77 ], 78 ]; 79 80 $this->removingPasses = [[ 81 new RemovePrivateAliasesPass(), 82 new ReplaceAliasByActualDefinitionPass(), 83 new RemoveAbstractDefinitionsPass(), 84 new RemoveUnusedDefinitionsPass(), 85 new AnalyzeServiceReferencesPass(), 86 new CheckExceptionOnInvalidReferenceBehaviorPass(), 87 new InlineServiceDefinitionsPass(new AnalyzeServiceReferencesPass()), 88 new AnalyzeServiceReferencesPass(), 89 new DefinitionErrorExceptionPass(), 90 ]]; 91 92 $this->afterRemovingPasses = [[ 93 new ResolveHotPathPass(), 94 ]]; 95 } 96 97 /** 98 * Returns all passes in order to be processed. 99 * 100 * @return CompilerPassInterface[] 101 */ 102 public function getPasses() 103 { 104 return array_merge( 105 [$this->mergePass], 106 $this->getBeforeOptimizationPasses(), 107 $this->getOptimizationPasses(), 108 $this->getBeforeRemovingPasses(), 109 $this->getRemovingPasses(), 110 $this->getAfterRemovingPasses() 111 ); 112 } 113 114 /** 115 * Adds a pass. 116 * 117 * @param string $type The pass type 118 * @param int $priority Used to sort the passes 119 * 120 * @throws InvalidArgumentException when a pass type doesn't exist 121 */ 122 public function addPass(CompilerPassInterface $pass, $type = self::TYPE_BEFORE_OPTIMIZATION, int $priority = 0) 123 { 124 $property = $type.'Passes'; 125 if (!isset($this->$property)) { 126 throw new InvalidArgumentException(sprintf('Invalid type "%s".', $type)); 127 } 128 129 $passes = &$this->$property; 130 131 if (!isset($passes[$priority])) { 132 $passes[$priority] = []; 133 } 134 $passes[$priority][] = $pass; 135 } 136 137 /** 138 * Gets all passes for the AfterRemoving pass. 139 * 140 * @return CompilerPassInterface[] 141 */ 142 public function getAfterRemovingPasses() 143 { 144 return $this->sortPasses($this->afterRemovingPasses); 145 } 146 147 /** 148 * Gets all passes for the BeforeOptimization pass. 149 * 150 * @return CompilerPassInterface[] 151 */ 152 public function getBeforeOptimizationPasses() 153 { 154 return $this->sortPasses($this->beforeOptimizationPasses); 155 } 156 157 /** 158 * Gets all passes for the BeforeRemoving pass. 159 * 160 * @return CompilerPassInterface[] 161 */ 162 public function getBeforeRemovingPasses() 163 { 164 return $this->sortPasses($this->beforeRemovingPasses); 165 } 166 167 /** 168 * Gets all passes for the Optimization pass. 169 * 170 * @return CompilerPassInterface[] 171 */ 172 public function getOptimizationPasses() 173 { 174 return $this->sortPasses($this->optimizationPasses); 175 } 176 177 /** 178 * Gets all passes for the Removing pass. 179 * 180 * @return CompilerPassInterface[] 181 */ 182 public function getRemovingPasses() 183 { 184 return $this->sortPasses($this->removingPasses); 185 } 186 187 /** 188 * Gets the Merge pass. 189 * 190 * @return CompilerPassInterface 191 */ 192 public function getMergePass() 193 { 194 return $this->mergePass; 195 } 196 197 public function setMergePass(CompilerPassInterface $pass) 198 { 199 $this->mergePass = $pass; 200 } 201 202 /** 203 * Sets the AfterRemoving passes. 204 * 205 * @param CompilerPassInterface[] $passes 206 */ 207 public function setAfterRemovingPasses(array $passes) 208 { 209 $this->afterRemovingPasses = [$passes]; 210 } 211 212 /** 213 * Sets the BeforeOptimization passes. 214 * 215 * @param CompilerPassInterface[] $passes 216 */ 217 public function setBeforeOptimizationPasses(array $passes) 218 { 219 $this->beforeOptimizationPasses = [$passes]; 220 } 221 222 /** 223 * Sets the BeforeRemoving passes. 224 * 225 * @param CompilerPassInterface[] $passes 226 */ 227 public function setBeforeRemovingPasses(array $passes) 228 { 229 $this->beforeRemovingPasses = [$passes]; 230 } 231 232 /** 233 * Sets the Optimization passes. 234 * 235 * @param CompilerPassInterface[] $passes 236 */ 237 public function setOptimizationPasses(array $passes) 238 { 239 $this->optimizationPasses = [$passes]; 240 } 241 242 /** 243 * Sets the Removing passes. 244 * 245 * @param CompilerPassInterface[] $passes 246 */ 247 public function setRemovingPasses(array $passes) 248 { 249 $this->removingPasses = [$passes]; 250 } 251 252 /** 253 * Sort passes by priority. 254 * 255 * @param array $passes CompilerPassInterface instances with their priority as key 256 * 257 * @return CompilerPassInterface[] 258 */ 259 private function sortPasses(array $passes): array 260 { 261 if (0 === \count($passes)) { 262 return []; 263 } 264 265 krsort($passes); 266 267 // Flatten the array 268 return array_merge(...$passes); 269 } 270} 271