Skip to content

Commit 93166ff

Browse files
committed
ClassType::add*() throws exception when method/property/etc already exists (BC break)
1 parent c48096c commit 93166ff

File tree

4 files changed

+63
-14
lines changed

4 files changed

+63
-14
lines changed

readme.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ Readonly properties introduced by PHP 8.1 can be marked via `setReadOnly()`.
164164

165165
------
166166

167-
If the added property, constant, method or parameter already exist, it will be overwritten.
167+
If the added property, constant, method or parameter already exist, it throws exception.
168168

169169
Members can be removed using `removeProperty()`, `removeConstant()`, `removeMethod()` or `removeParameter()`.
170170

src/PhpGenerator/ClassType.php

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,9 @@ public function getTraits(): array
338338

339339
public function addTrait(string $name, array|bool|null $deprecatedParam = null): TraitUse
340340
{
341+
if (isset($this->traits[$name])) {
342+
throw new Nette\InvalidStateException("Cannot add trait '$name', because it already exists.");
343+
}
341344
$this->traits[$name] = $trait = new TraitUse($name, $this);
342345
if (is_array($deprecatedParam)) {
343346
array_map(fn($item) => $trait->addResolution($item), $deprecatedParam);
@@ -356,13 +359,18 @@ public function removeTrait(string $name): static
356359

357360
public function addMember(Method|Property|Constant|EnumCase|TraitUse $member): static
358361
{
359-
match (true) {
360-
$member instanceof Method => $this->methods[strtolower($member->getName())] = $member,
361-
$member instanceof Property => $this->properties[$member->getName()] = $member,
362-
$member instanceof Constant => $this->consts[$member->getName()] = $member,
363-
$member instanceof EnumCase => $this->cases[$member->getName()] = $member,
364-
$member instanceof TraitUse => $this->traits[$member->getName()] = $member,
362+
$name = $member->getName();
363+
[$type, $n] = match (true) {
364+
$member instanceof Method => ['methods', strtolower($name)],
365+
$member instanceof Property => ['properties', $name],
366+
$member instanceof Constant => ['consts', $name],
367+
$member instanceof EnumCase => ['cases', $name],
368+
$member instanceof TraitUse => ['traits', $name],
365369
};
370+
if (isset($this->$type[$n])) {
371+
throw new Nette\InvalidStateException("Cannot add member '$name', because it already exists.");
372+
}
373+
$this->$type[$n] = $member;
366374
return $this;
367375
}
368376

@@ -395,6 +403,9 @@ public function getConstants(): array
395403

396404
public function addConstant(string $name, $value): Constant
397405
{
406+
if (isset($this->consts[$name])) {
407+
throw new Nette\InvalidStateException("Cannot add constant '$name', because it already exists.");
408+
}
398409
return $this->consts[$name] = (new Constant($name))
399410
->setValue($value)
400411
->setPublic();
@@ -434,6 +445,9 @@ public function getCases(): array
434445
/** Adds case to enum */
435446
public function addCase(string $name, string|int|null $value = null): EnumCase
436447
{
448+
if (isset($this->cases[$name])) {
449+
throw new Nette\InvalidStateException("Cannot add cases '$name', because it already exists.");
450+
}
437451
return $this->cases[$name] = (new EnumCase($name))
438452
->setValue($value);
439453
}
@@ -483,6 +497,9 @@ public function getProperty(string $name): Property
483497
*/
484498
public function addProperty(string $name, $value = null): Property
485499
{
500+
if (isset($this->properties[$name])) {
501+
throw new Nette\InvalidStateException("Cannot add property '$name', because it already exists.");
502+
}
486503
return $this->properties[$name] = func_num_args() > 1
487504
? (new Property($name))->setValue($value)
488505
: new Property($name);
@@ -545,12 +562,16 @@ public function getMethod(string $name): Method
545562

546563
public function addMethod(string $name): Method
547564
{
565+
$lower = strtolower($name);
566+
if (isset($this->methods[$lower])) {
567+
throw new Nette\InvalidStateException("Cannot add method '$name', because it already exists.");
568+
}
548569
$method = new Method($name);
549570
if (!$this->isInterface()) {
550571
$method->setPublic();
551572
}
552573

553-
return $this->methods[strtolower($name)] = $method;
574+
return $this->methods[$lower] = $method;
554575
}
555576

556577

tests/PhpGenerator/ClassType.addMember.phpt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ require __DIR__ . '/../bootstrap.php';
1010

1111

1212
$class = (new ClassType('Example'))
13-
->addMember($method = new Nette\PhpGenerator\Method('GETHANDLE'))
1413
->addMember($method = new Nette\PhpGenerator\Method('getHandle'))
1514
->addMember($property = new Nette\PhpGenerator\Property('handle'))
1615
->addMember($const = new Nette\PhpGenerator\Constant('ROLE'))
@@ -23,6 +22,9 @@ Assert::same(['Foo\Bar' => $trait], $class->getTraits());
2322
Assert::same('', $method->getBody());
2423

2524

26-
$class = (new ClassType('Example'))
27-
->setType('interface')
28-
->addMember($method = new Nette\PhpGenerator\Method('getHandle'));
25+
// duplicity
26+
$class = new ClassType('Example');
27+
$class->addMember(new Nette\PhpGenerator\Method('foo'));
28+
Assert::exception(function () use ($class) {
29+
$class->addMember(new Nette\PhpGenerator\Method('FOO'));
30+
}, Nette\InvalidStateException::class, "Cannot add member 'FOO', because it already exists.");

tests/PhpGenerator/ClassType.phpt

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,33 @@ Assert::exception(function () {
173173
}, Nette\InvalidArgumentException::class, 'Argument must be public|protected|private.');
174174

175175

176+
// duplicity
177+
$class = new ClassType('Example');
178+
$class->addConstant('a', 1);
179+
Assert::exception(function () use ($class) {
180+
$class->addConstant('a', 1);
181+
}, Nette\InvalidStateException::class, "Cannot add constant 'a', because it already exists.");
182+
183+
$class->addProperty('a');
184+
Assert::exception(function () use ($class) {
185+
$class->addProperty('a');
186+
}, Nette\InvalidStateException::class, "Cannot add property 'a', because it already exists.");
187+
188+
$class->addMethod('a');
189+
Assert::exception(function () use ($class) {
190+
$class->addMethod('a');
191+
}, Nette\InvalidStateException::class, "Cannot add method 'a', because it already exists.");
192+
193+
Assert::exception(function () use ($class) {
194+
$class->addMethod('A');
195+
}, Nette\InvalidStateException::class, "Cannot add method 'A', because it already exists.");
196+
197+
$class->addTrait('A');
198+
Assert::exception(function () use ($class) {
199+
$class->addTrait('A');
200+
}, Nette\InvalidStateException::class, "Cannot add trait 'A', because it already exists.");
201+
202+
176203
// remove members
177204
$class = new ClassType('Example');
178205
$class->addConstant('a', 1);
@@ -188,8 +215,7 @@ $class->removeProperty('b')->removeProperty('c');
188215
Assert::same(['a'], array_keys($class->getProperties()));
189216

190217
$class->addMethod('a');
191-
$class->addMethod('A');
192218
$class->addMethod('b');
193219
$class->removeMethod('B')->removeMethod('c');
194220

195-
Assert::same(['A'], array_keys($class->getMethods()));
221+
Assert::same(['a'], array_keys($class->getMethods()));

0 commit comments

Comments
 (0)