phpstan / phpstan-nette

Nette Framework class reflection extension for PHPStan & framework-specific rules
MIT License
100 stars 34 forks source link

Form events errors #82

Open martenb opened 2 years ago

martenb commented 2 years ago

Hi, i have problems with latest nette/forms and phpstan 1.0.. i will describe it on presenter, but same errors are in control...

<?php declare(strict_types = 1);

namespace App\Presenters;

use Nette\Application\UI\Form;
use Nette\Application\UI\Presenter;
use Nette\Utils\ArrayHash;

final class HomepagePresenter extends Presenter
{

    protected function createCompomentForm(): Form
    {
        $form = new Form();
        $form->onSuccess[] = function (Form $form, ArrayHash $values): void {

        };
        $form->onSuccess[] = [$this, 'formOnSuccess'];

        return $form;
    }

    public function formOnSuccess(Form $form, ArrayHash $values): void
    {

    }

}
 ------ ---------------------------------------------------------------------------------
  Line   Presenters/HomepagePresenter.php
 ------ ---------------------------------------------------------------------------------
  15     Array (array<callable(Nette\Application\UI\Form, mixed): void>) does not accept
         Closure(Nette\Application\UI\Form, Nette\Utils\ArrayHash): void.
  18     Array (array<callable(Nette\Application\UI\Form, mixed): void>) does not accept
         array{$this(App\Presenters\HomepagePresenter), 'formOnSuccess'}.
 ------ ---------------------------------------------------------------------------------
ondrejmirtes commented 2 years ago

Given the types from the stub: https://github.com/phpstan/phpstan-nette/blob/f4654b27b107241e052755ec187a0b1964541ba6/stubs/Forms/Form.stub#L8-L9

    /** @var array<callable(static, mixed): void> */
    public $onSuccess;

this is expected behaviour by PHPStan. Because you're narrowing down the type of the second parameter from mixed to ArrayHash.

I understand that Nette contains some magic (https://github.com/nette/forms/blob/0f0c770db65ce2a18fc766b8b718b53e081ac8e2/src/Forms/Form.php#L424-L442) that will prevent this bug from happening. But PHPStan currently doesn't have the facilities to describe this behaviour, so feel free to just ignore the error: https://phpstan.org/user-guide/ignoring-errors

jtojnar commented 1 year ago

I just noticed this with Container::onValidate – the property is expected to contain array<callable(static, T): void|callable(static, array): void|callable(T): void|callable(array): void> where T can be any object type but that is not expressible in PHPStan type language since containers like arrays are invariant in their item template types.

Would changing the stubs to just array<callable> and adding specific rules as a replacement be acceptable?

Comparison of the various type signatures: https://phpstan.org/r/a8969a90-ac6f-47f6-b11f-8df10e8f7e95

uestla commented 1 year ago

@martenb I solved this with a custom Form class:

/** @property array<callable(self, \Nette\Utils\ArrayHash $values): void> $onSuccess */
class Form extends \Nette\Application\UI\Form
{}