@@ -46,28 +46,54 @@ function processDirectory(string $dir, Context $context): array {
46
46
return $ fileInfos ;
47
47
}
48
48
49
- function processStubFile (string $ stubFile , Context $ context ): ?FileInfo {
49
+ function processStubFile (string $ stubFile , Context $ context, bool $ includeOnly = false ): ?FileInfo {
50
50
try {
51
51
if (!file_exists ($ stubFile )) {
52
52
throw new Exception ("File $ stubFile does not exist " );
53
53
}
54
54
55
- $ stubFilenameWithoutExtension = str_replace (".stub.php " , "" , $ stubFile );
56
- $ arginfoFile = "{$ stubFilenameWithoutExtension }_arginfo.h " ;
57
- $ legacyFile = "{$ stubFilenameWithoutExtension }_legacy_arginfo.h " ;
55
+ if (!$ includeOnly ) {
56
+ $ stubFilenameWithoutExtension = str_replace (".stub.php " , "" , $ stubFile );
57
+ $ arginfoFile = "{$ stubFilenameWithoutExtension }_arginfo.h " ;
58
+ $ legacyFile = "{$ stubFilenameWithoutExtension }_legacy_arginfo.h " ;
58
59
59
- $ stubCode = file_get_contents ($ stubFile );
60
- $ stubHash = computeStubHash ($ stubCode );
61
- $ oldStubHash = extractStubHash ($ arginfoFile );
62
- if ($ stubHash === $ oldStubHash && !$ context ->forceParse ) {
63
- /* Stub file did not change, do not regenerate. */
64
- return null ;
60
+ $ stubCode = file_get_contents ($ stubFile );
61
+ $ stubHash = computeStubHash ($ stubCode );
62
+ $ oldStubHash = extractStubHash ($ arginfoFile );
63
+ if ($ stubHash === $ oldStubHash && !$ context ->forceParse ) {
64
+ /* Stub file did not change, do not regenerate. */
65
+ return null ;
66
+ }
65
67
}
66
68
67
- initPhpParser ();
68
- $ fileInfo = parseStubFile ($ stubCode );
69
- $ constInfos = $ fileInfo ->getAllConstInfos ();
70
- $ context ->allConstInfos = array_merge ($ context ->allConstInfos , $ constInfos );
69
+ if (!$ fileInfo = $ context ->parsedFiles [$ stubFile ] ?? null ) {
70
+ initPhpParser ();
71
+ $ fileInfo = parseStubFile ($ stubCode ?? file_get_contents ($ stubFile ));
72
+ $ context ->parsedFiles [$ stubFile ] = $ fileInfo ;
73
+
74
+ foreach ($ fileInfo ->dependencies as $ dependency ) {
75
+ // TODO add header search path for extensions?
76
+ $ prefixes = [dirname ($ stubFile ) . "/ " , "" ];
77
+ foreach ($ prefixes as $ prefix ) {
78
+ $ depFile = $ prefix . $ dependency ;
79
+ if (file_exists ($ depFile )) {
80
+ break ;
81
+ }
82
+ $ depFile = null ;
83
+ }
84
+ if (!$ depFile ) {
85
+ throw new Exception ("File $ stubFile includes a file $ dependency which does not exist " );
86
+ }
87
+ processStubFile ($ depFile , $ context , true );
88
+ }
89
+
90
+ $ constInfos = $ fileInfo ->getAllConstInfos ();
91
+ $ context ->allConstInfos = array_merge ($ context ->allConstInfos , $ constInfos );
92
+ }
93
+
94
+ if ($ includeOnly ) {
95
+ return $ fileInfo ;
96
+ }
71
97
72
98
$ arginfoCode = generateArgInfoCode (
73
99
basename ($ stubFilenameWithoutExtension ),
@@ -131,6 +157,8 @@ class Context {
131
157
public $ forceRegeneration = false ;
132
158
/** @var iterable<ConstInfo> */
133
159
public iterable $ allConstInfos = [];
160
+ /** @var FileInfo[] */
161
+ public array $ parsedFiles = [];
134
162
}
135
163
136
164
class ArrayType extends SimpleType {
@@ -2896,6 +2924,8 @@ private function appendInheritedMemberSectionToClassSynopsis(DOMDocument $doc, D
2896
2924
}
2897
2925
2898
2926
class FileInfo {
2927
+ /** @var string[] */
2928
+ public $ dependencies = [];
2899
2929
/** @var ConstInfo[] */
2900
2930
public $ constInfos = [];
2901
2931
/** @var FuncInfo[] */
@@ -3546,6 +3576,14 @@ function handleStatements(FileInfo $fileInfo, array $stmts, PrettyPrinterAbstrac
3546
3576
continue ;
3547
3577
}
3548
3578
3579
+ if ($ stmt instanceof Stmt \Expression) {
3580
+ $ expr = $ stmt ->expr ;
3581
+ if ($ expr instanceof Expr \Include_) {
3582
+ $ fileInfo ->dependencies [] = (string )EvaluatedValue::createFromExpression ($ expr ->expr , null , null , [])->value ;
3583
+ continue ;
3584
+ }
3585
+ }
3586
+
3549
3587
throw new Exception ("Unexpected node {$ stmt ->getType ()}" );
3550
3588
}
3551
3589
}
0 commit comments