diff --git a/src/PhpGenerator/InterfaceType.php b/src/PhpGenerator/InterfaceType.php index 8743f8d0..9d884121 100644 --- a/src/PhpGenerator/InterfaceType.php +++ b/src/PhpGenerator/InterfaceType.php @@ -19,6 +19,7 @@ final class InterfaceType extends ClassLike { use Traits\ConstantsAware; use Traits\MethodsAware; + use Traits\PropertiesAware; /** @var string[] */ private array $extends = []; @@ -54,12 +55,13 @@ public function addExtend(string $name): static /** * Adds a member. If it already exists, throws an exception or overwrites it if $overwrite is true. */ - public function addMember(Method|Constant $member, bool $overwrite = false): static + public function addMember(Method|Constant|Property $member, bool $overwrite = false): static { $name = $member->getName(); [$type, $n] = match (true) { $member instanceof Constant => ['consts', $name], $member instanceof Method => ['methods', strtolower($name)], + $member instanceof Property => ['properties', $name], }; if (!$overwrite && isset($this->$type[$n])) { throw new Nette\InvalidStateException("Cannot add member '$name', because it already exists."); @@ -75,5 +77,6 @@ public function __clone(): void $clone = fn($item) => clone $item; $this->consts = array_map($clone, $this->consts); $this->methods = array_map($clone, $this->methods); + $this->properties = array_map($clone, $this->properties); } } diff --git a/src/PhpGenerator/Printer.php b/src/PhpGenerator/Printer.php index c401b139..949ed3dd 100644 --- a/src/PhpGenerator/Printer.php +++ b/src/PhpGenerator/Printer.php @@ -198,9 +198,11 @@ public function printClass( } $properties = []; - if ($class instanceof ClassType || $class instanceof TraitType) { + if ($class instanceof ClassType || $class instanceof TraitType || $class instanceof InterfaceType) { foreach ($class->getProperties() as $property) { - $properties[] = $this->printProperty($property, $readOnlyClass); + if (!$class instanceof InterfaceType || ($property->hasGetHook() || $property->hasSetHook())) { + $properties[] = $this->printProperty($property, $readOnlyClass, $class->isInterface()); + } } } @@ -375,7 +377,7 @@ private function printConstant(Constant $const): string } - private function printProperty(Property $property, bool $readOnlyClass = false): string + private function printProperty(Property $property, bool $readOnlyClass = false, bool $isInterface = false): string { $property->validate(); $type = $property->getType(); @@ -386,9 +388,9 @@ private function printProperty(Property $property, bool $readOnlyClass = false): . ltrim($this->printType($type, $property->isNullable()) . ' ') . '$' . $property->getName()); - $hooks = $this->printHooks($property); + $hooks = $this->printHooks($property, $isInterface); - $defaultValue = $property->getValue() === null && !$property->isInitialized() + $defaultValue = $isInterface || ($property->getValue() === null && !$property->isInitialized()) ? '' : ' = ' . $this->dump($property->getValue(), strlen($def) + 3); // 3 = ' = ' @@ -496,7 +498,7 @@ protected function isBraceOnNextLine(bool $multiLine, bool $hasReturnType): bool } - private function printHooks(Property $property): ?string + private function printHooks(Property $property, bool $isInterface = false): ?string { $getHook = $property->getGetHook(); $setHook = $property->getSetHook(); @@ -505,15 +507,19 @@ private function printHooks(Property $property): ?string return null; } - $out = " {\n"; + $out = ' {' . ($isInterface ? ' ' : "\n"); if ($getHook !== null) { - $out .= $this->indent("get {\n" . $this->indent($this->printFunctionBody($getHook)) . "}\n"); + $out .= $isInterface + ? 'get; ' + : $this->indent("get {\n" . $this->indent($this->printFunctionBody($getHook)) . "}\n"); } if ($setHook !== null) { $params = $this->printParameters($setHook); - $out .= $this->indent('set ' . $params . ' {' . "\n" . $this->indent($this->printFunctionBody($setHook)) . "}\n"); + $out .= $isInterface + ? 'set; ' + : $this->indent('set ' . $params . ' {' . "\n" . $this->indent($this->printFunctionBody($setHook)) . "}\n"); } return $out . '}'; diff --git a/tests/PhpGenerator/Property.hooks.interfaces.phpt b/tests/PhpGenerator/Property.hooks.interfaces.phpt new file mode 100644 index 00000000..28bc918f --- /dev/null +++ b/tests/PhpGenerator/Property.hooks.interfaces.phpt @@ -0,0 +1,48 @@ +setStrictTypes(); + +$namespace = $file->addNamespace('Abc'); + +$interface = new InterfaceType('HasAuthor'); + +// This will not be printed because it does not have any hooks +$interface->addProperty('isVisible') + ->setType(Type::Bool) + ->setPublic(); + +$interface->addProperty('score') + ->setType(Type::Int) + ->setPublic() + ->setGetHook(new PropertyHook); + +$interface->addProperty('author') + ->setType('Author') + ->setPublic() + ->setGetHook(new PropertyHook) + ->setSetHook(new PropertyHook); + +$expected = <<<'PHP' + interface HasAuthor + { + public int $score { get; } + public Author $author { get; set; } + } + PHP; + +same(rtrim($expected), rtrim((new PsrPrinter)->printClass($interface)));