diff --git a/spec/Prophecy/Doubler/Generator/ClassCodeGeneratorSpec.php b/spec/Prophecy/Doubler/Generator/ClassCodeGeneratorSpec.php index 50fb1704c..3d8cf4484 100644 --- a/spec/Prophecy/Doubler/Generator/ClassCodeGeneratorSpec.php +++ b/spec/Prophecy/Doubler/Generator/ClassCodeGeneratorSpec.php @@ -116,7 +116,7 @@ class CustomClass extends \RuntimeException implements \Prophecy\Doubler\Generat public $name; private $email; -public static function getName(array $fullname = NULL, \ReflectionClass $class, object $instance): ?string { +public static function getName(?array $fullname = NULL, \ReflectionClass $class, object $instance): ?string { return $this->name; } protected function getEmail(?string $default = 'ever.zet@gmail.com') { @@ -272,7 +272,7 @@ function it_overrides_properly_methods_with_args_passed_by_reference( namespace { class CustomClass extends \RuntimeException implements \Prophecy\Doubler\Generator\MirroredInterface { -public function getName(array &$fullname = NULL) { +public function getName(?array &$fullname = NULL) { return $this->name; } diff --git a/src/Prophecy/Doubler/Generator/ClassCodeGenerator.php b/src/Prophecy/Doubler/Generator/ClassCodeGenerator.php index ddc6985cd..a34ad0f40 100644 --- a/src/Prophecy/Doubler/Generator/ClassCodeGenerator.php +++ b/src/Prophecy/Doubler/Generator/ClassCodeGenerator.php @@ -11,6 +11,7 @@ namespace Prophecy\Doubler\Generator; +use Prophecy\Doubler\Generator\Node\ArgumentTypeNode; use Prophecy\Doubler\Generator\Node\ReturnTypeNode; use Prophecy\Doubler\Generator\Node\TypeNodeAbstract; @@ -78,14 +79,14 @@ private function generateMethod(Node\MethodNode $method): string return $php.'}'; } - private function generateTypes(TypeNodeAbstract $typeNode): string + private function generateTypes(TypeNodeAbstract $typeNode, bool $nullable = FALSE): string { if (!$typeNode->getTypes()) { return ''; } // When we require PHP 8 we can stop generating ?foo nullables and remove this first block - if ($typeNode->canUseNullShorthand()) { + if ($typeNode->canUseNullShorthand() || $nullable) { return sprintf( '?%s', $typeNode->getNonNullTypes()[0]); } else { return join('|', $typeNode->getTypes()); @@ -101,7 +102,18 @@ private function generateArguments(array $arguments): array { return array_map(function (Node\ArgumentNode $argument){ - $php = $this->generateTypes($argument->getTypeNode()); + $types = $argument->getTypeNode()->getTypes(); + if ($nullable = $argument->isOptional() && $argument->getDefault() === NULL) { + $count = \count($types); + if ($count === 1 && $types[0] === 'mixed' ) { + $nullable = FALSE; + } + elseif ($count > 1 && !isset($types['null'])) { + $argument->setTypeNode(new ArgumentTypeNode('null', ...$argument->getTypeNode()->getNonNullTypes())); + $nullable = FALSE; + } + } + $php = $this->generateTypes($argument->getTypeNode(), $nullable); $php .= ' '.($argument->isPassedByReference() ? '&' : '');