Skip to content

Commit ee3c15d

Browse files
committed
removed return type from Container::__call() again [Closes nette/utils#338]
The native `: mixed` return type was accidentally reintroduced on Container::__call() by 7cbe717 ("added missing native types"), reviving an incompatibility that had already been fixed once for nette/utils#315 (commit 40afa80). Nette\SmartObject::__call() in nette/utils intentionally declares no native return type (it stays untyped for BC). As long as nobody re-applies the trait, narrowing the inherited untyped __call() to `: mixed` is allowed and everything loads fine - which is why the test suite and Forms' own classes are unaffected. The fatal error appears only when a subclass extends Form/Container AND re-applies the SmartObject trait, e.g.: class MyForm extends Nette\Forms\Form { use Nette\SmartObject; } Then the trait's untyped __call() overrides the already-typed __call(): mixed, which PHP rejects as removing a return type: Declaration of Nette\SmartObject::__call(string $name, array $args) must be compatible with Nette\Forms\Container::__call(string $name, array $args): mixed Re-applying SmartObject on top of a class that already has it is an unusual, unexpected pattern, so the regression slipped through - but it happens in the wild (e.g. via downstream component classes), breaks on all PHP 8.1-8.5, and matches the report that 3.2.8 works but 3.2.9 does not. Dropping the native return type (keeping it in phpDoc) restores compatibility. A regression test covering the trait combination is added.
1 parent 1b7878e commit ee3c15d

2 files changed

Lines changed: 30 additions & 2 deletions

File tree

src/Forms/Container.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -604,8 +604,11 @@ public function addContainer(string|int $name): self
604604
/********************* extension methods ****************d*g**/
605605

606606

607-
/** @param mixed[] $args */
608-
public function __call(string $name, array $args): mixed
607+
/**
608+
* @param mixed[] $args
609+
* @return mixed
610+
*/
611+
public function __call(string $name, array $args)
609612
{
610613
if (isset(self::$extMethods[$name])) {
611614
return (self::$extMethods[$name])($this, ...$args);
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
/**
4+
* Test: A subclass that re-applies the Nette\SmartObject trait must remain
5+
* compatible with Container::__call(). The trait declares __call() without a
6+
* native return type, so Container::__call() must not declare one either,
7+
* otherwise PHP raises a fatal "incompatible declaration" error at compile time.
8+
* @see https://github.com/nette/utils/issues/338
9+
*/
10+
11+
declare(strict_types=1);
12+
13+
use Tester\Assert;
14+
15+
16+
require __DIR__ . '/../bootstrap.php';
17+
18+
19+
class FormWithSmartObject extends Nette\Forms\Form
20+
{
21+
use Nette\SmartObject;
22+
}
23+
24+
25+
Assert::type(Nette\Forms\Form::class, new FormWithSmartObject);

0 commit comments

Comments
 (0)