AutorÃa | Ultima modificación | Ver Log |
<?phpnamespace PhpOffice\PhpSpreadsheet\Calculation\Engine;use PhpOffice\PhpSpreadsheet\Calculation\Exception;class BranchPruner{protected bool $branchPruningEnabled;/*** Used to generate unique store keys.*/private int $branchStoreKeyCounter = 0;/*** currently pending storeKey (last item of the storeKeysStack.*/protected ?string $pendingStoreKey = null;/*** @var string[]*/protected array $storeKeysStack = [];/*** @var bool[]*/protected array $conditionMap = [];/*** @var bool[]*/protected array $thenMap = [];/*** @var bool[]*/protected array $elseMap = [];/*** @var int[]*/protected array $braceDepthMap = [];protected ?string $currentCondition = null;protected ?string $currentOnlyIf = null;protected ?string $currentOnlyIfNot = null;protected ?string $previousStoreKey = null;public function __construct(bool $branchPruningEnabled){$this->branchPruningEnabled = $branchPruningEnabled;}public function clearBranchStore(): void{$this->branchStoreKeyCounter = 0;}public function initialiseForLoop(): void{$this->currentCondition = null;$this->currentOnlyIf = null;$this->currentOnlyIfNot = null;$this->previousStoreKey = null;$this->pendingStoreKey = empty($this->storeKeysStack) ? null : end($this->storeKeysStack);if ($this->branchPruningEnabled) {$this->initialiseCondition();$this->initialiseThen();$this->initialiseElse();}}private function initialiseCondition(): void{if (isset($this->conditionMap[$this->pendingStoreKey]) && $this->conditionMap[$this->pendingStoreKey]) {$this->currentCondition = $this->pendingStoreKey;$stackDepth = count($this->storeKeysStack);if ($stackDepth > 1) {// nested if$this->previousStoreKey = $this->storeKeysStack[$stackDepth - 2];}}}private function initialiseThen(): void{if (isset($this->thenMap[$this->pendingStoreKey]) && $this->thenMap[$this->pendingStoreKey]) {$this->currentOnlyIf = $this->pendingStoreKey;} elseif (isset($this->previousStoreKey, $this->thenMap[$this->previousStoreKey])&& $this->thenMap[$this->previousStoreKey]) {$this->currentOnlyIf = $this->previousStoreKey;}}private function initialiseElse(): void{if (isset($this->elseMap[$this->pendingStoreKey]) && $this->elseMap[$this->pendingStoreKey]) {$this->currentOnlyIfNot = $this->pendingStoreKey;} elseif (isset($this->previousStoreKey, $this->elseMap[$this->previousStoreKey])&& $this->elseMap[$this->previousStoreKey]) {$this->currentOnlyIfNot = $this->previousStoreKey;}}public function decrementDepth(): void{if (!empty($this->pendingStoreKey)) {--$this->braceDepthMap[$this->pendingStoreKey];}}public function incrementDepth(): void{if (!empty($this->pendingStoreKey)) {++$this->braceDepthMap[$this->pendingStoreKey];}}public function functionCall(string $functionName): void{if ($this->branchPruningEnabled && ($functionName === 'IF(')) {// we handle a new if$this->pendingStoreKey = $this->getUnusedBranchStoreKey();$this->storeKeysStack[] = $this->pendingStoreKey;$this->conditionMap[$this->pendingStoreKey] = true;$this->braceDepthMap[$this->pendingStoreKey] = 0;} elseif (!empty($this->pendingStoreKey) && array_key_exists($this->pendingStoreKey, $this->braceDepthMap)) {// this is not an if but we go deeper++$this->braceDepthMap[$this->pendingStoreKey];}}public function argumentSeparator(): void{if (!empty($this->pendingStoreKey) && $this->braceDepthMap[$this->pendingStoreKey] === 0) {// We must go to the IF next argumentif ($this->conditionMap[$this->pendingStoreKey]) {$this->conditionMap[$this->pendingStoreKey] = false;$this->thenMap[$this->pendingStoreKey] = true;} elseif ($this->thenMap[$this->pendingStoreKey]) {$this->thenMap[$this->pendingStoreKey] = false;$this->elseMap[$this->pendingStoreKey] = true;} elseif ($this->elseMap[$this->pendingStoreKey]) {throw new Exception('Reaching fourth argument of an IF');}}}public function closingBrace(mixed $value): void{if (!empty($this->pendingStoreKey) && $this->braceDepthMap[$this->pendingStoreKey] === -1) {// we are closing an IF(if ($value !== 'IF(') {throw new Exception('Parser bug we should be in an "IF("');}if ($this->conditionMap[$this->pendingStoreKey]) {throw new Exception('We should not be expecting a condition');}$this->thenMap[$this->pendingStoreKey] = false;$this->elseMap[$this->pendingStoreKey] = false;--$this->braceDepthMap[$this->pendingStoreKey];array_pop($this->storeKeysStack);$this->pendingStoreKey = null;}}public function currentCondition(): ?string{return $this->currentCondition;}public function currentOnlyIf(): ?string{return $this->currentOnlyIf;}public function currentOnlyIfNot(): ?string{return $this->currentOnlyIfNot;}private function getUnusedBranchStoreKey(): string{$storeKeyValue = 'storeKey-' . $this->branchStoreKeyCounter;++$this->branchStoreKeyCounter;return $storeKeyValue;}}