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 ;
@@ -67,31 +67,41 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection,
6767 $ this ->cacheReturnTypes ();
6868
6969 $ componentType = new ConstantIntegerType (-1 );
70+
7071 if (count ($ functionCall ->getArgs ()) > 1 ) {
7172 $ componentType = $ scope ->getType ($ functionCall ->getArgs ()[1 ]->value );
7273
74+ if (! $ componentType ->isConstantValue ()->yes ()) {
75+ return $ this ->createAllComponentsReturnType ();
76+ }
77+
78+ $ componentType = $ componentType ->toInteger ();
79+
7380 if (! $ componentType instanceof ConstantIntegerType) {
7481 return $ this ->createAllComponentsReturnType ();
7582 }
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
@@ -129,17 +146,17 @@ private function cacheReturnTypes(): void
129146 }
130147
131148 $ stringType = new StringType ();
132- $ integerType = new IntegerType ( );
149+ $ port = IntegerRangeType:: fromInterval ( 0 , 65535 );
133150 $ falseType = new ConstantBooleanType (false );
134151 $ nullType = new NullType ();
135152
136153 $ stringOrFalseOrNull = TypeCombinator::union ($ stringType , $ falseType , $ nullType );
137- $ integerOrFalseOrNull = TypeCombinator::union ($ integerType , $ falseType , $ nullType );
154+ $ portOrFalseOrNull = TypeCombinator::union ($ port , $ falseType , $ nullType );
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 ,
@@ -150,7 +167,7 @@ private function cacheReturnTypes(): void
150167 $ this ->componentTypesPairedStrings = [
151168 'scheme ' => $ stringType ,
152169 'host ' => $ stringType ,
153- 'port ' => $ integerType ,
170+ 'port ' => $ port ,
154171 'user ' => $ stringType ,
155172 'pass ' => $ stringType ,
156173 'path ' => $ stringType ,
0 commit comments