Skip to content

Commit

Permalink
MethodsClassReflectionExtension for SoapClient magic methods
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Apr 23, 2021
1 parent 179107e commit f6107ad
Show file tree
Hide file tree
Showing 7 changed files with 170 additions and 1 deletion.
2 changes: 1 addition & 1 deletion build/baseline-7.4.neon
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,6 @@ parameters:
path: ../src/Reflection/ReflectionProvider/SetterReflectionProviderProvider.php

-
message: "#^Class class@anonymous/src/Testing/TestCase\\.php\\:270 has an uninitialized property \\$reflectionProvider\\. Give it default value or assign it in the constructor\\.$#"
message: "#^Class class@anonymous/src/Testing/TestCase\\.php\\:271 has an uninitialized property \\$reflectionProvider\\. Give it default value or assign it in the constructor\\.$#"
count: 1
path: ../src/Testing/TestCase.php
5 changes: 5 additions & 0 deletions conf/config.neon
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,11 @@ services:
-
implement: PHPStan\Reflection\Php\PhpMethodReflectionFactory

-
class: PHPStan\Reflection\Php\Soap\SoapClientMethodsClassReflectionExtension
tags:
- phpstan.broker.methodsClassReflectionExtension

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

namespace PHPStan\Reflection\Php\Soap;

use PHPStan\Reflection\ClassMemberReflection;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\FunctionVariant;
use PHPStan\Reflection\MethodReflection;
use PHPStan\TrinaryLogic;
use PHPStan\Type\Generic\TemplateTypeMap;
use PHPStan\Type\MixedType;
use PHPStan\Type\ObjectType;
use PHPStan\Type\Type;

class SoapClientMethodReflection implements MethodReflection
{

private ClassReflection $declaringClass;

private string $name;

public function __construct(ClassReflection $declaringClass, string $name)
{
$this->declaringClass = $declaringClass;
$this->name = $name;
}

public function getDeclaringClass(): ClassReflection
{
return $this->declaringClass;
}

public function isStatic(): bool
{
return false;
}

public function isPrivate(): bool
{
return false;
}

public function isPublic(): bool
{
return true;
}

public function getDocComment(): ?string
{
return null;
}

public function getName(): string
{
return $this->name;
}

public function getPrototype(): ClassMemberReflection
{
return $this;
}

public function getVariants(): array
{
return [
new FunctionVariant(
TemplateTypeMap::createEmpty(),
TemplateTypeMap::createEmpty(),
[],
true,
new MixedType(true)
),
];
}

public function isDeprecated(): TrinaryLogic
{
return TrinaryLogic::createNo();
}

public function getDeprecatedDescription(): ?string
{
return null;
}

public function isFinal(): TrinaryLogic
{
return TrinaryLogic::createNo();
}

public function isInternal(): TrinaryLogic
{
return TrinaryLogic::createNo();
}

public function getThrowType(): ?Type
{
return new ObjectType('SoapFault');
}

public function hasSideEffects(): TrinaryLogic
{
return TrinaryLogic::createYes();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php declare(strict_types = 1);

namespace PHPStan\Reflection\Php\Soap;

use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Reflection\MethodsClassReflectionExtension;

class SoapClientMethodsClassReflectionExtension implements MethodsClassReflectionExtension
{

public function hasMethod(ClassReflection $classReflection, string $methodName): bool
{
return $classReflection->getName() === 'SoapClient' || $classReflection->isSubclassOf('SoapClient');
}

public function getMethod(ClassReflection $classReflection, string $methodName): MethodReflection
{
return new SoapClientMethodReflection($classReflection, $methodName);
}

}
2 changes: 2 additions & 0 deletions src/Testing/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
use PHPStan\Reflection\Php\PhpFunctionReflection;
use PHPStan\Reflection\Php\PhpMethodReflection;
use PHPStan\Reflection\Php\PhpMethodReflectionFactory;
use PHPStan\Reflection\Php\Soap\SoapClientMethodsClassReflectionExtension;
use PHPStan\Reflection\Php\UniversalObjectCratesClassReflectionExtension;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Reflection\ReflectionProvider\ClassBlacklistReflectionProvider;
Expand Down Expand Up @@ -356,6 +357,7 @@ public function create(
$classReflectionExtensionRegistryProvider->addMethodsClassReflectionExtension($phpExtension);
$classReflectionExtensionRegistryProvider->addMethodsClassReflectionExtension(new MixinMethodsClassReflectionExtension([]));
$classReflectionExtensionRegistryProvider->addMethodsClassReflectionExtension($annotationsMethodsClassReflectionExtension);
$classReflectionExtensionRegistryProvider->addMethodsClassReflectionExtension(new SoapClientMethodsClassReflectionExtension());

$setterReflectionProviderProvider->setReflectionProvider($actualReflectionProvider);
}
Expand Down
1 change: 1 addition & 0 deletions tests/PHPStan/Analyser/NodeScopeResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,7 @@ public function dataFileAsserts(): iterable
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-4838.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-4879.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-4820.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-4822.php');
}

/**
Expand Down
33 changes: 33 additions & 0 deletions tests/PHPStan/Analyser/data/bug-4822.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

namespace Bug4822;

use PHPStan\TrinaryLogic;
use function PHPStan\Testing\assertVariableCertainty;

class Foo
{

/**
* @throws \Exception
*/
function save(): void {

}

function doFoo()
{
$soapClient = new \SoapClient('https://example.com/?wsdl');

try {
$response = $soapClient->test();

if (is_array($response)) {
$this->save();
}
} catch (\Exception $e) {
assertVariableCertainty(TrinaryLogic::createMaybe(), $response);
}
}

}

0 comments on commit f6107ad

Please sign in to comment.