├── .gitignore
├── .php_cs
├── .project
├── .settings
├── com.dubture.composer.core.prefs
├── org.eclipse.php.composer.core.prefs
├── org.eclipse.php.core.prefs
├── org.eclipse.wst.common.project.facet.core.xml
└── org.eclipse.wst.validation.prefs
├── .travis.yml
├── LICENSE
├── README.md
├── bin
└── phormat
├── composer.json
├── phpunit.xml.dist
├── profiles
└── default.yml
├── sami.php
├── src
├── Formatter.php
├── FormatterCli.php
├── collections
│ └── UnitCollection.php
├── commands
│ └── FormatterCommand.php
├── entities
│ ├── Block.php
│ ├── Group.php
│ └── Unit.php
├── events
│ ├── BlockEvent.php
│ ├── GroupEvent.php
│ └── TokenEvent.php
├── formatters
│ ├── BaseFormatter.php
│ ├── BlanksFormatter.php
│ ├── CommentsFormatter.php
│ ├── DefaultFormatter.php
│ ├── DelegateFormatter.php
│ ├── IndentationFormatter.php
│ ├── NewlineFormatter.php
│ ├── SpecializedFormatter.php
│ └── WhitespaceFormatter.php
├── parser
│ ├── Analyzer.php
│ ├── Context.php
│ ├── Lexer.php
│ ├── Parser.php
│ ├── TokenMatcher.php
│ └── TokenTracker.php
└── utils
│ ├── Sanitizer.php
│ └── Writer.php
└── tests
├── fixtures
└── samples
│ ├── default
│ ├── abstract-class.php
│ ├── blanks.php
│ ├── class-phpdoc.php
│ ├── class.php
│ └── sample1.php
│ └── raw
│ ├── abstract-class.php
│ ├── blanks.php
│ ├── class-phpdoc.php
│ ├── class.php
│ └── sample1.php
├── formatter
└── SamplesTest.php
├── parser
├── AnalyzerTest.php
└── ContextTest.php
├── token
└── TokenizerTest.php
└── utils
└── SamplesTrait.php
/.gitignore:
--------------------------------------------------------------------------------
1 | .buildpath
2 | composer.lock
3 | vendor/
4 | coverage/
5 | cache/
6 | api/
7 | .php_cs.cache
--------------------------------------------------------------------------------
/.php_cs:
--------------------------------------------------------------------------------
1 | getFinder()
5 | ->exclude(['fixtures'])
6 | ->in(__DIR__ . '/src')
7 | ->in(__DIR__ . '/tests');
8 |
9 | $cacheDir = getenv('TRAVIS') ? getenv('HOME') . '/.php-cs-fixer' : __DIR__;
10 |
11 | $config->setCacheFile($cacheDir . '/.php_cs.cache');
12 |
13 | return $config;
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | php-code-formatter
4 |
5 |
6 |
7 |
8 |
9 | com.dubture.composer.core.builder.buildPathManagementBuilder
10 |
11 |
12 |
13 |
14 | org.eclipse.wst.common.project.facet.core.builder
15 |
16 |
17 |
18 |
19 | org.eclipse.wst.validation.validationbuilder
20 |
21 |
22 |
23 |
24 | org.eclipse.dltk.core.scriptbuilder
25 |
26 |
27 |
28 |
29 |
30 | org.eclipse.php.core.PHPNature
31 | org.eclipse.wst.common.project.facet.core.nature
32 | com.dubture.composer.core.composerNature
33 |
34 |
35 |
--------------------------------------------------------------------------------
/.settings/com.dubture.composer.core.prefs:
--------------------------------------------------------------------------------
1 | com.dubture.composer.corebuildpath.includes.excludes=\n
2 | eclipse.preferences.version=1
3 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.php.composer.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.php.composer.corebuildpath.includes.excludes=\n
3 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.php.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | include_path=
3 | phpVersion=php5.6
4 | useShortTags=false
5 | use_asp_tags_as_php=false
6 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.wst.common.project.facet.core.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.wst.validation.prefs:
--------------------------------------------------------------------------------
1 | disabled=114tests/fixtures06vendor
2 | eclipse.preferences.version=1
3 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | dist: trusty
4 |
5 | php:
6 | - 5.6
7 | - 7.0
8 | - 7.1
9 | - 7.2
10 | - hhvm
11 |
12 | install:
13 | - composer install
14 |
15 | script:
16 | - vendor/bin/phpunit --coverage-clover=coverage.clover
17 |
18 | after_script:
19 | - wget https://scrutinizer-ci.com/ocular.phar
20 | - php ocular.phar code-coverage:upload --format=php-clover coverage.clover
21 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Thomas Gossmann
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PHP Code Formatter
2 |
3 | [](https://packagist.org/packages/gossi/php-code-formatter)
4 | [](https://packagist.org/packages/gossi/php-code-formatter)
5 | [](https://packagist.org/packages/gossi/php-code-formatter)
6 | [](https://travis-ci.org/gossi/php-code-formatter)
7 | [](https://scrutinizer-ci.com/g/gossi/php-code-formatter)
8 | [](https://scrutinizer-ci.com/g/gossi/php-code-formatter)
9 |
10 | A library for formatting php code.
11 |
12 |
13 | ## Features
14 |
15 | - Whitespace
16 | - New lines
17 | - Indentation (on curly braces only)
18 | - Blanks (partial support)
19 |
20 | -> [Wishlist](https://github.com/gossi/php-code-formatter/labels/feature-request)
21 |
22 | ## Getting started
23 |
24 | ### Installation
25 |
26 | Via composer:
27 |
28 | ```
29 | composer require gossi/php-code-formatter
30 | ```
31 |
32 | ### From Code
33 |
34 | This simple code snippet is all you need:
35 |
36 | ```php
37 | use gossi\formatter\Formatter;
38 |
39 | $formatter = new Formatter();
40 | $beautifulCode = $formatter->format($uglyCode);
41 | ```
42 |
43 | ### From CLI
44 |
45 | A bare cli version is available:
46 |
47 | ```
48 | vendor/bin/phormat path/to/file.php
49 | ```
50 |
51 | will output the formatted source code to stdout
52 |
53 |
54 | ## Development
55 |
56 | php code formatter is not yet finished (see [Wishlist](https://github.com/gossi/php-code-formatter/labels/feature-request)). Please help the development, by picking one of the open issues or implement your own rules. See the wiki on [creating your own rules](https://github.com/gossi/php-code-formatter/wiki/creating-your-own-Rules).
57 |
58 | Psr-2? Spaces suck, deal with it :p Once [Version 1.0](https://github.com/gossi/php-code-formatter/milestones/Version%201.0) is reached, a psr-2 profile will be shipped.
59 |
60 |
--------------------------------------------------------------------------------
/bin/phormat:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | run();
9 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name" : "gossi/php-code-formatter",
3 | "type" : "library",
4 | "description" : "A code formatter for php code",
5 | "license" : "MIT",
6 | "authors" : [{
7 | "name" : "Thomas Gossmann",
8 | "homepage" : "http://gos.si"
9 | }
10 | ],
11 | "keywords" : [
12 | "php",
13 | "formatter",
14 | "beautifier"
15 | ],
16 | "support" : {
17 | "issues" : "https://github.com/gossi/php-code-formatter/issues"
18 | },
19 | "autoload" : {
20 | "psr-4" : {
21 | "gossi\\formatter\\" : "src"
22 | }
23 | },
24 | "autoload-dev" : {
25 | "psr-4" : {
26 | "gossi\\formatter\\tests\\" : "tests"
27 | }
28 | },
29 | "require" : {
30 | "php" : ">=7.2",
31 | "gossi/php-code-profiles" : "dev-master",
32 | "symfony/config" : "^5.0",
33 | "symfony/yaml" : "^5.0",
34 | "symfony/event-dispatcher" : "~2|^3|^4",
35 | "symfony/console" : "~2|^3|^4",
36 | "phootwork/collection" : "^1.5",
37 | "phootwork/tokenizer" : "~0"
38 | },
39 | "require-dev" : {
40 | "phpunit/phpunit" : "^5.7",
41 | "sami/sami" : "^4|^3",
42 | "phootwork/php-cs-fixer-config" : "~0.1"
43 | },
44 | "scripts" : {
45 | "check" : "@cs",
46 | "cs" : "php-cs-fixer fix -v --diff --dry-run",
47 | "cs-fix" : "php-cs-fixer fix -v --diff",
48 | "test" : "phpunit",
49 | "api" : "sami.php update sami.php"
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
15 | ./tests/
16 | ./tests/fixtures
17 |
18 |
19 |
20 |
21 |
22 | tests/
23 | vendor/
24 |
25 |
26 | src/
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/profiles/default.yml:
--------------------------------------------------------------------------------
1 | indentation:
2 | # policy
3 | character: tab
4 | size: 1
5 |
6 | # declarations
7 | struct: true
8 | function: true
9 | blocks: true
10 | switch: true
11 | case: true
12 | break: true
13 | empty_lines: false
14 |
15 | # curly braces
16 | braces:
17 | struct: same
18 | function: same
19 | blocks: same
20 |
21 | whitespace:
22 |
23 | # global
24 | default:
25 | before_curly: true
26 |
27 | before_open: true
28 | after_open: false
29 | before_close: false
30 | after_close: false
31 |
32 | before_comma: false
33 | after_comma: true
34 | before_semicolon: false
35 | after_semicolon: true
36 |
37 | before_arrow: false
38 | after_arrow: false
39 | before_doublecolon: false
40 | after_doublecolon: false
41 |
42 | # # declarations
43 | # struct:
44 | # before_curly: true
45 | # before_comma: false
46 | # after_comma: true
47 | #
48 | # properties:
49 | # # multi properties
50 | # before_comma: false
51 | # after_comma: true
52 | #
53 | # constants:
54 | # # multi constants
55 | # before_comma: false
56 | # after_comma: true
57 | #
58 | # function:
59 | # before_curly: true
60 | # before_open: false
61 | # after_open: false
62 | # before_close: false
63 | # before_comma: false
64 | # after_comma: true
65 | #
66 | # # control statements
67 | # blocks:
68 | # before_curly: true
69 | # after_curly: true
70 | #
71 | # ifelse:
72 | # before_open: false
73 | # after_open: false
74 | # before_close: false
75 | #
76 | # for:
77 | # before_open: false
78 | # after_open: false
79 | # before_close: false
80 | # before_comma: false
81 | # after_comma: true
82 | # before_semicolon: false
83 | # after_semicolon: true
84 | #
85 | # foreach:
86 | # before_open: false
87 | # after_open: false
88 | # before_close: false
89 | # before_arrow: true
90 | # after_arrow: true
91 | #
92 | # switch:
93 | # before_open: false
94 | # after_open: false
95 | # before_close: false
96 | # before_colon: false
97 | #
98 | # while:
99 | # before_open: false
100 | # after_open: false
101 | # before_close: false
102 | #
103 | # catch:
104 | # before_open: false
105 | # after_open: false
106 | # before_close: false
107 | #
108 | # # multiple static
109 | # static:
110 | # before_comma: false
111 | # after_comma: true
112 | #
113 | # global:
114 | # before_comma: false
115 | # after_comma: true
116 | #
117 | # echo:
118 | # before_comma: false
119 | # after_comma: true
120 | #
121 | # yield:
122 | # before_arrow: true
123 | # after_arrow: true
124 |
125 | # expressions
126 | field_access:
127 | before_arrow: false
128 | after_arrow: false
129 | before_doublecolon: false
130 | after_doublecolon: false
131 |
132 | function_invocation:
133 | before_open: false
134 | after_open: false
135 | before_close: false
136 | before_comma: false
137 | after_comma: true
138 | before_arrow: false
139 | after_arrow: false
140 | before_doublecolon: false
141 | after_doublecolon: false
142 |
143 | assignments:
144 | before_assignment: true
145 | after_assignment: true
146 |
147 | operators:
148 | before_binary: true
149 | after_binary: true
150 | before_unary: true
151 | after_unary: false
152 | before_prefix: false
153 | after_prefix: false
154 | before_postfix: false
155 | after_postfix: true
156 |
157 | # type_casts:
158 | # before_open: false
159 | # after_open: false
160 | # before_close: false
161 |
162 | conditionals:
163 | before_questionmark: true
164 | after_questionmark: true
165 | before_colon: true
166 | after_colon: true
167 |
168 | # grouping with parenthesis
169 | grouping:
170 | before_open: false
171 | after_open: false
172 | before_close: false
173 | after_close: false
174 |
175 | # arrays
176 |
177 | newlines:
178 | elseif_else: false
179 | catch: false
180 | finally: false
181 | do_while: false
182 |
183 | blanks:
184 |
185 | # namespace
186 | before_namespace: 0
187 | after_namespace: 1
188 | after_use: 1
189 |
190 | # structs
191 | before_struct: 1
192 | before_traits: 1
193 | before_constants: 1
194 | before_fields: 1
195 | before_methods: 1
196 | beginning_method: 0
197 | end_method: 0
198 | end_struct: 1
199 |
200 | # file
201 | end_file: 1
202 |
--------------------------------------------------------------------------------
/sami.php:
--------------------------------------------------------------------------------
1 | files()
11 | ->name('*.php')
12 | ->in($dir)
13 | ;
14 |
15 | return new Sami($iterator, [
16 | 'title' => 'PHP Code Formatter API',
17 | 'theme' => 'default',
18 | 'build_dir' => __DIR__ . '/api/%version%',
19 | 'cache_dir' => __DIR__ . '/cache/%version%',
20 | 'default_opened_level' => 2
21 | ]);
22 |
--------------------------------------------------------------------------------
/src/Formatter.php:
--------------------------------------------------------------------------------
1 | profile = $profile;
21 | }
22 |
23 | public function format($code) {
24 | $parser = new Parser();
25 | $parser->parse($code);
26 |
27 | // formatting
28 | $delegate = new DelegateFormatter($parser, $this->profile);
29 | $delegate->format();
30 |
31 | // post processing
32 |
33 | return $delegate->getCode();
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/FormatterCli.php:
--------------------------------------------------------------------------------
1 | setArguments();
44 |
45 | return $inputDefinition;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/collections/UnitCollection.php:
--------------------------------------------------------------------------------
1 | collection as $unit) {
28 | if ($unit->start === $token) {
29 | return $unit;
30 | }
31 | }
32 |
33 | return null;
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/src/commands/FormatterCommand.php:
--------------------------------------------------------------------------------
1 | setName('format')
19 | ->setDescription('Beautify PHP Code')
20 | ->addArgument(
21 | 'input',
22 | InputArgument::REQUIRED,
23 | 'The input'
24 | )
25 | // ->addArgument(
26 | // 'output',
27 | // InputArgument::OPTIONAL,
28 | // 'The output'
29 | // )
30 | ->addOption(
31 | 'profile',
32 | null,
33 | InputOption::VALUE_OPTIONAL,
34 | 'The profile with the formatting options'
35 | )
36 | ;
37 | }
38 |
39 | protected function execute(InputInterface $in, OutputInterface $output) {
40 | $in = $in->getArgument('input');
41 | // $out = $in->getArgument('output');
42 |
43 | $code = file_exists($in) ? file_get_contents($in) : null;
44 |
45 | if ($code !== null) {
46 | $formatter = new Formatter();
47 | $beauty = $formatter->format($code);
48 |
49 | echo $output->writeln($beauty);
50 | }
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/src/entities/Block.php:
--------------------------------------------------------------------------------
1 | self::TYPE_NAMESPACE,
34 | T_CLASS => self::TYPE_CLASS,
35 | T_TRAIT => self::TYPE_TRAIT,
36 | T_INTERFACE => self::TYPE_INTERFACE,
37 | T_FUNCTION => self::TYPE_FUNCTION,
38 | T_IF => self::TYPE_IF,
39 | T_ELSEIF => self::TYPE_ELSEIF,
40 | T_ELSE => self::TYPE_ELSE,
41 | T_DO => self::TYPE_DO,
42 | T_WHILE => self::TYPE_WHILE,
43 | T_FOR => self::TYPE_FOR,
44 | T_FOREACH => self::TYPE_FOREACH,
45 | T_SWITCH => self::TYPE_SWITCH,
46 | T_USE => self::TYPE_USE,
47 | T_TRY => self::TYPE_TRY,
48 | T_CATCH => self::TYPE_CATCH,
49 | ];
50 |
51 | private static $STRUCTS = [self::TYPE_CLASS, self::TYPE_TRAIT, self::TYPE_INTERFACE];
52 | private static $ROUTINE = [self::TYPE_FUNCTION, self::TYPE_METHOD];
53 | private static $BLOCKS = [self::TYPE_IF, self::TYPE_ELSEIF, self::TYPE_ELSE, self::TYPE_DO,
54 | self::TYPE_WHILE, self::TYPE_FOR, self::TYPE_FOREACH, self::TYPE_SWITCH, self::TYPE_USE,
55 | self::TYPE_NAMESPACE];
56 |
57 | /**
58 | * The opening curly brace
59 | *
60 | * @var Token
61 | */
62 | public $open = null;
63 |
64 | /**
65 | * The closing curly brace
66 | *
67 | * @var Token
68 | */
69 | public $close = null;
70 |
71 | /**
72 | * Start is the initial token of that block
73 | *
74 | * @var Token
75 | */
76 | public $start = null;
77 |
78 | /**
79 | * Start is the last token of that block
80 | *
81 | * @var Token
82 | */
83 | public $end = null;
84 |
85 | public $type = '';
86 |
87 | public function __construct($type) {
88 | $this->type = $type;
89 | }
90 |
91 | public function isStruct() {
92 | return in_array($this->type, self::$STRUCTS);
93 | }
94 |
95 | public function isRoutine() {
96 | return in_array($this->type, self::$ROUTINE);
97 | }
98 |
99 | public function isBlock() {
100 | return in_array($this->type, self::$BLOCKS);
101 | }
102 |
103 | public static function getType(Token $token) {
104 | if (isset(self::$typeMap[$token->type])) {
105 | return self::$typeMap[$token->type];
106 | } else if ($token->contents == 'finally') {
107 | return self::TYPE_FINALLY;
108 | }
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/src/entities/Group.php:
--------------------------------------------------------------------------------
1 | type == self::BLOCK;
25 | }
26 |
27 | public function isCall() {
28 | return $this->type == self::CALL;
29 | }
30 |
31 | public function isGroup() {
32 | return $this->type == self::GROUP;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/entities/Unit.php:
--------------------------------------------------------------------------------
1 | self::UNIT_NAMESPACE,
18 | T_USE => self::UNIT_USE,
19 | T_CONST => self::UNIT_CONSTANTS,
20 | T_NAMESPACE => self::UNIT_NAMESPACE,
21 | T_USE => self::UNIT_USE,
22 | T_REQUIRE => self::UNIT_IMPORTS,
23 | T_REQUIRE_ONCE => self::UNIT_IMPORTS,
24 | T_INCLUDE => self::UNIT_IMPORTS,
25 | T_INCLUDE_ONCE => self::UNIT_IMPORTS
26 | ];
27 |
28 | /** @var Token */
29 | public $start = null;
30 |
31 | /** @var Token */
32 | public $end = null;
33 | public $type = '';
34 |
35 | public static function getType(Token $token) {
36 | if (isset(self::$typeMap[$token->type])) {
37 | return self::$typeMap[$token->type];
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/events/BlockEvent.php:
--------------------------------------------------------------------------------
1 | block = $block;
15 | }
16 |
17 | public function getName() {
18 | return 'context.block_' . ($this->block->end === null ? 'enter' : 'leave');
19 | }
20 |
21 | /**
22 | * Returns the associated block
23 | *
24 | * @return Block
25 | */
26 | public function getBlock() {
27 | return $this->block;
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/src/events/GroupEvent.php:
--------------------------------------------------------------------------------
1 | group = $group;
15 | }
16 |
17 | public function getName() {
18 | return 'context.group_' . ($this->group->end === null ? 'enter' : 'leave');
19 | }
20 |
21 | /**
22 | * Returns the associated group
23 | *
24 | * @return Group
25 | */
26 | public function getGroup() {
27 | return $this->group;
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/src/events/TokenEvent.php:
--------------------------------------------------------------------------------
1 | token = $token;
13 | }
14 |
15 | public function getToken() {
16 | return $this->token;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/formatters/BaseFormatter.php:
--------------------------------------------------------------------------------
1 | config = $profile;
30 | $this->writer = $writer;
31 | $this->parser = $parser;
32 | $this->context = $parser->getContext();
33 | $this->matcher = $parser->getMatcher();
34 |
35 | $this->init();
36 | }
37 |
38 | public function visitToken(Token $token) {
39 | $this->nextToken = $this->parser->getTracker()->getNextToken();
40 | $this->prevToken = $this->parser->getTracker()->getPrevToken();
41 |
42 | $this->doVisitToken($token);
43 | }
44 |
45 | protected function doVisitToken(Token $token) {
46 |
47 | }
48 |
49 | protected function init() {
50 |
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/src/formatters/BlanksFormatter.php:
--------------------------------------------------------------------------------
1 | units = $this->parser->getAnalyzer()->getUnits();
13 | }
14 |
15 | protected function doVisitToken(Token $token) {
16 | $this->unitStart($token);
17 | $this->unitEnd($token);
18 | }
19 |
20 | private function unitStart(Token $token) {
21 | $unit = $this->units->findUnitByStart($token);
22 |
23 | if ($unit !== null) {
24 | $this->currentUnit = $unit;
25 | $this->blankBefore($unit->type);
26 | }
27 | }
28 |
29 | private function unitEnd(Token $token) {
30 | if ($this->currentUnit !== null && $this->currentUnit->end === $token) {
31 | $this->blankAfter($this->currentUnit->type);
32 | $this->currentUnit = null;
33 | }
34 | }
35 |
36 | private function blankBefore($key) {
37 | for ($i = 0, $count = $this->config->getBlanks('before_' . $key); $i < $count; $i++) {
38 | $this->defaultFormatter->addPreWriteln();
39 | }
40 | }
41 |
42 | private function blankAfter($key) {
43 | for ($i = 0, $count = $this->config->getBlanks('after_' . $key); $i < $count; $i++) {
44 | $this->defaultFormatter->addPostWriteln();
45 | }
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/src/formatters/CommentsFormatter.php:
--------------------------------------------------------------------------------
1 | type == T_DOC_COMMENT
11 | || $token->type == T_INLINE_HTML && strpos($token->contents, '/*') !== 0) {
12 |
13 | $lines = explode("\n", $token->contents);
14 | $firstLine = array_shift($lines);
15 | $this->writer->writeln();
16 | $this->writer->writeln($firstLine);
17 |
18 | foreach ($lines as $line) {
19 | $this->writer->writeln(' ' . ltrim($line));
20 | }
21 |
22 | $this->defaultFormatter->hideToken();
23 | }
24 | }
25 |
26 | public static function isComment(Token $token) {
27 | return $token->type == T_DOC_COMMENT
28 | || ($token->type == T_INLINE_HTML && strpos($token->contents, '/*') !== 0)
29 | || $token->type == T_COMMENT;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/formatters/DefaultFormatter.php:
--------------------------------------------------------------------------------
1 | preCommands = new Queue();
16 | $this->postCommands = new Queue();
17 | }
18 |
19 | public function addPreWrite($content = '') {
20 | $this->preCommands->enqueue(['write', $content]);
21 | }
22 |
23 | public function addPreWriteln($content = '') {
24 | $this->preCommands->enqueue(['writeln', $content]);
25 | }
26 |
27 | public function addPreIndent() {
28 | $this->preCommands->enqueue(['indent']);
29 | }
30 |
31 | public function addPreOutdent() {
32 | $this->preCommands->enqueue(['outdent']);
33 | }
34 |
35 | public function addPostWrite($content = '') {
36 | $this->postCommands->enqueue(['write', $content]);
37 | }
38 |
39 | public function addPostWriteln($content = '') {
40 | $this->postCommands->enqueue(['writeln', $content]);
41 | }
42 |
43 | public function addPostIndent() {
44 | $this->postCommands->enqueue(['indent']);
45 | }
46 |
47 | public function addPostOutdent() {
48 | $this->postCommands->enqueue(['outdent']);
49 | }
50 |
51 | public function hideToken() {
52 | $this->showToken = false;
53 | }
54 |
55 | protected function doVisitToken(Token $token) {
56 | $group = $this->context->getGroupContext();
57 |
58 | // pre commands
59 | $this->processCommands($this->preCommands);
60 |
61 | // finish line on semicolon
62 | if ($token->contents == ';' && $group->type != Group::BLOCK) {
63 | $this->context->resetLineContext();
64 | $this->writer->writeln($token->contents);
65 | }
66 |
67 | // when no semicolon and token output allowed
68 | else if ($this->showToken) {
69 | $this->writer->write($token->contents);
70 | }
71 |
72 | // post commands
73 | $this->processCommands($this->postCommands);
74 |
75 | // reset
76 | $this->preCommands->clear();
77 | $this->postCommands->clear();
78 | $this->showToken = true;
79 | }
80 |
81 | private function processCommands(Queue $commands) {
82 | foreach ($commands as $cmd) {
83 | switch ($cmd[0]) {
84 | case 'write':
85 | $this->writer->write($cmd[1]);
86 | break;
87 |
88 | case 'writeln':
89 | $this->writer->writeln($cmd[1]);
90 | break;
91 |
92 | case 'indent':
93 | $this->writer->indent();
94 | break;
95 |
96 | case 'outdent':
97 | $this->writer->outdent();
98 | break;
99 | }
100 | }
101 | }
102 |
103 | }
104 |
--------------------------------------------------------------------------------
/src/formatters/DelegateFormatter.php:
--------------------------------------------------------------------------------
1 | profile = $profile;
31 | $this->parser = $parser;
32 | $this->writer = new Writer([
33 | 'indentation_character' => $profile->getIndentation('character') == 'tab' ? "\t" : ' ',
34 | 'indentation_size' => $profile->getIndentation('size')
35 | ]);
36 |
37 | // define rules
38 | $this->defaultFormatter = new DefaultFormatter($parser, $profile, $this->writer);
39 | $this->commentsFormatter = new CommentsFormatter($parser, $profile, $this->writer, $this->defaultFormatter);
40 | $this->indentationFormatter = new IndentationFormatter($parser, $profile, $this->writer, $this->defaultFormatter);
41 | $this->newlineFormatter = new NewlineFormatter($parser, $profile, $this->writer, $this->defaultFormatter);
42 | $this->whitespaceFormatter = new WhitespaceFormatter($parser, $profile, $this->writer, $this->defaultFormatter);
43 | $this->blanksFormatter = new BlanksFormatter($parser, $profile, $this->writer, $this->defaultFormatter);
44 | }
45 |
46 | public function format() {
47 | foreach ($this->parser->getTokens() as $token) {
48 | $token->accept($this);
49 | }
50 | }
51 |
52 | public function visitToken(Token $token) {
53 | $this->parser->getTracker()->visitToken($token);
54 |
55 | // visit all rules
56 | $this->commentsFormatter->visitToken($token);
57 | $this->indentationFormatter->visitToken($token);
58 | $this->newlineFormatter->visitToken($token);
59 | $this->whitespaceFormatter->visitToken($token);
60 | $this->blanksFormatter->visitToken($token);
61 | $this->defaultFormatter->visitToken($token);
62 | }
63 |
64 | public function getCode() {
65 | return $this->writer->getContent();
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/src/formatters/IndentationFormatter.php:
--------------------------------------------------------------------------------
1 | indentOpenCurlyBrace($token);
10 | $this->indentCloseCurlyBrace($token);
11 | }
12 |
13 | private function indentOpenCurlyBrace(Token $token) {
14 | if ($token->contents == '{') {
15 | $this->defaultFormatter->addPostIndent();
16 | }
17 | }
18 |
19 | private function indentCloseCurlyBrace(Token $token) {
20 | if ($token->contents == '}') {
21 | $this->defaultFormatter->addPreOutdent();
22 | }
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/formatters/NewlineFormatter.php:
--------------------------------------------------------------------------------
1 | context->addListener(Context::EVENT_BLOCK_ENTER, [$this, 'preOpenCurlyBrace']);
12 | $this->context->addListener(Context::EVENT_BLOCK_LEAVE, [$this, 'postCloseCurlyBrace']);
13 | }
14 |
15 | public function preOpenCurlyBrace(BlockEvent $event) {
16 | $block = $event->getBlock();
17 |
18 | // curly braces in strucs
19 | if ($block->isStruct()) {
20 | $this->newlineOrSpaceBeforeCurly($this->config->getBraces('struct') == 'next');
21 | }
22 |
23 | // curly braces in functions
24 | else if ($block->isRoutine()) {
25 | $this->newlineOrSpaceBeforeCurly($this->config->getBraces('function') == 'next');
26 | }
27 |
28 | // curly braces in blocks
29 | else if ($block->isBlock()) {
30 | $this->newlineOrSpaceBeforeCurly($this->config->getBraces('blocks') == 'next');
31 | }
32 |
33 | // new line after open curly brace
34 | $this->defaultFormatter->addPostWriteln();
35 | }
36 |
37 | public function postCloseCurlyBrace(BlockEvent $event) {
38 | $block = $event->getBlock();
39 | $token = $event->getToken();
40 | $nextToken = $this->parser->getTracker()->nextToken($token);
41 |
42 | // check new line before T_ELSE and T_ELSEIF
43 | if (in_array($block->type, [Block::TYPE_IF, Block::TYPE_ELSEIF])
44 | && in_array($nextToken->type, [T_ELSE, T_ELSEIF])) {
45 | $this->newlineOrSpaceAfterCurly($this->config->getNewline('elseif_else'));
46 | }
47 |
48 | // check new line before T_CATCH
49 | else if ($this->nextToken->type == T_CATCH) {
50 | $this->newlineOrSpaceAfterCurly($this->config->getNewline('catch'));
51 | }
52 |
53 | // check new line before finally
54 | else if ($token->contents == 'finally') {
55 | $this->newlineOrSpaceAfterCurly($this->config->getNewline('finally'));
56 | }
57 |
58 | // check new line before while in a do-while block
59 | else if ($block->type == Block::TYPE_DO && $nextToken->type == T_WHILE) {
60 | $this->newlineOrSpaceAfterCurly($this->config->getNewline('do_while'));
61 | }
62 |
63 | // anyway a new line
64 | else {
65 | $this->defaultFormatter->addPostWriteln();
66 | }
67 | }
68 |
69 | private function newlineOrSpaceBeforeCurly($condition) {
70 | if ($condition) {
71 | $this->writer->writeln();
72 | } else if ($this->config->getWhitespace('before_curly')) {
73 | $this->writer->write(' ');
74 | }
75 | }
76 |
77 | private function newlineOrSpaceAfterCurly($condition) {
78 | if ($condition) {
79 | $this->writer->writeln();
80 | } else {
81 | $this->defaultFormatter->addPostWrite(' ');
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/formatters/SpecializedFormatter.php:
--------------------------------------------------------------------------------
1 | defaultFormatter = $default;
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/src/formatters/WhitespaceFormatter.php:
--------------------------------------------------------------------------------
1 | 'ifelse',
11 | T_ELSEIF => 'ifelse',
12 | T_WHILE => 'while',
13 | T_FOREACH => 'foreach',
14 | T_FOR => 'for',
15 | T_CATCH => 'catch'
16 | ];
17 |
18 | private static $SYNTAX = [
19 | ')' => 'close',
20 | '(' => 'open',
21 | ',' => 'comma',
22 | ';' => 'semicolon',
23 | ':' => 'colon',
24 | '=>' => 'arrow',
25 | '->' => 'arrow', // function invocation
26 | '::' => 'doublecolon', // function invocation
27 | '?' => 'questionmark'
28 | ];
29 |
30 | protected function doVisitToken(Token $token) {
31 | $this->applyKeywords($token);
32 | $this->applyAssignments($token);
33 | $this->applyOperators($token);
34 | $this->applyPrefixPostfix($token);
35 | $this->applyUnary($token);
36 | $this->applySyntax($token);
37 | }
38 |
39 | private function applyKeywords(Token $token) {
40 | if ($this->matcher->isKeyword($token)) {
41 | $this->defaultFormatter->addPostWrite(' ');
42 | }
43 | }
44 |
45 | private function applyAssignments(Token $token) {
46 | if ($this->matcher->isAssignment($token)) {
47 | $this->whitespaceBeforeAfter('assignment', 'assignments');
48 | }
49 | }
50 |
51 | private function applyOperators(Token $token) {
52 | if ($this->matcher->isOperator($token)) {
53 | $this->whitespaceBeforeAfter('binary', 'operators');
54 | }
55 | }
56 |
57 | private function applyPrefixPostfix(Token $token) {
58 | if ($token->type == T_INC || $token->type == T_DEC) {
59 | // pre
60 | if ($this->nextToken->type == T_VAR) {
61 | $this->whitespaceBeforeAfter('prefix', 'operators');
62 | }
63 |
64 | // post
65 | else if ($this->prevToken->type == T_VAR) {
66 | $this->whitespaceBeforeAfter('postfix', 'operators');
67 | }
68 | }
69 | }
70 |
71 | /**
72 | * @TODO
73 | * @param Token $token
74 | */
75 | private function applyUnary(Token $token) {
76 |
77 | }
78 |
79 | private function applySyntax(Token $token) {
80 | if (array_key_exists($token->contents, self::$SYNTAX)) {
81 | $key = self::$SYNTAX[$token->contents];
82 | $group = $this->context->getGroupContext();
83 |
84 | // return when semicolon is not inside a block context
85 | if ($token->contents == ';' && $group->type != Group::BLOCK) {
86 | return;
87 | }
88 |
89 | // anyway find context and apply it
90 | $context = $this->findContext($token);
91 | $this->whitespaceBeforeAfter($key, $context);
92 | }
93 | }
94 |
95 | private function findContext(Token $token) {
96 | $group = $this->context->getGroupContext();
97 | $context = 'default';
98 |
99 | // first check the context of the current line
100 | $line = $this->context->getLineContext();
101 | if (!empty($line)) {
102 | $context = $line;
103 | }
104 |
105 | // is it a parens group?
106 | else if ($group->type == Group::GROUP) {
107 | $context = 'grouping';
108 | }
109 |
110 | // a function call?
111 | else if ($group->type == Group::CALL) {
112 | $context = 'function_invocation';
113 | }
114 |
115 | // field access?
116 | else if ($token->contents === '->' || $token->contents === '::') {
117 | $context = 'field_access';
118 | }
119 |
120 | // or a given block statement?
121 | else if ($group->type == Group::BLOCK
122 | && isset(self::$BLOCK_CONTEXT_MAPPING[$group->token->type])) {
123 | $context = self::$BLOCK_CONTEXT_MAPPING[$group->token->type];
124 | }
125 |
126 | return $context;
127 | }
128 |
129 | private function whitespaceBeforeAfter($key, $context = 'default') {
130 | if ($this->config->getWhitespace('before_' . $key, $context)) {
131 | $this->defaultFormatter->addPreWrite(' ');
132 | }
133 |
134 | if ($this->config->getWhitespace('after_' . $key, $context)) {
135 | $this->defaultFormatter->addPostWrite(' ');
136 | }
137 | }
138 |
139 | }
140 |
--------------------------------------------------------------------------------
/src/parser/Analyzer.php:
--------------------------------------------------------------------------------
1 | parser = $parser;
25 | $this->matcher = $parser->getMatcher();
26 | $this->units = new UnitCollection();
27 |
28 | // register listeners
29 | $context = $parser->getContext();
30 | $context->addListener(Context::EVENT_ROUTINE_LEAVE, [$this, 'onRoutineClosed']);
31 | $context->addListener(Context::EVENT_BLOCK_LEAVE, [$this, 'onBlockClosed']);
32 | }
33 |
34 | public function getUnits() {
35 | return $this->units;
36 | }
37 |
38 | public function analyze(TokenCollection $tokens) {
39 | foreach ($tokens as $token) {
40 | $this->parser->getTracker()->visitToken($token);
41 | $this->findUnitStart($token);
42 | $this->findUnitEnd($token);
43 | $this->finish($token);
44 | }
45 | }
46 |
47 | private function findUnitStart(Token $token) {
48 | $detectedUnit = null;
49 | $detectedUnitType = null;
50 |
51 | if ($this->detectedUnit === null && ($this->matcher->isModifier($token)
52 | || $this->matcher->isUnitIdentifier($token))) {
53 | $detectedUnit = $token;
54 | }
55 |
56 | if ($detectedUnit !== null) {
57 |
58 | // traits = use statements in struct body
59 | if ($token->type == T_USE && $this->parser->getContext()->getCurrentContext() == Context::CONTEXT_STRUCT) {
60 | $detectedUnitType = Unit::UNIT_TRAITS;
61 | }
62 |
63 | // line statements
64 | else if ($this->matcher->isUnitIdentifier($token)) {
65 | $detectedUnitType = Unit::getType($token);
66 | }
67 |
68 | // check for properties
69 | else if ($this->matcher->isModifier($token)) {
70 | $nextToken = $token;
71 | do {
72 | $nextToken = $this->parser->getTracker()->nextToken($nextToken);
73 | if ($nextToken !== null && $nextToken->type == T_VARIABLE) {
74 | $detectedUnitType = Unit::UNIT_FIELDS;
75 | break;
76 | } else if ($nextToken !== null && $nextToken->type == T_FUNCTION) {
77 | $detectedUnitType = Unit::UNIT_METHODS;
78 | break;
79 | } else if ($nextToken !== null && $nextToken->type == T_CLASS) {
80 | return;
81 | }
82 | } while ($this->matcher->isModifier($nextToken));
83 | }
84 |
85 | // continue last unit, or start new unit?
86 | if ($detectedUnitType !== Unit::UNIT_METHODS
87 | && $this->currentUnit !== null
88 | && $detectedUnitType === $this->currentUnit->type) {
89 | $prevToken = $token;
90 | do {
91 | $prevToken = $this->parser->getTracker()->prevToken($prevToken);
92 | } while (CommentsFormatter::isComment($prevToken)
93 | || $this->matcher->isModifier($prevToken));
94 |
95 | // yes, new unit
96 | if ($prevToken !== $this->currentUnit->end) {
97 | $this->dumpCurrentUnit();
98 | $this->detectedUnit = $detectedUnit;
99 | $this->detectedUnitType = $detectedUnitType;
100 | }
101 | } else {
102 | $this->dumpCurrentUnit();
103 | $this->detectedUnit = $detectedUnit;
104 | $this->detectedUnitType = $detectedUnitType;
105 | }
106 | }
107 | }
108 |
109 | private function findUnitEnd(Token $token) {
110 | if ($this->detectedUnit !== null) {
111 | if ($token->contents == ';') {
112 | $this->flushDetection($token);
113 | }
114 | }
115 | }
116 |
117 | private function flushDetection(Token $token) {
118 | $this->currentUnit = new Unit();
119 | $this->currentUnit->start = $this->detectedUnit;
120 | $this->currentUnit->type = $this->detectedUnitType;
121 | $this->currentUnit->end = $token;
122 |
123 | $this->detectedUnit = null;
124 | $this->detectedUnitType = null;
125 | }
126 |
127 | public function onRoutineClosed(BlockEvent $event) {
128 | if ($this->parser->getContext()->getCurrentContext() == Context::CONTEXT_STRUCT) {
129 |
130 | $block = $event->getBlock();
131 |
132 | if ($this->currentUnit === null || $block->start != $this->currentUnit->start) {
133 | $this->detectedUnit = $block->start;
134 | $this->detectedUnitType = Unit::UNIT_METHODS;
135 | $this->flushDetection($event->getToken());
136 | }
137 |
138 | $this->dumpCurrentUnit();
139 | }
140 | }
141 |
142 | public function onBlockClosed(BlockEvent $event) {
143 | $block = $event->getBlock();
144 | if ($block->type == Block::TYPE_USE || $block->type == Block::TYPE_NAMESPACE) {
145 | $this->detectedUnit = $block->start;
146 | $this->detectedUnitType = $block->type;
147 | $this->flushDetection($event->getToken());
148 | }
149 | }
150 |
151 | private function finish(Token $token) {
152 | if ($this->parser->getTracker()->isLastToken($token)) {
153 | $this->dumpCurrentUnit();
154 | }
155 | }
156 |
157 | private function dumpCurrentUnit() {
158 | if ($this->currentUnit !== null) {
159 | $this->units->add($this->currentUnit);
160 | $this->currentUnit = null;
161 | }
162 | }
163 |
164 | }
165 |
--------------------------------------------------------------------------------
/src/parser/Context.php:
--------------------------------------------------------------------------------
1 | parser = $parser;
61 | $this->matcher = $parser->getMatcher();
62 | $this->blockStack = new Stack();
63 | $this->groupStack = new Stack();
64 | $this->contextStack = new Stack();
65 | $this->dispatcher = new EventDispatcher();
66 | }
67 |
68 | public function reset() {
69 | // remove listeners
70 | foreach ($this->events as $event) {
71 | $listeners = $this->dispatcher->getListeners($event);
72 | foreach ($listeners as $listener) {
73 | $this->dispatcher->removeListener($event, $listener);
74 | }
75 | }
76 |
77 | // reset data objects
78 | $this->blockStack->clear();
79 | $this->groupStack->clear();
80 | $this->contextStack->clear();
81 | }
82 |
83 | public function setTracker(TokenTracker $tracker) {
84 | $this->tracker = $tracker;
85 | }
86 |
87 | public function addListener($name, $listener) {
88 | $this->dispatcher->addListener($name, $listener);
89 | }
90 |
91 | public function removeListener($name, $listener) {
92 | $this->dispatcher->removeListener($name, $listener);
93 | }
94 |
95 | public function visitToken(Token $token) {
96 | // load current contexts
97 | $this->block = $this->peekBlock();
98 | $this->group = $this->peekGroup();
99 |
100 | // detect new contexts
101 | $this->detectBlockContext($token);
102 | $this->detectGroupContext($token);
103 | $this->detectLineContext($token);
104 | }
105 |
106 | private function detectBlockContext(Token $token) {
107 | if ($this->matcher->isBlock($token)) {
108 | $this->blockDetected = $token;
109 | }
110 |
111 | $this->enterBlockContext($token);
112 | $this->leaveBlockContext($token);
113 |
114 | // neglect block detection
115 | if ($this->blockDetected !== null && $token->contents == ';'
116 | && ($this->group !== null ? !($this->group->type == Group::BLOCK
117 | || $this->group->type == Group::GROUP) : true)) {
118 | $this->blockDetected = null;
119 | }
120 | }
121 |
122 | private function enterBlockContext(Token $token) {
123 | if ($token->contents == '{' && $this->blockDetected !== null) {
124 | $type = Block::getType($this->blockDetected);
125 | if ($type == Block::TYPE_FUNCTION && $this->getCurrentContext() == self::CONTEXT_STRUCT) {
126 | $type = Block::TYPE_METHOD;
127 | }
128 | $block = new Block($type);
129 | $block->start = $this->findBlockStart($this->blockDetected);
130 | $block->open = $token;
131 | $this->blockStack->push($block);
132 | $this->block = $block;
133 | $this->blockDetected = null;
134 |
135 | $event = new BlockEvent($token, $this->block);
136 | $this->dispatcher->dispatch(self::EVENT_BLOCK_ENTER, $event);
137 |
138 | // enter struct context
139 | if ($block->isStruct()) {
140 | $this->inStructBody = true;
141 | $this->dispatcher->dispatch(self::EVENT_STRUCT_ENTER, $event);
142 | $this->contextStack->push(self::CONTEXT_STRUCT);
143 | }
144 |
145 | // enter routine context
146 | else if ($block->isRoutine()) {
147 | $this->inRoutineBody = true;
148 | $this->dispatcher->dispatch(self::EVENT_ROUTINE_ENTER, $event);
149 | $this->contextStack->push(self::CONTEXT_ROUTINE);
150 | }
151 |
152 | // enter block context
153 | else {
154 | $this->contextStack->push(self::CONTEXT_BLOCK);
155 | }
156 | }
157 | }
158 |
159 | private function findBlockStart(Token $token) {
160 | $startToken = $token;
161 | $prevToken = $this->tracker->prevToken($token);
162 |
163 | while ($this->matcher->isModifier($prevToken)) {
164 | $startToken = $prevToken;
165 | $prevToken = $this->tracker->prevToken($prevToken);
166 | }
167 |
168 | return $startToken;
169 | }
170 |
171 | private function leaveBlockContext(Token $token) {
172 | if ($token->contents == '}') {
173 | $this->block = $this->blockStack->pop();
174 |
175 | // find block end
176 | if ($this->block->type == Block::TYPE_DO) {
177 | $nextToken = $token;
178 | do {
179 | $nextToken = $this->tracker->nextToken($nextToken);
180 | } while ($nextToken->contents != ';');
181 | $this->block->end = $nextToken;
182 | } else {
183 | $this->block->end = $token;
184 | }
185 |
186 | $event = new BlockEvent($token, $this->block);
187 | $this->dispatcher->dispatch(self::EVENT_BLOCK_LEAVE, $event);
188 | $this->contextStack->pop();
189 |
190 | // leave struct context
191 | if ($this->inStructBody && $this->block->isStruct()) {
192 | $this->inStructBody = false;
193 | $this->dispatcher->dispatch(self::EVENT_STRUCT_LEAVE, $event);
194 | }
195 |
196 | // leave routine context
197 | else if ($this->inRoutineBody && $this->block->isRoutine()) {
198 | $this->inRoutineBody = false;
199 | $this->dispatcher->dispatch(self::EVENT_ROUTINE_LEAVE, $event);
200 | }
201 | }
202 | }
203 |
204 | public function isBlockContextDetected() {
205 | return $this->blockDetected !== null;
206 | }
207 |
208 | /**
209 | * Tells you, whenever being in a struct, this is also true when inside
210 | * a method or inside a function, which is inside a method
211 | *
212 | * @return bool
213 | */
214 | public function inStructBody() {
215 | return $this->inStructBody;
216 | }
217 |
218 | /**
219 | * Tells you, whenever being in a function or method
220 | *
221 | * @return bool
222 | */
223 | public function inRoutineBody() {
224 | return $this->inRoutineBody;
225 | }
226 |
227 | private function detectGroupContext(Token $token) {
228 | $prevToken = $this->tracker->getPrevToken();
229 | if ($token->contents == '(') {
230 | $group = new Group();
231 | $group->start = $token;
232 | // if (in_array($prevToken->type, Tokenizer::$BLOCKS)
233 | // || in_array($prevToken->type, Tokenizer::$OPERATORS)) {
234 | if (($this->matcher->isBlock($prevToken) || $this->matcher->isOperator($prevToken))
235 | && !$this->group->isBlock()) {
236 | $group->type = Group::BLOCK;
237 | $group->token = $prevToken;
238 | } else if ($this->isFunctionInvocation($token)) {
239 | $group->type = Group::CALL;
240 | $group->token = $prevToken;
241 | } else {
242 | $group->type = Group::GROUP;
243 | }
244 |
245 | $this->groupStack->push($group);
246 | $this->group = $group;
247 |
248 | $event = new GroupEvent($token, $group);
249 | $this->dispatcher->dispatch(self::EVENT_GROUP_ENTER, $event);
250 | } else if ($token->contents == ')') {
251 | $this->group = $this->groupStack->pop();
252 | $this->group->end = $token;
253 |
254 | $event = new GroupEvent($token, $this->group);
255 | $this->dispatcher->dispatch(self::EVENT_GROUP_LEAVE, $event);
256 | }
257 | }
258 |
259 | private function isFunctionInvocation($token) {
260 | $prevToken = $this->tracker->getPrevToken();
261 | return $token->contents == '(' && $prevToken->type == T_STRING;
262 | }
263 |
264 | private function detectLineContext(Token $token) {
265 | if ($this->matcher->isLineContext($token)) {
266 | $this->line = $token->contents;
267 | }
268 | }
269 |
270 | public function resetLineContext() {
271 | $this->line = null;
272 | }
273 |
274 | /**
275 | * Returns the line context or null if not present
276 | *
277 | * @return string|null
278 | */
279 | public function getLineContext() {
280 | return $this->line;
281 | }
282 |
283 | /**
284 | * Returns the current context. Context is one of the Context::CONTEXT_* constants.
285 | *
286 | * @return string
287 | */
288 | public function getCurrentContext() {
289 | if ($this->contextStack->size() > 0) {
290 | return $this->contextStack->peek();
291 | }
292 |
293 | return self::CONTEXT_FILE;
294 | }
295 |
296 | /**
297 | * Returns the current block context
298 | *
299 | * @return Block
300 | */
301 | public function getBlockContext() {
302 | return $this->block;
303 | }
304 |
305 | /**
306 | * Returns the current group context
307 | *
308 | * @return Group|null
309 | */
310 | public function getGroupContext() {
311 | return $this->group;
312 | }
313 |
314 | private function peekBlock() {
315 | if ($this->blockStack->size() > 0) {
316 | return $this->blockStack->peek();
317 | }
318 | return new Block(null);
319 | }
320 |
321 | private function peekGroup() {
322 | if ($this->groupStack->size() > 0) {
323 | return $this->groupStack->peek();
324 | }
325 | return new Group();
326 | }
327 | }
328 |
--------------------------------------------------------------------------------
/src/parser/Lexer.php:
--------------------------------------------------------------------------------
1 | size(); $i < $n; $i++) {
19 | $token = $tokens->get($i);
20 |
21 | // fix ELSEIF
22 | if ($token->type == T_ELSE) {
23 | $nextToken = $tokens->get($i + 1);
24 |
25 | if ($nextToken->type == T_IF) {
26 | $i++;
27 | $fixedTokens->add(new Token([T_ELSEIF, 'else if']));
28 | } else {
29 | $fixedTokens->add($token);
30 | }
31 |
32 | continue;
33 | }
34 |
35 | $fixedTokens->add($token);
36 | }
37 | return $fixedTokens;
38 | }
39 |
40 | /**
41 | *
42 | * @param TokenCollection $tokens
43 | * @return TokenCollection
44 | */
45 | public function filterTokens(TokenCollection $tokens) {
46 | return $tokens->filter(function (Token $token) {
47 | return $token->type != T_WHITESPACE;
48 | });
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/parser/Parser.php:
--------------------------------------------------------------------------------
1 | matcher = new TokenMatcher();
26 | $this->tokenizer = new PhpTokenizer();
27 | $this->lexer = new Lexer();
28 | $this->context = new Context($this);
29 | $this->analyzer = new Analyzer($this);
30 | }
31 |
32 | public function parse($code) {
33 | // get tokens
34 | $tokens = $this->tokenizer->tokenize($code);
35 |
36 | // preparations
37 | $tokens = $this->lexer->filterTokens($tokens);
38 | $tokens = $this->lexer->repair($tokens);
39 |
40 | // helpers
41 | $this->tracker = new TokenTracker($tokens, $this->context);
42 | $this->tokens = $tokens;
43 |
44 | // analyze
45 | $this->analyzer->analyze($tokens);
46 | $this->context->reset();
47 | }
48 |
49 | /**
50 | *
51 | * @return TokenCollection
52 | */
53 | public function getTokens() {
54 | return $this->tokens;
55 | }
56 |
57 | /**
58 | * @return TokenTracker
59 | */
60 | public function getTracker() {
61 | return $this->tracker;
62 | }
63 |
64 | /**
65 | * @return Context
66 | */
67 | public function getContext() {
68 | return $this->context;
69 | }
70 |
71 | /**
72 | * @return Analyzer
73 | */
74 | public function getAnalyzer() {
75 | return $this->analyzer;
76 | }
77 |
78 | /**
79 | * @return TokenMatcher
80 | */
81 | public function getMatcher() {
82 | return $this->matcher;
83 | }
84 |
85 | }
86 |
--------------------------------------------------------------------------------
/src/parser/TokenMatcher.php:
--------------------------------------------------------------------------------
1 | >=', '^='];
25 | public static $OPERATORS = ['&', '&&', 'and', '|', '||', 'or', '^', 'xor', 'instanceof', '==', '>=', '>', '===', '!=', '<>', '!==', '<=', '<', '<<', '>>', '+', '-', '*', '/', '**', 'as'];
26 | public static $STRUCTURAL = [T_CLASS, T_INTERFACE, T_TRAIT, T_NAMESPACE, T_USE, T_FUNCTION];
27 | public static $STRUCTS = [T_CLASS, T_INTERFACE, T_TRAIT];
28 | public static $LINE_CONTEXT = ['echo', 'global', 'static', 'yield', 'case'];
29 |
30 | /** @var Set */
31 | private $keywords;
32 | /** @var Set */
33 | private $blocks;
34 | /** @var Set */
35 | private $casts;
36 | /** @var Set */
37 | private $assignments;
38 | /** @var Set */
39 | private $operators;
40 | /** @var Set */
41 | private $structural;
42 | /** @var Set */
43 | private $structs;
44 | /** @var Set */
45 | private $lineContext;
46 | /** @var Set */
47 | private $imports;
48 | /** @var Set */
49 | private $unitIdentifier;
50 | /** @var Set */
51 | private $modifier;
52 |
53 | public function __construct() {
54 | $this->keywords = new Set([T_ABSTRACT, T_CASE, T_CLASS, T_FUNCTION, T_CLONE, T_CONST,
55 | T_EXTENDS, T_FINAL, T_GLOBAL, T_IMPLEMENTS, T_INTERFACE, T_NAMESPACE, T_NEW,
56 | T_PRIVATE, T_PUBLIC, T_PROTECTED, T_THROW, T_TRAIT, T_USE]);
57 |
58 | $this->blocks = new Set([T_IF, T_ELSEIF, T_ELSE, T_FOR, T_FOREACH, T_WHILE,
59 | T_DO, T_SWITCH, T_TRY, T_CATCH, T_CLASS, T_INTERFACE, T_TRAIT,
60 | T_NAMESPACE, T_USE, T_FUNCTION]);
61 |
62 | $this->casts = new Set([T_ARRAY_CAST, T_BOOL_CAST, T_DOUBLE_CAST, T_INT_CAST,
63 | T_OBJECT_CAST, T_STRING_CAST, T_UNSET_CAST]);
64 |
65 | $this->assignments = new Set(['=', '&=', '.=', '/=', '-=', '%=', '*=', '|=', '+=',
66 | '**=', '<<=', '>>=', '^=']);
67 |
68 | $this->operators = new Set(['&', '&&', 'and', '|', '||', 'or', '^', 'xor',
69 | 'instanceof', '==', '>=', '>', '===', '!=', '<>', '!==', '<=', '<', '<<',
70 | '>>', '+', '-', '*', '/', '**', 'as']);
71 |
72 | $this->structural = new Set([T_CLASS, T_INTERFACE, T_TRAIT, T_NAMESPACE, T_USE, T_FUNCTION]);
73 |
74 | $this->structs = new Set([T_CLASS, T_INTERFACE, T_TRAIT]);
75 |
76 | $this->lineContext = new Set(['echo', 'global', 'static', 'yield', 'case']);
77 |
78 | $this->imports = new Set([T_REQUIRE, T_REQUIRE_ONCE, T_INCLUDE, T_INCLUDE_ONCE]);
79 |
80 | $this->unitIdentifier = new Set([T_CONST, T_NAMESPACE, T_USE]);
81 | $this->unitIdentifier->addAll($this->imports);
82 |
83 | $this->modifier = new Set([T_PRIVATE, T_PUBLIC, T_PROTECTED, T_STATIC, T_VAR, T_ABSTRACT]);
84 | }
85 |
86 | public function isKeyword(Token $token) {
87 | return $this->keywords->contains($token->type);
88 | }
89 |
90 | public function isBlock(Token $token) {
91 | return $this->blocks->contains($token->type);
92 | }
93 |
94 | public function isCast(Token $token) {
95 | return $this->blocks->contains($token->type);
96 | }
97 |
98 | public function isAssignment(Token $token) {
99 | return $this->assignments->contains($token->contents);
100 | }
101 |
102 | public function isOperator(Token $token) {
103 | return $this->operators->contains($token->contents);
104 | }
105 |
106 | public function isStruct(Token $token) {
107 | return $this->operators->contains($token->type);
108 | }
109 |
110 | public function isLineContext(Token $token) {
111 | return $this->lineContext->contains($token->contents);
112 | }
113 |
114 | public function isImport(Token $token) {
115 | return $this->imports->contains($token->type);
116 | }
117 |
118 | public function isUnitIdentifier(Token $token) {
119 | return $this->unitIdentifier->contains($token->type);
120 | }
121 |
122 | public function isModifier(Token $token) {
123 | return $this->modifier->contains($token->type);
124 | }
125 |
126 | }
127 |
--------------------------------------------------------------------------------
/src/parser/TokenTracker.php:
--------------------------------------------------------------------------------
1 | tokens = $tokens;
18 | $this->context = $contextManager;
19 | $this->context->setTracker($this);
20 | }
21 |
22 | public function visitToken(Token $token) {
23 | $this->next = $this->nextToken($token);
24 | $this->prev = $this->prevToken($token);
25 | $this->context->visitToken($token);
26 | }
27 |
28 | public function getNextToken() {
29 | return $this->next;
30 | }
31 |
32 | public function getPrevToken() {
33 | return $this->prev;
34 | }
35 |
36 | public function nextToken(Token $token, $offset = 1) {
37 | $index = $this->tokens->indexOf($token);
38 | $index += $offset;
39 | $token = $this->tokens->get($index);
40 |
41 | if ($token === null) {
42 | $token = new Token();
43 | }
44 |
45 | return $token;
46 | }
47 |
48 | public function prevToken($token, $offset = 1) {
49 | $index = $this->tokens->indexOf($token);
50 | $index -= $offset;
51 | $token = $this->tokens->get($index);
52 |
53 | if ($token === null) {
54 | $token = new Token();
55 | }
56 |
57 | return $token;
58 | }
59 |
60 | public function isLastToken(Token $token) {
61 | return $this->tokens->indexOf($token) == $this->tokens->size() - 1;
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/src/utils/Sanitizer.php:
--------------------------------------------------------------------------------
1 | trimLines();
15 | $this->removeDoubleBlanks();
16 | }
17 |
18 | private function trimLines() {
19 |
20 | }
21 |
22 | private function removeDoubleBlanks() {
23 |
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/utils/Writer.php:
--------------------------------------------------------------------------------
1 | "\t",
18 | 'indentation_size' => 1
19 | ];
20 |
21 | public function __construct($options = []) {
22 | $this->options = array_merge($this->options, $options);
23 |
24 | $this->indentation = str_repeat($this->options['indentation_character'],
25 | $this->options['indentation_size']);
26 | }
27 |
28 | public function indent() {
29 | $this->indentationLevel += 1;
30 |
31 | return $this;
32 | }
33 |
34 | public function outdent() {
35 | $this->indentationLevel -= 1;
36 |
37 | if ($this->indentationLevel < 0) {
38 | throw new \RuntimeException('The identation level cannot be less than zero.');
39 | }
40 |
41 | return $this;
42 | }
43 |
44 | /**
45 | *
46 | * @param string $content
47 | */
48 | public function writeln($content = '') {
49 | $this->write($content . "\n");
50 |
51 | return $this;
52 | }
53 |
54 | /**
55 | *
56 | * @param string $content
57 | */
58 | public function write($content) {
59 | $lines = explode("\n", $content);
60 | for ($i = 0, $c = count($lines); $i < $c; $i ++) {
61 | if ($this->indentationLevel > 0
62 | && !empty($lines[$i])
63 | && (empty($this->content) || "\n" === substr($this->content, -1))) {
64 | $this->content .= str_repeat($this->indentation, $this->indentationLevel);
65 | }
66 |
67 | $this->content .= $lines[$i];
68 |
69 | if ($i + 1 < $c) {
70 | $this->content .= "\n";
71 | }
72 | }
73 |
74 | return $this;
75 | }
76 |
77 | public function rtrim() {
78 | $addNl = "\n" === substr($this->content, -1);
79 | $this->content = rtrim($this->content);
80 |
81 | if ($addNl) {
82 | $this->content .= "\n";
83 | }
84 |
85 | return $this;
86 | }
87 |
88 | public function endsWith($search) {
89 | return substr($this->content, -strlen($search)) === $search;
90 | }
91 |
92 | public function reset() {
93 | $this->content = '';
94 | $this->indentationLevel = 0;
95 |
96 | return $this;
97 | }
98 |
99 | public function getContent() {
100 | return $this->content;
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/tests/fixtures/samples/default/abstract-class.php:
--------------------------------------------------------------------------------
1 | content == self::XYZ) {
18 | doSomething();
19 | }
20 | }
21 |
22 | public function mthd() {
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/tests/fixtures/samples/default/sample1.php:
--------------------------------------------------------------------------------
1 | (1 - 1));
15 | }
16 |
--------------------------------------------------------------------------------
/tests/fixtures/samples/raw/abstract-class.php:
--------------------------------------------------------------------------------
1 | content == self::XYZ) {
26 | doSomething();
27 | }
28 | }
29 | /**
30 | * Description for mthd
31 | *
32 | * @see #__construct
33 | *
34 | * @param string $param Description for $param
35 | * @return void
36 | */
37 | public function mthd($param = false) {
38 |
39 | }
40 | }
--------------------------------------------------------------------------------
/tests/fixtures/samples/raw/class.php:
--------------------------------------------------------------------------------
1 | content == self::XYZ) {
13 | doSomething();
14 | }
15 | }
16 | public function mthd() {
17 |
18 | }
19 | }
--------------------------------------------------------------------------------
/tests/fixtures/samples/raw/sample1.php:
--------------------------------------------------------------------------------
1 | (1-1));}
--------------------------------------------------------------------------------
/tests/formatter/SamplesTest.php:
--------------------------------------------------------------------------------
1 | compareSample('sample1');
12 | }
13 |
14 | public function testClass() {
15 | $this->compareSample('class');
16 | }
17 |
18 | // public function testClassWithDocblock() {
19 | // $this->compareSample('class-phpdoc');
20 | // }
21 | }
22 |
--------------------------------------------------------------------------------
/tests/parser/AnalyzerTest.php:
--------------------------------------------------------------------------------
1 | getRawContent($file);
15 | $parser = new Parser();
16 | $parser->parse($code);
17 | return $parser;
18 | }
19 |
20 | private function getUnits($file) {
21 | return $this->getParser($file)->getAnalyzer()->getUnits();
22 | }
23 |
24 | public function testUnitsOrder() {
25 | $this->assertUnitsOrder($this->getUnits('class'));
26 | }
27 |
28 | public function testUnitsWithDocblockOrder() {
29 | $this->assertUnitsOrder($this->getUnits('class-phpdoc'));
30 | }
31 |
32 | private function assertUnitsOrder(UnitCollection $units) {
33 | $this->assertEquals(Unit::UNIT_NAMESPACE, $units->get(0)->type);
34 | $this->assertEquals(Unit::UNIT_USE, $units->get(1)->type);
35 | $this->assertEquals(Unit::UNIT_TRAITS, $units->get(2)->type);
36 | $this->assertEquals(Unit::UNIT_CONSTANTS, $units->get(3)->type);
37 | $this->assertEquals(Unit::UNIT_FIELDS, $units->get(4)->type);
38 | $this->assertEquals(Unit::UNIT_METHODS, $units->get(5)->type);
39 | }
40 |
41 | public function testUnitsAbstractOrder() {
42 | $units = $this->getUnits('abstract-class');
43 |
44 | $this->assertEquals(Unit::UNIT_NAMESPACE, $units->get(0)->type);
45 | $this->assertEquals(Unit::UNIT_FIELDS, $units->get(1)->type);
46 | $this->assertEquals(Unit::UNIT_METHODS, $units->get(2)->type);
47 | $this->assertEquals(Unit::UNIT_METHODS, $units->get(3)->type);
48 | $this->assertEquals(Unit::UNIT_METHODS, $units->get(4)->type);
49 | $this->assertEquals(Unit::UNIT_METHODS, $units->get(5)->type);
50 | $this->assertEquals(Unit::UNIT_CONSTANTS, $units->get(6)->type);
51 | }
52 |
53 | // public function testUnitsOrderPosition() {
54 |
55 | // }
56 | }
57 |
--------------------------------------------------------------------------------
/tests/parser/ContextTest.php:
--------------------------------------------------------------------------------
1 | getRawContent('sample1');
18 | }
19 |
20 | public function testBlockStack() {
21 | $log = new ArrayList();
22 | $listener = function (BlockEvent $event) use ($log) {
23 | $log->add($event->getName() . ' ' . $event->getBlock()->type);
24 | };
25 |
26 | $parser = new Parser();
27 | $parser->getContext()->addListener(Context::EVENT_BLOCK_ENTER, $listener);
28 | $parser->getContext()->addListener(Context::EVENT_BLOCK_LEAVE, $listener);
29 | $parser->parse($this->getCode());
30 |
31 | $this->assertEquals([
32 | 'context.block_enter if',
33 | 'context.block_leave if',
34 | 'context.block_enter else',
35 | 'context.block_leave else',
36 | 'context.block_enter for',
37 | 'context.block_enter do',
38 | 'context.block_enter if',
39 | 'context.block_leave if',
40 | 'context.block_leave do',
41 | 'context.block_leave for'],
42 | $log->toArray());
43 | }
44 |
45 | public function testBlockPositionsOnSample1() {
46 | $blocks = new ArrayList();
47 | $listener = function (BlockEvent $event) use ($blocks) {
48 | $blocks->add($event->getBlock());
49 | };
50 |
51 | $parser = new Parser();
52 | $parser->getContext()->addListener(Context::EVENT_BLOCK_LEAVE, $listener);
53 | $parser->parse($this->getCode());
54 | $tokens = $parser->getTokens();
55 |
56 | // test: if (first one)
57 | $if = $blocks->get(0);
58 | $this->assertEquals(Block::TYPE_IF, $if->type);
59 | $this->assertEquals($tokens->get(1), $if->start, 'if start token');
60 | $this->assertEquals($tokens->get(12), $if->end, 'if end token');
61 |
62 | // test: for
63 | $for = $blocks->get(4);
64 | $this->assertEquals(Block::TYPE_FOR, $for->type);
65 | $this->assertEquals($tokens->get(20), $for->start, 'for start token');
66 | $this->assertEquals($tokens->get(68), $for->end, 'for end token');
67 |
68 | // test: do
69 | $do = $blocks->get(3);
70 | $this->assertEquals(Block::TYPE_DO, $do->type);
71 | $this->assertEquals($tokens->get(34), $do->start, 'do start token');
72 | $this->assertEquals($tokens->get(67), $do->end, 'do end token');
73 | }
74 |
75 | public function testBlockPositionsOnAbstractClass() {
76 | $blocks = new ArrayList();
77 | $listener = function (BlockEvent $event) use ($blocks) {
78 | $blocks->add($event->getBlock());
79 | };
80 |
81 | $parser = new Parser();
82 | $parser->getContext()->addListener(Context::EVENT_BLOCK_LEAVE, $listener);
83 | $parser->parse($this->getRawContent('abstract-class'));
84 | $tokens = $parser->getTokens();
85 |
86 | // test: class
87 | $class = $blocks->get(3);
88 | $this->assertEquals(Block::TYPE_CLASS, $class->type);
89 | $this->assertEquals($tokens->get(8), $class->start);
90 | $this->assertEquals($tokens->get(59), $class->end);
91 |
92 | // test: static method
93 | $static = $blocks->get(1);
94 | $this->assertEquals(Block::TYPE_METHOD, $static->type);
95 | $this->assertEquals($tokens->get(34), $static->start);
96 | $this->assertEquals($tokens->get(46), $static->end);
97 | }
98 |
99 | public function testGroupStack() {
100 | $log = new ArrayList();
101 | $listener = function (GroupEvent $event) use ($log) {
102 | $log->add($event->getName() . ' ' . $event->getGroup()->type);
103 | };
104 |
105 | $parser = new Parser();
106 | $parser->getContext()->addListener(Context::EVENT_GROUP_ENTER, $listener);
107 | $parser->getContext()->addListener(Context::EVENT_GROUP_LEAVE, $listener);
108 | $parser->parse($this->getCode());
109 |
110 | $this->assertEquals([
111 | // if
112 | 'context.group_enter block',
113 | 'context.group_leave block',
114 | // for
115 | 'context.group_enter block',
116 | 'context.group_leave block',
117 | // call
118 | 'context.group_enter call',
119 | 'context.group_leave call',
120 | // if
121 | 'context.group_enter block',
122 | 'context.group_leave block',
123 | // while
124 | 'context.group_enter block',
125 | // while -> group
126 | 'context.group_enter group',
127 | 'context.group_leave group',
128 | 'context.group_leave block',
129 | ], $log->toArray());
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/tests/token/TokenizerTest.php:
--------------------------------------------------------------------------------
1 | parse($this->getRawContent('sample1'));
15 |
16 | $tokens = $parser->getTokens();
17 | $tracker = $parser->getTracker();
18 |
19 | $firstIf = $tokens->get(1);
20 | $firstIfOpen = $tokens->get(2);
21 |
22 | $this->assertEquals('if', $firstIf->contents);
23 | $this->assertEquals('(', $firstIfOpen->contents);
24 |
25 | $tracker->visitToken($firstIfOpen);
26 | $this->assertEquals($firstIf, $tracker->getPrevToken());
27 |
28 | $tracker->visitToken($firstIf);
29 | $this->assertEquals($firstIfOpen, $tracker->getNextToken());
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/tests/utils/SamplesTrait.php:
--------------------------------------------------------------------------------
1 | getContent('raw/' . $file);
14 | }
15 |
16 | protected function getDefaultContent($file) {
17 | return $this->getContent('default/' . $file);
18 | }
19 |
20 | protected function compareSample($sample) {
21 | $raw = $this->getRawContent($sample);
22 | $formatter = new Formatter();
23 |
24 | // default coding style
25 | $code = $formatter->format($raw);
26 | // if ($sample == 'class') {
27 | // echo $code;
28 | // }
29 | $this->assertEquals($this->getDefaultContent($sample), $code);
30 |
31 | // psr2 coding style
32 | }
33 | }
34 |
--------------------------------------------------------------------------------