Completed
Pull Request — master (#601)
by
unknown
02:47
created

DocumentGenerateCommand::isUniqueAnnotation()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 10
rs 9.4285
cc 3
eloc 5
nc 3
nop 2
1
<?php
2
3
/*
4
 * This file is part of the ONGR package.
5
 *
6
 * (c) NFQ Technologies UAB <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace ONGR\ElasticsearchBundle\Command;
13
14
use ONGR\ElasticsearchBundle\Mapping\MetadataCollector;
15
use Symfony\Component\Console\Helper\FormatterHelper;
16
use Symfony\Component\Console\Helper\QuestionHelper;
17
use Symfony\Component\Console\Input\InputInterface;
18
use Symfony\Component\Console\Output\OutputInterface;
19
use Symfony\Component\Console\Question\ConfirmationQuestion;
20
use Symfony\Component\Console\Question\Question;
21
use Symfony\Component\HttpKernel\Kernel;
22
23
class DocumentGenerateCommand extends AbstractManagerAwareCommand
24
{
25
    /**
26
     * @var QuestionHelper
27
     */
28
    private $questionHelper;
29
30
    /**
31
     * {@inheritdoc}
32
     */
33
    protected function configure()
34
    {
35
        parent::configure();
36
37
        $this
38
            ->setName('ongr:es:document:generate')
39
            ->setDescription('Generates a new Elasticsearch document inside a bundle');
40
    }
41
42
    /**
43
     * {@inheritdoc}
44
     */
45
    protected function execute(InputInterface $input, OutputInterface $output)
46
    {
47
        if ($input->hasParameterOption(['--no-interaction', '-n'])) {
48
            throw $this->getException('No interaction mode is not allowed!');
49
        }
50
    }
51
52
    /**
53
     * {@inheritdoc}
54
     */
55
    protected function interact(InputInterface $input, OutputInterface $output)
56
    {
57
        /** @var FormatterHelper $formatter */
58
        $formatter = $this->getHelperSet()->get('formatter');
59
        $this->questionHelper = new QuestionHelper();
60
61
        $output->writeln(
62
            [
63
                '',
64
                $formatter->formatBlock('Welcome to the ONGRElasticsearchBundle document generator', 'bg=blue', true),
65
                '',
66
                'This command helps you generate ONGRElasticsearchBundle documents.',
67
                '',
68
                'First, you need to give the document name you want to generate.',
69
                'You must use the shortcut notation like <comment>AcmeDemoBundle:Post</comment>.',
70
                '',
71
            ]
72
        );
73
74
        /** @var Kernel $kernel */
75
        $kernel = $this->getContainer()->get('kernel');
76
        $bundleNames = array_keys($kernel->getBundles());
77
78
        while (true) {
79
            $document = $this->questionHelper->ask(
80
                $input,
81
                $output,
82
                $this->getQuestion('The Document shortcut name', null, [$this, 'validateDocumentName'], $bundleNames)
83
            );
84
85
            list($bundle, $document) = $this->parseShortcutNotation($document);
86
87
            if (in_array(strtolower($document), $this->getReservedKeywords())) {
88
                $output->writeln(
89
                    $formatter->formatBlock(sprintf('"%s" is a reserved word.', $document), 'bg=red', true)
90
                );
91
                continue;
92
            }
93
94
            try {
95
                if (!file_exists(
96
                    $kernel->getBundle($bundle)->getPath() . '/Document/' . str_replace('\\', '/', $document) . '.php'
97
                )) {
98
                    break;
99
                }
100
101
                $output->writeln(
102
                    $formatter->formatBlock(
103
                        sprintf('Document "%s:%s" already exists.', $bundle, $document),
104
                        'bg=red',
105
                        true
106
                    )
107
                );
108
            } catch (\Exception $e) {
109
                $output->writeln(
110
                    $formatter->formatBlock(sprintf('Bundle "%s" does not exist.', $bundle), 'bg=red', true)
111
                );
112
            }
113
        }
114
115
        $output->writeln($this->getOptionsLabel($this->getDocumentAnnotations(), 'Available types'));
116
        $annotation = $this->questionHelper->ask(
117
            $input,
118
            $output,
119
            $this->getQuestion(
120
                'Document type',
121
                'Document',
122
                [$this, 'validateDocumentAnnotation'],
123
                $this->getDocumentAnnotations()
124
            )
125
        );
126
127
        $documentType = lcfirst($document);
0 ignored issues
show
Bug introduced by
The variable $document does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
128
        if ($annotation == 'Document') {
129
            $documentType = $this->questionHelper->ask(
130
                $input,
131
                $output,
132
                $this->getQuestion(
133
                    "\n" . 'Elasticsearch Document name',
134
                    lcfirst($document),
135
                    [$this, 'validateFieldName']
136
                )
137
            );
138
        }
139
140
        $properties = [];
141
        $output->writeln(['', $formatter->formatBlock('New Document Property', 'bg=blue;fg=white', true)]);
142
143
        while (true) {
144
            $property = [];
145
            $question = $this->getQuestion(
146
                'Property name [<comment>press <info><return></info> to stop</comment>]',
147
                false
148
            );
149
150
            if (!$field = $this->questionHelper->ask($input, $output, $question)) {
151
                break;
152
            }
153
154
            foreach ($properties as $previousProperty) {
155
                if ($previousProperty['field_name'] == $field) {
156
                    $output->writeln($this->getException('Duplicate field name "%s"', [$field])->getMessage());
157
                    continue(2);
158
                }
159
            }
160
161
            try {
162
                $this->validateFieldName($field);
163
            } catch (\InvalidArgumentException $e) {
164
                $output->writeln($e->getMessage());
165
                continue;
166
            }
167
168
            $output->writeln($this->getOptionsLabel($this->getPropertyAnnotations(), 'Available annotations'));
169
            $property['annotation'] = $this->questionHelper->ask(
170
                $input,
171
                $output,
172
                $this->getQuestion(
173
                    'Property annotation',
174
                    'Property',
175
                    [$this, 'validatePropertyAnnotation'],
176
                    $this->getPropertyAnnotations()
177
                )
178
            );
179
180
            $property['field_name'] = $property['property_name'] = $field;
181
182
            switch ($property['annotation']) {
183
                case 'Embedded':
184
                    $property['property_name'] = $this->askForPropertyName($input, $output, $property['field_name']);
185
                    $property['property_class'] = $this->askForPropertyClass($input, $output);
186
187
                    $question = new ConfirmationQuestion("\n<info>Multiple</info> [<comment>no</comment>]: ", false);
188
                    $question->setAutocompleterValues(['yes', 'no']);
189
                    $property['property_multiple'] = $this->questionHelper->ask($input, $output, $question);
190
191
                    $property['property_options'] = $this->askForPropertyOptions($input, $output);
192
                    break;
193 View Code Duplication
                case 'ParentDocument':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
194
                    if (!$this->isUniqueAnnotation($properties, $property['annotation'])) {
195
                        $output->writeln(
196
                            $this
197
                                ->getException('Only one "%s" field can be added', [$property['annotation']])
198
                                ->getMessage()
199
                        );
200
                        continue(2);
201
                    }
202
                    $property['property_class'] = $this->askForPropertyClass($input, $output);
203
                    break;
204
                case 'Property':
205
                    $property['property_name'] = $this->askForPropertyName($input, $output, $property['field_name']);
206
207
                    $output->writeln($this->getOptionsLabel($this->getPropertyTypes(), 'Available types'));
208
                    $property['property_type'] = $this->questionHelper->ask(
209
                        $input,
210
                        $output,
211
                        $this->getQuestion(
212
                            'Property type',
213
                            'string',
214
                            [$this, 'validatePropertyType'],
215
                            $this->getPropertyTypes()
216
                        )
217
                    );
218
219
                    $property['property_options'] = $this->askForPropertyOptions($input, $output);
220
                    break;
221 View Code Duplication
                case 'Ttl':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
222
                    if (!$this->isUniqueAnnotation($properties, $property['annotation'])) {
223
                        $output->writeln(
224
                            $this
225
                                ->getException('Only one "%s" field can be added', [$property['annotation']])
226
                                ->getMessage()
227
                        );
228
                        continue(2);
229
                    }
230
                    $property['property_default'] = $this->questionHelper->ask(
231
                        $input,
232
                        $output,
233
                        $this->getQuestion("\n" . 'Default time to live')
234
                    );
235
                    break;
236
                case 'Id':
237
                    if (!$this->isUniqueAnnotation($properties, $property['annotation'])) {
238
                        $output->writeln(
239
                            $this
240
                                ->getException('Only one "%s" field can be added', [$property['annotation']])
241
                                ->getMessage()
242
                        );
243
                        continue(2);
244
                    }
245
                    break;
246
            }
247
248
            $properties[] = $property;
249
            $output->writeln(['', $formatter->formatBlock('New Document Property', 'bg=blue;fg=white', true)]);
250
        }
251
252
        $this->getContainer()->get('es.generate')->generate(
253
            $this->getContainer()->get('kernel')->getBundle($bundle),
0 ignored issues
show
Bug introduced by
The variable $bundle does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
254
            $document,
255
            $annotation,
256
            $documentType,
257
            $properties
258
        );
259
    }
260
261
    /**
262
     * @param array  $properties
263
     * @param string $annotation
264
     *
265
     * @return string
266
     */
267
    private function isUniqueAnnotation($properties, $annotation)
268
    {
269
        foreach ($properties as $property) {
270
            if ($property['annotation'] == $annotation) {
271
                return false;
272
            }
273
        }
274
275
        return true;
276
    }
277
278
    /**
279
     * Asks for property name
280
     *
281
     * @param InputInterface  $input
282
     * @param OutputInterface $output
283
     * @param string          $default
284
     *
285
     * @return string
286
     */
287 View Code Duplication
    private function askForPropertyName(InputInterface $input, OutputInterface $output, $default = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
288
    {
289
        return $this->questionHelper->ask(
290
            $input,
291
            $output,
292
            $this->getQuestion("\n" . 'Property name in Elasticsearch', $default, [$this, 'validateFieldName'])
293
        );
294
    }
295
296
    /**
297
     * Asks for property options
298
     *
299
     * @param InputInterface  $input
300
     * @param OutputInterface $output
301
     *
302
     * @return string
303
     */
304 View Code Duplication
    private function askForPropertyOptions(InputInterface $input, OutputInterface $output)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
305
    {
306
        return $this->questionHelper->ask(
307
            $input,
308
            $output,
309
            $this->getQuestion(
310
                "\n" . 'Property options [<comment>press <info><return></info> to stop</comment>]',
311
                false,
312
                null,
313
                ['"index"="not_analyzed"', '"analyzer"="standard"']
314
            )
315
        );
316
    }
317
318
    /**
319
     * Asks for property class
320
     *
321
     * @param InputInterface  $input
322
     * @param OutputInterface $output
323
     *
324
     * @return string
325
     */
326 View Code Duplication
    private function askForPropertyClass(InputInterface $input, OutputInterface $output)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
327
    {
328
        return $this->questionHelper->ask(
329
            $input,
330
            $output,
331
            $this->getQuestion(
332
                "\n" . 'Property class',
333
                null,
334
                [$this, 'validatePropertyClass'],
335
                $this->getDocumentClasses()
336
            )
337
        );
338
    }
339
340
    /**
341
     * Returns available document classes
342
     *
343
     * @return array
344
     */
345
    private function getDocumentClasses()
346
    {
347
        /** @var MetadataCollector $metadataCollector */
348
        $metadataCollector = $this->getContainer()->get('es.metadata_collector');
349
        $classes = [];
350
351
        foreach ($this->getContainer()->getParameter('es.managers') as $manager) {
352
            $documents = $metadataCollector->getMappings($manager['mappings']);
353
            foreach ($documents as $document) {
354
                $classes[] = sprintf('%s:%s', $document['bundle'], $document['class']);
355
            }
356
        }
357
358
        return $classes;
359
    }
360
361
    /**
362
     * Parses shortcut notation
363
     *
364
     * @param string $shortcut
365
     *
366
     * @return string[]
367
     * @throws \InvalidArgumentException
368
     */
369
    private function parseShortcutNotation($shortcut)
370
    {
371
        $shortcut = str_replace('/', '\\', $shortcut);
372
373
        if (false === $pos = strpos($shortcut, ':')) {
374
            throw $this->getException(
375
                'The document name isn\'t valid ("%s" given, expecting something like AcmeBundle:Post)',
376
                [$shortcut]
377
            );
378
        }
379
380
        return [substr($shortcut, 0, $pos), substr($shortcut, $pos + 1)];
381
    }
382
383
    /**
384
     * Validates property class
385
     *
386
     * @param string $class
387
     *
388
     * @return string
389
     * @throws \InvalidArgumentException
390
     */
391
    public function validatePropertyClass($class)
392
    {
393
        if (!in_array($class, $this->getDocumentClasses())) {
394
            throw $this->getException(
395
                'The document isn\'t available ("%s" given, expecting one of following: %s)',
396
                [$class, $this->getDocumentClasses()]
397
            );
398
        }
399
400
        return $class;
401
    }
402
403
    /**
404
     * Performs basic checks in document name
405
     *
406
     * @param string $document
407
     *
408
     * @return string
409
     * @throws \InvalidArgumentException
410
     */
411
    public function validateDocumentName($document)
412
    {
413
        if (!preg_match('{^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*:[a-zA-Z0-9_\x7f-\xff\\\/]+$}', $document)) {
414
            throw $this->getException(
415
                'The document name isn\'t valid ("%s" given, expecting something like AcmeBundle:Post)',
416
                [$document]
417
            );
418
        }
419
420
        return $document;
421
    }
422
423
    /**
424
     * Validates field name
425
     *
426
     * @param string $field
427
     *
428
     * @return string
429
     * @throws \InvalidArgumentException
430
     */
431
    public function validateFieldName($field)
432
    {
433
        if (!$field || $field != lcfirst(preg_replace('/[^a-zA-Z]+/', '', $field))) {
434
            throw $this->getException(
435
                'The parameter isn\'t valid ("%s" given, expecting camelcase separated words)',
436
                [$field]
437
            );
438
        }
439
440
        if (in_array(strtolower($field), $this->getReservedKeywords())) {
441
            throw $this->getException('"%s" is a reserved word.', [$field]);
442
        }
443
444
        return $field;
445
    }
446
447
    /**
448
     * Validates property type
449
     *
450
     * @param string $type
451
     *
452
     * @return string
453
     * @throws \InvalidArgumentException
454
     */
455 View Code Duplication
    public function validatePropertyType($type)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
456
    {
457
        if (!in_array($type, $this->getPropertyTypes())) {
458
            throw $this->getException(
459
                'The property type isn\'t valid ("%s" given, expecting one of following: %s)',
460
                [$type, implode(', ', $this->getPropertyTypes())]
461
            );
462
        }
463
464
        return $type;
465
    }
466
467
    /**
468
     * Validates document annotation
469
     *
470
     * @param string $annotation
471
     *
472
     * @return string
473
     * @throws \InvalidArgumentException
474
     */
475 View Code Duplication
    public function validateDocumentAnnotation($annotation)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
476
    {
477
        if (!in_array($annotation, $this->getDocumentAnnotations())) {
478
            throw $this->getException(
479
                'The document annotation isn\'t valid ("%s" given, expecting one of following: %s)',
480
                [$annotation, implode(', ', $this->getDocumentAnnotations())]
481
            );
482
        }
483
484
        return $annotation;
485
    }
486
487
    /**
488
     * Validates property annotation
489
     *
490
     * @param string $annotation
491
     *
492
     * @return string
493
     * @throws \InvalidArgumentException
494
     */
495 View Code Duplication
    public function validatePropertyAnnotation($annotation)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
496
    {
497
        if (!in_array($annotation, $this->getPropertyAnnotations())) {
498
            throw $this->getException(
499
                'The property annotation isn\'t valid ("%s" given, expecting one of following: %s)',
500
                [$annotation, implode(', ', $this->getPropertyAnnotations())]
501
            );
502
        }
503
504
        return $annotation;
505
    }
506
507
    /**
508
     * Returns formatted question
509
     *
510
     * @param string        $question
511
     * @param mixed         $default
512
     * @param callable|null $validator
513
     * @param array|null    $values
514
     *
515
     * @return Question
516
     */
517
    private function getQuestion($question, $default = null, callable $validator = null, array $values = null)
518
    {
519
        $question = new Question(
520
            sprintf('<info>%s</info>%s: ', $question, $default ? sprintf(' [<comment>%s</comment>]', $default) : ''),
521
            $default
522
        );
523
524
        $question
525
            ->setValidator($validator)
526
            ->setAutocompleterValues($values);
527
528
        return $question;
529
    }
530
531
    /**
532
     * Returns options label
533
     *
534
     * @param array  $options
535
     * @param string $suffix
536
     *
537
     * @return string[]
538
     */
539
    private function getOptionsLabel(array $options, $suffix)
540
    {
541
        $label = sprintf('<info>%s:</info> ', $suffix);
542
543
        foreach ($options as &$option) {
544
            $option = sprintf('<comment>%s</comment>', $option);
545
        }
546
547
        return ['', $label . implode(', ', $options) . '.'];
548
    }
549
550
    /**
551
     * Returns formatted exception
552
     *
553
     * @param string $format
554
     * @param array  $args
555
     *
556
     * @return \InvalidArgumentException
557
     */
558
    private function getException($format, $args = [])
559
    {
560
        /** @var FormatterHelper $formatter */
561
        $formatter = $this->getHelperSet()->get('formatter');
562
        return new \InvalidArgumentException($formatter->formatBlock(vsprintf($format, $args), 'bg=red', true));
563
    }
564
565
    /**
566
     * Returns available property types
567
     *
568
     * @return array
569
     */
570
    private function getPropertyTypes()
571
    {
572
        $reflection = new \ReflectionClass('ONGR\ElasticsearchBundle\Annotation\Property');
573
574
        return $this
575
            ->getContainer()
576
            ->get('annotations.cached_reader')
577
            ->getPropertyAnnotation($reflection->getProperty('type'), 'Doctrine\Common\Annotations\Annotation\Enum')
578
            ->value;
579
    }
580
581
    /**
582
     * Returns property annotations
583
     *
584
     * @return string[]
585
     */
586
    private function getPropertyAnnotations()
587
    {
588
        return ['Embedded', 'Id', 'ParentDocument', 'Property', 'Ttl'];
589
    }
590
591
    /**
592
     * Returns document annotations
593
     *
594
     * @return string[]
595
     */
596
    private function getDocumentAnnotations()
597
    {
598
        return ['Document', 'Nested', 'Object'];
599
    }
600
601
    /**
602
     * Returns reserved keywords
603
     *
604
     * @return string[]
605
     */
606
    private function getReservedKeywords()
607
    {
608
        return [
609
            'abstract',
610
            'and',
611
            'array',
612
            'as',
613
            'break',
614
            'callable',
615
            'case',
616
            'catch',
617
            'class',
618
            'clone',
619
            'const',
620
            'continue',
621
            'declare',
622
            'default',
623
            'do',
624
            'else',
625
            'elseif',
626
            'enddeclare',
627
            'endfor',
628
            'endforeach',
629
            'endif',
630
            'endswitch',
631
            'endwhile',
632
            'extends',
633
            'final',
634
            'finally',
635
            'for',
636
            'foreach',
637
            'function',
638
            'global',
639
            'goto',
640
            'if',
641
            'implements',
642
            'interface',
643
            'instanceof',
644
            'insteadof',
645
            'namespace',
646
            'new',
647
            'or',
648
            'private',
649
            'protected',
650
            'public',
651
            'static',
652
            'switch',
653
            'throw',
654
            'trait',
655
            'try',
656
            'use',
657
            'var',
658
            'while',
659
            'xor',
660
            'yield',
661
            'die',
662
            'echo',
663
            'empty',
664
            'exit',
665
            'eval',
666
            'include',
667
            'include_once',
668
            'isset',
669
            'list',
670
            'require',
671
            'require_once',
672
            'return',
673
            'print',
674
            'unset',
675
        ];
676
    }
677
}
678