Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions conf/config.neon
Original file line number Diff line number Diff line change
Expand Up @@ -1774,6 +1774,11 @@ services:
tags:
- phpstan.broker.dynamicFunctionReturnTypeExtension

-
class: PHPStan\Type\Php\StrrevFunctionReturnTypeExtension
tags:
- phpstan.broker.dynamicFunctionReturnTypeExtension

-
class: PHPStan\Type\Php\SubstrDynamicReturnTypeExtension
tags:
Expand Down
73 changes: 73 additions & 0 deletions src/Type/Php/StrrevFunctionReturnTypeExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?php declare(strict_types = 1);

namespace PHPStan\Type\Php;

use PhpParser\Node\Expr\FuncCall;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\FunctionReflection;
use PHPStan\Type\Accessory\AccessoryLowercaseStringType;
use PHPStan\Type\Accessory\AccessoryNonEmptyStringType;
use PHPStan\Type\Accessory\AccessoryNonFalsyStringType;
use PHPStan\Type\Accessory\AccessoryUppercaseStringType;
use PHPStan\Type\Constant\ConstantStringType;
use PHPStan\Type\DynamicFunctionReturnTypeExtension;
use PHPStan\Type\IntersectionType;
use PHPStan\Type\StringType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeCombinator;
use function count;
use function strrev;

final class StrrevFunctionReturnTypeExtension implements DynamicFunctionReturnTypeExtension
{

public function isFunctionSupported(FunctionReflection $functionReflection): bool
{
return $functionReflection->getName() === 'strrev';
}

public function getTypeFromFunctionCall(
FunctionReflection $functionReflection,
FuncCall $functionCall,
Scope $scope,
): Type
{
$args = $functionCall->getArgs();
if (count($args) < 1) {
return new StringType();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return null instead

}

$inputType = $scope->getType($args[0]->value);
$constantStrings = $inputType->getConstantStrings();
if (count($constantStrings) > 0) {
$resultTypes = [];
foreach ($constantStrings as $constantString) {
$resultTypes[] = new ConstantStringType(strrev($constantString->getValue()));
}

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

$accessoryTypes = [];
if ($inputType->isNonFalsyString()->yes()) {
$accessoryTypes[] = new AccessoryNonFalsyStringType();
} elseif ($inputType->isNonEmptyString()->yes()) {
$accessoryTypes[] = new AccessoryNonEmptyStringType();
}
if ($inputType->isLowercaseString()->yes()) {
$accessoryTypes[] = new AccessoryLowercaseStringType();
}
if ($inputType->isUppercaseString()->yes()) {
$accessoryTypes[] = new AccessoryUppercaseStringType();
}

if (count($accessoryTypes) > 0) {
$accessoryTypes[] = new StringType();

return new IntersectionType($accessoryTypes);
}

return new StringType();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return null instead

}

}
37 changes: 37 additions & 0 deletions tests/PHPStan/Analyser/nsrt/strrev.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

namespace Strrev;

use function PHPStan\Testing\assertType;

class Foo
{
/**
* @param string $string
* @param non-empty-string $nonEmptyString
* @param non-falsy-string $nonFalsyString
* @param numeric-string $numericString
* @param lowercase-string $lowercaseString
* @param uppercase-string $uppercaseString
* @param 'foo'|'bar' $constantStrings
*
* @return void
*/
public function test(
string $string,
string $nonEmptyString,
string $nonFalsyString,
string $numericString,
string $lowercaseString,
string $uppercaseString,
string $constantStrings,
) {
assertType('string', strrev($string));
assertType('non-empty-string', strrev($nonEmptyString));
assertType('non-falsy-string', strrev($nonFalsyString));
assertType('non-empty-string', strrev($numericString));
assertType('lowercase-string', strrev($lowercaseString));
assertType('uppercase-string', strrev($uppercaseString));
assertType("'oof'|'rab'", strrev($constantStrings));
}
}
Loading