diff --git a/src/Prophecy/Doubler/Generator/ClassCodeGenerator.php b/src/Prophecy/Doubler/Generator/ClassCodeGenerator.php index ddc6985c..a34ad0f4 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() ? '&' : '');