Skip to content

Commit a44e30c

Browse files
authored
Merge pull request #1 from machitgarha/constant-support
2 parents 9790721 + a32b9fa commit a44e30c

File tree

9 files changed

+81
-11
lines changed

9 files changed

+81
-11
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
/composer.lock
22
/vendor/
3+
4+
# Cache files
35
.php_cs.cache
6+
.phpunit.result.cache

README.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
[![Build Status](https://travis-ci.com/php-stubs/generator.svg?branch=master)](https://travis-ci.com/github/php-stubs/generator)
44

5-
Use this tool to generate stub declarations for functions, classes, interfaces, and global variables defined in any PHP code. The stubs can subsequently be used to facilitate IDE completion or static analysis via [Psalm](https://getpsalm.org) or potentially other tools. Stub generation is particularly useful for code which mixes definitions with side-effects.
5+
Use this tool to generate stub declarations for functions, classes, interfaces, and global variables defined in any PHP code. The stubs can subsequently be used to facilitate IDE completion or static analysis via [Psalm](https://getpsalm.org) or potentially other tools. Stub generation is particularly useful for code which mixes definitions with side-effects.
66

77
The generator is based on nikic's [PHP-Parser](https://github.com/nikic/PHP-Parser), and the code also relies on several [Symfony](https://symfony.com) components.
88

@@ -155,11 +155,10 @@ The set of symbol types are:
155155
- `StubsGenerator::DOCUMENTED_GLOBALS`: Global variables, but only those with a doc comment.
156156
- `StubsGenerator::UNDOCUMENTED_GLOBALS`: Global variable, but only those without a doc comment.
157157
- `StubsGenerator::GLOBALS`: Shortcut to include both documented and undocumented global variables.
158+
- `StubsGenerator::CONSTANTS`: Constant declarations.
158159
- `StubsGenerator::DEFAULT`: Shortcut to include everything _except_ undocumented global variables.
159160
- `StubsGenerator::ALL`: Shortcut to include everything.
160161

161162
## TODO
162163

163-
- Add support for constants declared with `const`.
164-
- Add support for constants declared with `define()`.
165-
- Consider parsing function and method bodies for these declarations.
164+
- Consider parsing function and method bodies for constant declarations.

src/GenerateStubsCommand.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class GenerateStubsCommand extends Command
3333
['documented-globals', StubsGenerator::DOCUMENTED_GLOBALS],
3434
['undocumented-globals', StubsGenerator::UNDOCUMENTED_GLOBALS],
3535
['globals', StubsGenerator::GLOBALS],
36+
['constants', StubsGenerator::CONSTANTS],
3637
];
3738

3839
/**

src/NodeVisitor.php

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@
55
use PhpParser\Node\Expr\ArrayDimFetch;
66
use PhpParser\Node\Expr\Assign;
77
use PhpParser\Node\Expr\ConstFetch;
8+
use PhpParser\Node\Expr\FuncCall;
89
use PhpParser\Node\Expr\Variable;
910
use PhpParser\Node\Name;
1011
use PhpParser\Node\Scalar\String_;
1112
use PhpParser\Node\Stmt;
1213
use PhpParser\Node\Stmt\Class_;
1314
use PhpParser\Node\Stmt\ClassLike;
1415
use PhpParser\Node\Stmt\ClassMethod;
16+
use PhpParser\Node\Stmt\Const_;
1517
use PhpParser\Node\Stmt\Expression;
1618
use PhpParser\Node\Stmt\Function_;
1719
use PhpParser\Node\Stmt\If_;
@@ -42,6 +44,8 @@ class NodeVisitor extends NodeVisitorAbstract
4244
/** @var bool */
4345
private $needsUndocumentedGlobals;
4446
/** @var bool */
47+
private $needsConstants;
48+
/** @var bool */
4549
private $nullifyGlobals;
4650

4751
/**
@@ -79,6 +83,7 @@ class NodeVisitor extends NodeVisitorAbstract
7983
'classes' => [],
8084
'interfaces' => [],
8185
'traits' => [],
86+
'constants' => [],
8287
'globals' => [],
8388
];
8489

@@ -93,6 +98,7 @@ public function __construct(int $symbols = StubsGenerator::DEFAULT, array $confi
9398
$this->needsInterfaces = ($symbols & StubsGenerator::INTERFACES) !== 0;
9499
$this->needsDocumentedGlobals = ($symbols & StubsGenerator::DOCUMENTED_GLOBALS) !== 0;
95100
$this->needsUndocumentedGlobals = ($symbols & StubsGenerator::UNDOCUMENTED_GLOBALS) !== 0;
101+
$this->needsConstants = ($symbols & StubsGenerator::CONSTANTS) !== 0;
96102

97103
$this->nullifyGlobals = !empty($config['nullify_globals']);
98104

@@ -155,6 +161,14 @@ public function enterNode(Node $node)
155161
if ($this->nullifyGlobals) {
156162
$node->expr->expr = new ConstFetch(new Name('null'));
157163
}
164+
} elseif ($node instanceof Const_) {
165+
$this->isInDeclaration = true;
166+
} elseif (
167+
$node instanceof Expression &&
168+
$node->expr instanceof FuncCall &&
169+
$node->expr->name->parts[0] === 'define'
170+
) {
171+
$this->isInDeclaration = true;
158172
} elseif ($node instanceof If_) {
159173
if (!$this->isInIf) {
160174
// We'll examine the first level inside of an if statement to
@@ -182,6 +196,12 @@ public function leaveNode(Node $node, bool $preserveStack = false)
182196
|| $node instanceof Class_
183197
|| $node instanceof Interface_
184198
|| $node instanceof Trait_
199+
|| $node instanceof Const_
200+
|| (
201+
$node instanceof Expression &&
202+
$node->expr instanceof FuncCall &&
203+
$node->expr->name->parts[0] === 'define'
204+
)
185205
) {
186206
// We're leaving one of these.
187207
$this->isInDeclaration = false;
@@ -336,6 +356,32 @@ private function needsNode(Node $node, string $namespace): bool
336356
&& !trait_exists($fullyQualifiedName);
337357
}
338358

359+
if ($this->needsConstants) {
360+
if ($node instanceof Const_) {
361+
$node->consts = \array_filter(
362+
$node->consts,
363+
function (\PhpParser\Node\Const_ $const) {
364+
$fullyQualifiedName = $const->name->name;
365+
return $this->count('constants', $fullyQualifiedName)
366+
&& !defined($fullyQualifiedName);
367+
}
368+
);
369+
370+
return count($node->consts) > 0;
371+
}
372+
373+
if (
374+
$node instanceof Expression &&
375+
$node->expr instanceof FuncCall &&
376+
$node->expr->name->parts[0] === 'define'
377+
) {
378+
$fullyQualifiedName = $node->expr->args[0]->value->value;
379+
380+
return $this->count('constants', $fullyQualifiedName)
381+
&& !defined($fullyQualifiedName);
382+
}
383+
}
384+
339385
if (($this->needsDocumentedGlobals || $this->needsUndocumentedGlobals)
340386
&& !$this->isInIf // Don't keep conditionally declared globals.
341387
&& $node instanceof Expression

src/StubsGenerator.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,19 +66,26 @@ class StubsGenerator
6666
*/
6767
public const GLOBALS = self::DOCUMENTED_GLOBALS | self::UNDOCUMENTED_GLOBALS;
6868

69+
/**
70+
* Constant symbol type.
71+
*
72+
* @var int
73+
*/
74+
public const CONSTANTS = 64;
75+
6976
/**
7077
* The default set of symbol types.
7178
*
7279
* @var int
7380
*/
74-
public const DEFAULT = self::FUNCTIONS | self::CLASSES | self::TRAITS | self::INTERFACES | self::DOCUMENTED_GLOBALS;
81+
public const DEFAULT = self::FUNCTIONS | self::CLASSES | self::TRAITS | self::INTERFACES | self::DOCUMENTED_GLOBALS | self::CONSTANTS;
7582

7683
/**
7784
* Shortcut to include every symbol type.
7885
*
7986
* @var int
8087
*/
81-
public const ALL = self::FUNCTIONS | self::CLASSES | self::TRAITS | self::INTERFACES | self::GLOBALS;
88+
public const ALL = self::FUNCTIONS | self::CLASSES | self::TRAITS | self::INTERFACES | self::GLOBALS | self::CONSTANTS;
8289

8390
/** @var int */
8491
private $symbols;

test/NodeVisitorTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ public function inputOutputProvider(): array
4444
['globals', 'globals.nullified', StubsGenerator::GLOBALS, [ 'nullify_globals' => true ]],
4545
'junk',
4646
'namespaces',
47+
'constants',
4748
];
4849

4950
$baseDir = __DIR__ . '/files/';

test/files/constants.in.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
/** doc */
4+
const FOO = 'bar';
5+
6+
/** doc */
7+
define('FIZ', 'BUZ');
8+
9+
const A = 1, B = 2;

test/files/constants.out.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
/** doc */
4+
const FOO = 'bar';
5+
6+
/** doc */
7+
\define('FIZ', 'BUZ');
8+
9+
const A = 1, B = 2;

test/files/junk.in.php

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,3 @@
3434
return [
3535
'foo'
3636
];
37-
38-
// TODO: We should start parsing constants!
39-
const FOO = 'bar';
40-
41-
define('FIZ', 'BUZ');

0 commit comments

Comments
 (0)