1919use PHPStan \Type \Constant \ConstantBooleanType ;
2020use PHPStan \Type \Constant \ConstantIntegerType ;
2121use PHPStan \Type \Constant \ConstantStringType ;
22- use PHPStan \Type \IntegerType ;
22+ use PHPStan \Type \IntegerRangeType ;
2323use PHPStan \Type \NullType ;
2424use PHPStan \Type \StringType ;
2525use PHPStan \Type \Type ;
@@ -66,32 +66,42 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection,
6666
6767 $ this ->cacheReturnTypes ();
6868
69- $ componentType = new ConstantIntegerType (-1 );
7069 if (count ($ functionCall ->getArgs ()) > 1 ) {
7170 $ componentType = $ scope ->getType ($ functionCall ->getArgs ()[1 ]->value );
7271
72+ if (! $ componentType ->isConstantValue ()->yes ()) {
73+ return $ this ->createAllComponentsReturnType ();
74+ }
75+
76+ $ componentType = $ componentType ->toInteger ();
77+
7378 if (! $ componentType instanceof ConstantIntegerType) {
7479 return $ this ->createAllComponentsReturnType ();
7580 }
81+ } else {
82+ $ componentType = new ConstantIntegerType (-1 );
7683 }
7784
7885 $ urlType = $ scope ->getType ($ functionCall ->getArgs ()[0 ]->value );
79- if (count ($ urlType ->getConstantStrings ()) !== 0 ) {
80- $ returnTypes = [];
86+ if (count ($ urlType ->getConstantStrings ()) > 0 ) {
87+ $ types = [];
8188 foreach ($ urlType ->getConstantStrings () as $ constantString ) {
8289 try {
8390 // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
8491 $ result = @parse_url ($ constantString ->getValue (), $ componentType ->getValue ());
85- $ returnTypes [] = $ scope ->getTypeFromValue ($ result );
8692 } catch (\ValueError $ e ) {
87- $ returnTypes [] = new ConstantBooleanType (false );
93+ $ types [] = new ConstantBooleanType (false );
94+ continue ;
8895 }
96+
97+ $ types [] = $ scope ->getTypeFromValue ($ result );
8998 }
90- return TypeCombinator::union (...$ returnTypes );
99+
100+ return TypeCombinator::union (...$ types );
91101 }
92102
93103 if ($ componentType ->getValue () === -1 ) {
94- return $ this ->createAllComponentsReturnType ( );
104+ return TypeCombinator:: union ( $ this ->createComponentsArray (), new ConstantBooleanType ( false ) );
95105 }
96106
97107 return $ this ->componentTypesPairedConstants [$ componentType ->getValue ()] ?? new ConstantBooleanType (false );
@@ -102,24 +112,31 @@ private function createAllComponentsReturnType(): Type
102112 if ($ this ->allComponentsTogetherType === null ) {
103113 $ returnTypes = [
104114 new ConstantBooleanType (false ),
115+ new NullType (),
116+ IntegerRangeType::fromInterval (0 , 65535 ),
117+ new StringType (),
118+ $ this ->createComponentsArray (),
105119 ];
106120
107- $ builder = ConstantArrayTypeBuilder::createEmpty ();
121+ $ this ->allComponentsTogetherType = TypeCombinator::union (...$ returnTypes );
122+ }
108123
109- if ($ this ->componentTypesPairedStrings === null ) {
110- throw new \PHPStan \ShouldNotHappenException ();
111- }
124+ return $ this ->allComponentsTogetherType ;
125+ }
112126
113- foreach ( $ this -> componentTypesPairedStrings as $ componentName => $ componentValueType ) {
114- $ builder -> setOffsetValueType ( new ConstantStringType ( $ componentName ), $ componentValueType , true );
115- }
127+ private function createComponentsArray (): Type
128+ {
129+ $ builder = ConstantArrayTypeBuilder:: createEmpty ();
116130
117- $ returnTypes [] = $ builder ->getArray ();
131+ if ($ this ->componentTypesPairedStrings === null ) {
132+ throw new \PHPStan \ShouldNotHappenException ();
133+ }
118134
119- $ this ->allComponentsTogetherType = TypeCombinator::union (...$ returnTypes );
135+ foreach ($ this ->componentTypesPairedStrings as $ componentName => $ componentValueType ) {
136+ $ builder ->setOffsetValueType (new ConstantStringType ($ componentName ), $ componentValueType , true );
120137 }
121138
122- return $ this -> allComponentsTogetherType ;
139+ return $ builder -> getArray () ;
123140 }
124141
125142 private function cacheReturnTypes (): void
@@ -128,18 +145,18 @@ private function cacheReturnTypes(): void
128145 return ;
129146 }
130147
131- $ stringType = new StringType ();
132- $ integerType = new IntegerType ( );
133- $ falseType = new ConstantBooleanType (false );
134- $ nullType = new NullType ();
148+ $ string = new StringType ();
149+ $ port = IntegerRangeType:: fromInterval ( 0 , 65535 );
150+ $ false = new ConstantBooleanType (false );
151+ $ null = new NullType ();
135152
136- $ stringOrFalseOrNull = TypeCombinator::union ($ stringType , $ falseType , $ nullType );
137- $ integerOrFalseOrNull = TypeCombinator::union ($ integerType , $ falseType , $ nullType );
153+ $ stringOrFalseOrNull = TypeCombinator::union ($ string , $ false , $ null );
154+ $ portOrFalseOrNull = TypeCombinator::union ($ port , $ false , $ null );
138155
139156 $ this ->componentTypesPairedConstants = [
140157 PHP_URL_SCHEME => $ stringOrFalseOrNull ,
141158 PHP_URL_HOST => $ stringOrFalseOrNull ,
142- PHP_URL_PORT => $ integerOrFalseOrNull ,
159+ PHP_URL_PORT => $ portOrFalseOrNull ,
143160 PHP_URL_USER => $ stringOrFalseOrNull ,
144161 PHP_URL_PASS => $ stringOrFalseOrNull ,
145162 PHP_URL_PATH => $ stringOrFalseOrNull ,
@@ -148,14 +165,14 @@ private function cacheReturnTypes(): void
148165 ];
149166
150167 $ this ->componentTypesPairedStrings = [
151- 'scheme ' => $ stringType ,
152- 'host ' => $ stringType ,
153- 'port ' => $ integerType ,
154- 'user ' => $ stringType ,
155- 'pass ' => $ stringType ,
156- 'path ' => $ stringType ,
157- 'query ' => $ stringType ,
158- 'fragment ' => $ stringType ,
168+ 'scheme ' => $ string ,
169+ 'host ' => $ string ,
170+ 'port ' => $ port ,
171+ 'user ' => $ string ,
172+ 'pass ' => $ string ,
173+ 'path ' => $ string ,
174+ 'query ' => $ string ,
175+ 'fragment ' => $ string ,
159176 ];
160177 }
161178}
0 commit comments