Create New Item
Item Type
File
Folder
Item Name
Search file in folder and subfolders...
Are you sure want to rename?
peripherad
/
back
/
vendor
/
friendsofphp
/
php-cs-fixer
/
src
/
Fixer
/
ClassNotation
:
SingleClassElementPerStatementFixer.php
Advanced Search
Upload
New Item
Settings
Back
Back Up
Advanced Editor
Save
<?php declare(strict_types=1); /* * This file is part of PHP CS Fixer. * * (c) Fabien Potencier <fabien@symfony.com> * Dariusz Rumiński <dariusz.ruminski@gmail.com> * * This source file is subject to the MIT license that is bundled * with this source code in the file LICENSE. */ namespace PhpCsFixer\Fixer\ClassNotation; use PhpCsFixer\AbstractFixer; use PhpCsFixer\Fixer\ConfigurableFixerInterface; use PhpCsFixer\Fixer\ConfigurableFixerTrait; use PhpCsFixer\FixerConfiguration\AllowedValueSubset; use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver; use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface; use PhpCsFixer\FixerConfiguration\FixerOptionBuilder; use PhpCsFixer\FixerDefinition\CodeSample; use PhpCsFixer\FixerDefinition\FixerDefinition; use PhpCsFixer\FixerDefinition\FixerDefinitionInterface; use PhpCsFixer\Preg; use PhpCsFixer\Tokenizer\CT; use PhpCsFixer\Tokenizer\FCT; use PhpCsFixer\Tokenizer\Token; use PhpCsFixer\Tokenizer\Tokens; use PhpCsFixer\Tokenizer\TokensAnalyzer; /** * Fixer for rules defined in PSR2 ¶4.2. * * @phpstan-type _AutogeneratedInputConfiguration array{ * elements?: list<'const'|'property'>, * } * @phpstan-type _AutogeneratedComputedConfiguration array{ * elements: list<'const'|'property'>, * } * * @implements ConfigurableFixerInterface<_AutogeneratedInputConfiguration, _AutogeneratedComputedConfiguration> * * @author Javier Spagnoletti <phansys@gmail.com> * @author Dariusz Rumiński <dariusz.ruminski@gmail.com> * * @no-named-arguments Parameter names are not covered by the backward compatibility promise. */ final class SingleClassElementPerStatementFixer extends AbstractFixer implements ConfigurableFixerInterface { /** @use ConfigurableFixerTrait<_AutogeneratedInputConfiguration, _AutogeneratedComputedConfiguration> */ use ConfigurableFixerTrait; public function isCandidate(Tokens $tokens): bool { return $tokens->isAnyTokenKindsFound(Token::getClassyTokenKinds()); } /** * {@inheritdoc} * * Must run before ClassAttributesSeparationFixer. */ public function getPriority(): int { return 56; } public function getDefinition(): FixerDefinitionInterface { return new FixerDefinition( 'There MUST NOT be more than one property or constant declared per statement.', [ new CodeSample( <<<'PHP' <?php final class Example { const FOO_1 = 1, FOO_2 = 2; private static $bar1 = array(1,2,3), $bar2 = [1,2,3]; } PHP, ), new CodeSample( <<<'PHP' <?php final class Example { const FOO_1 = 1, FOO_2 = 2; private static $bar1 = array(1,2,3), $bar2 = [1,2,3]; } PHP, ['elements' => ['property']], ), ], ); } protected function applyFix(\SplFileInfo $file, Tokens $tokens): void { $analyzer = new TokensAnalyzer($tokens); $elements = array_reverse($analyzer->getClassyElements(), true); foreach ($elements as $index => $element) { if (!\in_array($element['type'], $this->configuration['elements'], true)) { continue; // not in configuration } $this->fixElement($tokens, $element['type'], $index); } } protected function createConfigurationDefinition(): FixerConfigurationResolverInterface { $values = ['const', 'property']; return new FixerConfigurationResolver([ (new FixerOptionBuilder('elements', 'List of strings which element should be modified.')) ->setDefault($values) ->setAllowedTypes(['string[]']) ->setAllowedValues([new AllowedValueSubset($values)]) ->getOption(), ]); } private function fixElement(Tokens $tokens, string $type, int $index): void { $tokensAnalyzer = new TokensAnalyzer($tokens); $repeatIndex = $index; while (true) { $repeatIndex = $tokens->getNextMeaningfulToken($repeatIndex); $repeatToken = $tokens[$repeatIndex]; if ($tokensAnalyzer->isArray($repeatIndex)) { if ($repeatToken->isGivenKind(\T_ARRAY)) { $repeatIndex = $tokens->getNextTokenOfKind($repeatIndex, ['(']); $repeatIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $repeatIndex); } else { $repeatIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $repeatIndex); } continue; } if ($repeatToken->equalsAny([';', [CT::T_PROPERTY_HOOK_BRACE_OPEN]])) { return; // no repeating found, no fixing needed } if ($repeatToken->equals(',')) { break; } } $start = $tokens->getPrevTokenOfKind($index, [';', '{', '}']); $this->expandElement( $tokens, $type, $tokens->getNextMeaningfulToken($start), $tokens->getNextTokenOfKind($index, [';']), ); } private function expandElement(Tokens $tokens, string $type, int $startIndex, int $endIndex): void { $divisionContent = null; if ($tokens[$startIndex - 1]->isWhitespace()) { $divisionContent = $tokens[$startIndex - 1]->getContent(); if (Preg::match('#(\n|\r\n)#', $divisionContent, $matches)) { $divisionContent = $matches[0].trim($divisionContent, "\r\n"); } } // iterate variables to split up for ($i = $endIndex - 1; $i > $startIndex; --$i) { $token = $tokens[$i]; if ($token->equals(')')) { $i = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $i); continue; } if ($token->isGivenKind(CT::T_ARRAY_SQUARE_BRACE_CLOSE)) { $i = $tokens->findBlockStart(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $i); continue; } if (!$tokens[$i]->equals(',')) { continue; } $tokens[$i] = new Token(';'); if ($tokens[$i + 1]->isWhitespace()) { $tokens->clearAt($i + 1); } if (null !== $divisionContent && '' !== $divisionContent) { $tokens->insertAt($i + 1, new Token([\T_WHITESPACE, $divisionContent])); } // collect modifiers $sequence = $this->getModifiersSequences($tokens, $type, $startIndex, $endIndex); $tokens->insertAt($i + 2, $sequence); } } /** * @return list<Token> */ private function getModifiersSequences(Tokens $tokens, string $type, int $startIndex, int $endIndex): array { if ('property' === $type) { $tokenKinds = [\T_PUBLIC, \T_PROTECTED, \T_PRIVATE, \T_STATIC, \T_VAR, \T_STRING, \T_NS_SEPARATOR, CT::T_NULLABLE_TYPE, CT::T_ARRAY_TYPEHINT, CT::T_TYPE_ALTERNATION, CT::T_TYPE_INTERSECTION, FCT::T_READONLY, FCT::T_PRIVATE_SET, FCT::T_PROTECTED_SET, FCT::T_PUBLIC_SET]; } else { $tokenKinds = [\T_PUBLIC, \T_PROTECTED, \T_PRIVATE, \T_CONST]; } $sequence = []; for ($i = $startIndex; $i < $endIndex - 1; ++$i) { if ($tokens[$i]->isComment()) { continue; } if (!$tokens[$i]->isWhitespace() && !$tokens[$i]->isGivenKind($tokenKinds)) { break; } $sequence[] = clone $tokens[$i]; } return $sequence; } }