Skip to content

Commit

Permalink
Merge pull request #231 from IanDelMar/wp-parse-url
Browse files Browse the repository at this point in the history
Fix/update extension for wp_parse_url
  • Loading branch information
szepeviktor authored Jun 28, 2024
2 parents 37ef209 + 2a284d8 commit 9d9e32a
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 24 deletions.
59 changes: 38 additions & 21 deletions src/WpParseUrlFunctionDynamicReturnTypeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
use PHPStan\Type\Constant\ConstantBooleanType;
use PHPStan\Type\Constant\ConstantIntegerType;
use PHPStan\Type\Constant\ConstantStringType;
use PHPStan\Type\IntegerType;
use PHPStan\Type\IntegerRangeType;
use PHPStan\Type\NullType;
use PHPStan\Type\StringType;
use PHPStan\Type\Type;
Expand Down Expand Up @@ -67,31 +67,41 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection,
$this->cacheReturnTypes();

$componentType = new ConstantIntegerType(-1);

if (count($functionCall->getArgs()) > 1) {
$componentType = $scope->getType($functionCall->getArgs()[1]->value);

if (! $componentType->isConstantValue()->yes()) {
return $this->createAllComponentsReturnType();
}

$componentType = $componentType->toInteger();

if (! $componentType instanceof ConstantIntegerType) {
return $this->createAllComponentsReturnType();
}
}

$urlType = $scope->getType($functionCall->getArgs()[0]->value);
if (count($urlType->getConstantStrings()) !== 0) {
$returnTypes = [];
if (count($urlType->getConstantStrings()) > 0) {
$types = [];
foreach ($urlType->getConstantStrings() as $constantString) {
try {
// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
$result = @parse_url($constantString->getValue(), $componentType->getValue());
$returnTypes[] = $scope->getTypeFromValue($result);
} catch (\ValueError $e) {
$returnTypes[] = new ConstantBooleanType(false);
$types[] = new ConstantBooleanType(false);
continue;
}

$types[] = $scope->getTypeFromValue($result);
}
return TypeCombinator::union(...$returnTypes);

return TypeCombinator::union(...$types);
}

if ($componentType->getValue() === -1) {
return $this->createAllComponentsReturnType();
return TypeCombinator::union($this->createComponentsArray(), new ConstantBooleanType(false));
}

return $this->componentTypesPairedConstants[$componentType->getValue()] ?? new ConstantBooleanType(false);
Expand All @@ -102,24 +112,31 @@ private function createAllComponentsReturnType(): Type
if ($this->allComponentsTogetherType === null) {
$returnTypes = [
new ConstantBooleanType(false),
new NullType(),
IntegerRangeType::fromInterval(0, 65535),
new StringType(),
$this->createComponentsArray(),
];

$builder = ConstantArrayTypeBuilder::createEmpty();
$this->allComponentsTogetherType = TypeCombinator::union(...$returnTypes);
}

if ($this->componentTypesPairedStrings === null) {
throw new \PHPStan\ShouldNotHappenException();
}
return $this->allComponentsTogetherType;
}

foreach ($this->componentTypesPairedStrings as $componentName => $componentValueType) {
$builder->setOffsetValueType(new ConstantStringType($componentName), $componentValueType, true);
}
private function createComponentsArray(): Type
{
$builder = ConstantArrayTypeBuilder::createEmpty();

$returnTypes[] = $builder->getArray();
if ($this->componentTypesPairedStrings === null) {
throw new \PHPStan\ShouldNotHappenException();
}

$this->allComponentsTogetherType = TypeCombinator::union(...$returnTypes);
foreach ($this->componentTypesPairedStrings as $componentName => $componentValueType) {
$builder->setOffsetValueType(new ConstantStringType($componentName), $componentValueType, true);
}

return $this->allComponentsTogetherType;
return $builder->getArray();
}

private function cacheReturnTypes(): void
Expand All @@ -129,17 +146,17 @@ private function cacheReturnTypes(): void
}

$stringType = new StringType();
$integerType = new IntegerType();
$port = IntegerRangeType::fromInterval(0, 65535);
$falseType = new ConstantBooleanType(false);
$nullType = new NullType();

$stringOrFalseOrNull = TypeCombinator::union($stringType, $falseType, $nullType);
$integerOrFalseOrNull = TypeCombinator::union($integerType, $falseType, $nullType);
$portOrFalseOrNull = TypeCombinator::union($port, $falseType, $nullType);

$this->componentTypesPairedConstants = [
PHP_URL_SCHEME => $stringOrFalseOrNull,
PHP_URL_HOST => $stringOrFalseOrNull,
PHP_URL_PORT => $integerOrFalseOrNull,
PHP_URL_PORT => $portOrFalseOrNull,
PHP_URL_USER => $stringOrFalseOrNull,
PHP_URL_PASS => $stringOrFalseOrNull,
PHP_URL_PATH => $stringOrFalseOrNull,
Expand All @@ -150,7 +167,7 @@ private function cacheReturnTypes(): void
$this->componentTypesPairedStrings = [
'scheme' => $stringType,
'host' => $stringType,
'port' => $integerType,
'port' => $port,
'user' => $stringType,
'pass' => $stringType,
'path' => $stringType,
Expand Down
6 changes: 3 additions & 3 deletions tests/data/wp_parse_url.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
assertType("array{scheme: 'http', host: 'def.abc'}", $value);

$value = wp_parse_url('http://def.abc', $integer);
assertType('array{scheme?: string, host?: string, port?: int, user?: string, pass?: string, path?: string, query?: string, fragment?: string}|false', $value);
assertType('array{scheme?: string, host?: string, port?: int<0, 65535>, user?: string, pass?: string, path?: string, query?: string, fragment?: string}|int<0, 65535>|string|false|null', $value);

$value = wp_parse_url('http://def.abc', PHP_URL_FRAGMENT);
assertType('null', $value);
Expand All @@ -45,10 +45,10 @@
assertType('false', $value);

$value = wp_parse_url($string, PHP_URL_PORT);
assertType('int|false|null', $value);
assertType('int<0, 65535>|false|null', $value);

$value = wp_parse_url($string);
assertType('array{scheme?: string, host?: string, port?: int, user?: string, pass?: string, path?: string, query?: string, fragment?: string}|false', $value);
assertType('array{scheme?: string, host?: string, port?: int<0, 65535>, user?: string, pass?: string, path?: string, query?: string, fragment?: string}|false', $value);

/** @var 'http://def.abc'|'https://example.com' $union */
$union = $union;
Expand Down

0 comments on commit 9d9e32a

Please sign in to comment.