Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit b9b02a3

Browse files
committed
Property can be abstract / final
1 parent 466918d commit b9b02a3

File tree

6 files changed

+126
-3
lines changed

6 files changed

+126
-3
lines changed

‎readme.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,21 @@ class Demo
699699
}
700700
```
701701

702+
Properties and property hooks can be abstract or final:
703+
704+
```php
705+
$class->addProperty('id')
706+
->setType('int')
707+
->addHook('get')
708+
->setAbstract();
709+
710+
$class->addProperty('role')
711+
->setType('string')
712+
->addHook('set', 'strtolower($value)')
713+
->setFinal();
714+
```
715+
716+
702717
<!---->
703718

704719
Namespace

‎src/PhpGenerator/ClassManipulator.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ private function implementMethod(\ReflectionMethod $rm): Method
116116
private function implementProperty(\ReflectionProperty $rp): Property
117117
{
118118
$property = (new Factory)->fromPropertyReflection($rp);
119-
$property->setHooks([]);
119+
$property->setHooks([])->setAbstract(false);
120120
$this->class->addMember($property);
121121
return $property;
122122
}

‎src/PhpGenerator/Printer.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -380,12 +380,14 @@ private function printProperty(Property $property, bool $readOnlyClass = false,
380380
{
381381
$property->validate();
382382
$type = $property->getType();
383-
$def = (($property->getVisibility() ?: 'public')
383+
$def = ($property->isAbstract() && !$isInterface ? 'abstract ' : '')
384+
. ($property->isFinal() ? 'final ' : '')
385+
. ($property->getVisibility() ?: 'public')
384386
. ($property->isStatic() ? ' static' : '')
385387
. (!$readOnlyClass && $property->isReadOnly() && $type ? ' readonly' : '')
386388
. ''
387389
. ltrim($this->printType($type, $property->isNullable()) . '')
388-
. '$' . $property->getName());
390+
. '$' . $property->getName();
389391

390392
$defaultValue = $property->getValue() === null && !$property->isInitialized()
391393
? ''

‎src/PhpGenerator/Property.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ final class Property
2828
private ?string $type = null;
2929
private bool $nullable = false;
3030
private bool $initialized = false;
31+
private bool $final = false;
32+
private bool $abstract = false;
3133

3234

3335
public function setValue(mixed $val): static
@@ -99,11 +101,46 @@ public function isInitialized(): bool
99101
}
100102

101103

104+
public function setFinal(bool $state = true): static
105+
{
106+
$this->final = $state;
107+
return $this;
108+
}
109+
110+
111+
public function isFinal(): bool
112+
{
113+
return $this->final;
114+
}
115+
116+
117+
public function setAbstract(bool $state = true): static
118+
{
119+
$this->abstract = $state;
120+
return $this;
121+
}
122+
123+
124+
public function isAbstract(): bool
125+
{
126+
return $this->abstract;
127+
}
128+
129+
102130
/** @throws Nette\InvalidStateException */
103131
public function validate(): void
104132
{
105133
if ($this->readOnly && !$this->type) {
106134
throw new Nette\InvalidStateException("Property \$$this->name: Read-only properties are only supported on typed property.");
135+
136+
} elseif ($this->abstract && $this->final) {
137+
throw new Nette\InvalidStateException("Property \$$this->name cannot be abstract and final at the same time.");
138+
139+
} elseif (
140+
$this->abstract
141+
&& !Nette\Utils\Arrays::some($this->getHooks(), fn($hook) => $hook->isAbstract())
142+
) {
143+
throw new Nette\InvalidStateException("Property \$$this->name: Abstract property must have at least one abstract hook.");
107144
}
108145
}
109146

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
/**
4+
* Test: PHP 8.4 abstract/final property
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
use Nette\PhpGenerator\ClassType;
10+
11+
require __DIR__ . '/../bootstrap.php';
12+
13+
14+
$class = (new ClassType('Demo'))
15+
->setAbstract();
16+
17+
$class->addProperty('first')
18+
->setType('string')
19+
->setAbstract()
20+
->addHook('set')
21+
->setAbstract();
22+
23+
$prop = $class->addProperty('second')
24+
->setType('string')
25+
->setAbstract();
26+
27+
$prop->addHook('set')
28+
->setAbstract();
29+
30+
$prop->addHook('get', '123');
31+
32+
$class->addProperty('third')
33+
->setFinal();
34+
35+
same(<<<'XX'
36+
abstract class Demo
37+
{
38+
abstract public string $first { set; }
39+
40+
abstract public string $second {
41+
set;
42+
get => 123;
43+
}
44+
45+
final public $third;
46+
}
47+
48+
XX, (string) $class);
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Nette\PhpGenerator\Property;
6+
use Tester\Assert;
7+
8+
require __DIR__ . '/../bootstrap.php';
9+
10+
11+
Assert::exception(function () {
12+
$property = new Property('a');
13+
$property->setFinal()->setAbstract();
14+
$property->validate();
15+
}, Nette\InvalidStateException::class, 'Property $a cannot be abstract and final at the same time.');
16+
17+
Assert::exception(function () {
18+
$property = new Property('a');
19+
$property->setAbstract();
20+
$property->validate();
21+
}, Nette\InvalidStateException::class, 'Property $a: Abstract property must have at least one abstract hook.');

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /