@@ -19,10 +19,6 @@ class PhpStanType
19
19
'\OCI-Collection ' ,
20
20
];
21
21
22
- private bool $ nullable ;
23
-
24
- private bool $ falsable ;
25
-
26
22
/**
27
23
* @var string[]
28
24
*/
@@ -42,33 +38,17 @@ public function __construct(string|\SimpleXMLElement $data, bool $writeOnly = fa
42
38
$ data = $ regs [1 ];
43
39
}
44
40
45
- //first we try to parse the type string to have a list as clean as possible.
46
- $ nullable = false ;
47
- $ falsable = false ;
48
41
// Let's make the parameter nullable if it is by reference and is used only for writing.
49
42
if ($ writeOnly && $ data !== 'resource ' && $ data !== 'mixed ' ) {
50
43
$ data .= '|null ' ;
51
44
}
52
45
53
46
$ returnTypes = $ this ->explodeTypes ($ data );
54
- //remove 'null' from the list to identify if the signature type should be nullable
55
- if (($ nullablePosition = \array_search ('null ' , $ returnTypes , true )) !== false ) {
56
- $ nullable = true ;
57
- \array_splice ($ returnTypes , (int ) $ nullablePosition , 1 );
58
- }
59
- //remove 'false' from the list to identify if the function return false on error
60
- if (($ falsablePosition = \array_search ('false ' , $ returnTypes , true )) !== false ) {
61
- $ falsable = true ;
62
- \array_splice ($ returnTypes , (int ) $ falsablePosition , 1 );
63
- }
64
- $ count = \count ($ returnTypes );
65
- if ($ count === 0 ) {
66
- $ returnType = '' ;
67
- }
47
+ $ anyNullable = false ;
68
48
foreach ($ returnTypes as &$ returnType ) {
69
49
$ returnType = \trim ($ returnType );
70
50
if (str_contains ($ returnType , '? ' )) {
71
- $ nullable = true ;
51
+ $ anyNullable = true ;
72
52
$ returnType = \str_replace ('? ' , '' , $ returnType );
73
53
}
74
54
// remove the parenthesis only if we are not dealing with a callable
@@ -97,9 +77,10 @@ public function __construct(string|\SimpleXMLElement $data, bool $writeOnly = fa
97
77
98
78
$ returnType = Type::toRootNamespace ($ returnType );
99
79
}
80
+ if ($ anyNullable ) {
81
+ $ returnTypes [] = 'null ' ;
82
+ }
100
83
$ this ->types = array_unique ($ returnTypes );
101
- $ this ->nullable = $ nullable ;
102
- $ this ->falsable = $ falsable ;
103
84
}
104
85
105
86
/**
@@ -136,27 +117,26 @@ public static function selectMostUsefulType(
136
117
public function getDocBlockType (?ErrorType $ errorType = null ): string
137
118
{
138
119
$ returnTypes = $ this ->types ;
139
- //add back either null or false to the return types unless the target function return null or false on error (only relevant on return type)
140
- if ($ this ->falsable && $ errorType !== ErrorType::FALSY ) {
141
- $ returnTypes [] = 'false ' ;
142
- } elseif ($ this ->nullable && $ errorType !== ErrorType::NULLSY ) {
143
- $ returnTypes [] = 'null ' ;
120
+ // If we're turning an error marker into an exception, remove
121
+ // the error marker from the return types
122
+ if (in_array ('false ' , $ returnTypes ) && $ errorType === ErrorType::FALSY ) {
123
+ $ returnTypes = array_diff ($ returnTypes , ['false ' ]);
124
+ }
125
+ if (in_array ('null ' , $ returnTypes ) && $ errorType === ErrorType::NULLSY ) {
126
+ $ returnTypes = array_diff ($ returnTypes , ['null ' ]);
144
127
}
145
128
sort ($ returnTypes );
146
129
$ type = join ('| ' , $ returnTypes );
147
- if ( $ type === ' bool ' && ! $ this -> nullable && $ errorType === ErrorType:: FALSY ) {
148
- // If the function only returns a boolean, since false is for error, true is for success .
149
- // Let's replace this with a "void".
130
+ // If the function only returns a boolean, since false is for error, true is for success.
131
+ // Let's replace this with a "void" .
132
+ if ( $ type === ' bool ' && $ errorType === ErrorType:: FALSY ) {
150
133
return 'void ' ;
151
134
}
152
135
return $ type ;
153
136
}
154
137
155
138
public function getSignatureType (?ErrorType $ errorType = null ): string
156
139
{
157
- //We edit the return type depending of the "onErrorType" of the function. For example, a function that is both nullable and "nullsy" will created a non nullable safe function. Only relevant on return type.
158
- $ nullable = $ errorType === ErrorType::NULLSY ? false : $ this ->nullable ;
159
- $ falsable = $ errorType === ErrorType::FALSY ? false : $ this ->falsable ;
160
140
$ types = $ this ->types ;
161
141
//no typehint exists for those cases
162
142
if (\array_intersect (self ::NO_SIGNATURE_TYPES , $ types ) !== []) {
@@ -172,8 +152,6 @@ public function getSignatureType(?ErrorType $errorType = null): string
172
152
$ type = 'array ' ; //generics cannot be typehinted
173
153
} elseif (str_contains ($ type , 'resource ' )) {
174
154
$ type = '' ; // resource cant be typehinted
175
- } elseif (str_contains ($ type , 'null ' )) {
176
- $ type = '' ; // null is a real typehint
177
155
} elseif (str_contains ($ type , 'true ' )) {
178
156
$ type = 'bool ' ; // php8.1 doesn't support "true" as a typehint
179
157
} elseif (str_contains ($ type , 'non-falsy-string ' )) {
@@ -186,10 +164,21 @@ public function getSignatureType(?ErrorType $errorType = null): string
186
164
$ types = array_unique ($ types );
187
165
sort ($ types );
188
166
167
+ // If we're turning false/null into exceptions, then
168
+ // remove false/null from the return types
169
+ if ($ errorType === ErrorType::FALSY ) {
170
+ $ types = array_diff ($ types , ['false ' ]);
171
+ }
172
+ if ($ errorType === ErrorType::NULLSY ) {
173
+ $ types = array_diff ($ types , ['null ' ]);
174
+ }
175
+ // remove "null" from the union so we can add "?" later
176
+ $ nullable = in_array ('null ' , $ types );
177
+ $ types = array_diff ($ types , ['null ' ]);
189
178
if (count ($ types ) === 0 ) {
190
179
return '' ;
191
180
} elseif (count ($ types ) === 1 ) {
192
- $ finalType = $ types [0 ];
181
+ $ finalType = array_values ( $ types) [0 ];
193
182
if ($ finalType === 'bool ' && !$ nullable && $ errorType === ErrorType::FALSY ) {
194
183
// If the function only returns a boolean, since false is for
195
184
// error, true is for success. Let's replace this with a "void".
0 commit comments