Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Leverage First-class callable syntax #47672

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 17, 2022

Conversation

tigitz
Copy link
Contributor

@tigitz tigitz commented Sep 23, 2022

Q A
Branch? 6.2
Bug fix? no
New feature? no
Deprecations? no
Tickets -
License MIT
Doc PR -

Rationale

https://wiki.php.net/rfc/first_class_callable_syntax

Mainly:

The advantage is that the new syntax is accessible to static analysis, and respects the scope at the point where the callable is created.

I'd argue that it also improves readability and IDE color syntax also helps:

image

I've manually reviewed each changes and discarded some of them where [Foo::class, 'method'] was intended to be tested with this specific syntax

@tigitz
Copy link
Contributor Author

tigitz commented Sep 23, 2022

There are related failures in the test suite, I'm looking into it.

@tigitz tigitz force-pushed the first-class-callable-syntax branch from 3a2b728 to 34532a1 Compare September 25, 2022 23:16
@tigitz
Copy link
Contributor Author

tigitz commented Sep 25, 2022

So I've dug a little more to properly implement these improvements. Hopefully, I got a good enough understanding now.

Mainly I've been reminded that

$this->foo(...) === $this->foo(...) // false
[$this, 'foo'] === [$this, 'foo'] // true

Even though both are callables, they are Closure and array respectively. So switching one with the other is not as straightforward as I previously thought.

This has consequences on unit tests where equality is tested. Symfony public api returning callables with the array syntax form must be kept that way and therefore their related tests too.

A couple more points:

  • As stated by @stof \Symfony\Component\DependencyInjection\Definition::setFactory doesn't support closures.

  • I refrained from applying this in \Symfony\Component\EventDispatcher\EventDispatcher::addSubscriber

--- a/src/Symfony/Component/EventDispatcher/EventDispatcher.php
+++ b/src/Symfony/Component/EventDispatcher/EventDispatcher.php
@@ -163,10 +163,10 @@ class EventDispatcher implements EventDispatcherInterface
             if (\is_string($params)) {
                 $this->addListener($eventName, [$subscriber, $params]);
             } elseif (\is_string($params[0])) {
-                $this->addListener($eventName, [$subscriber, $params[0]], $params[1] ?? 0);
+                $this->addListener($eventName, $subscriber->{$params[0]}(...), $params[1] ?? 0);
             } else {
                 foreach ($params as $listener) {
-                    $this->addListener($eventName, [$subscriber, $listener[0]], $listener[1] ?? 0);
+                    $this->addListener($eventName, $subscriber->{$params[0]}(...), $listener[1] ?? 0);
                 }
             }
         }

As it changes the expected behavior of what's stored inside the listeners (closure instead of array) when adding a Subscriber.
Even though it's valid, as the param is typed array|callable, it could break userland code if they implicitly rely on having an array here when addSubscriber is called.

  • I've reverted updates on EventDispatcherTest::testGetLazyListeners , testRemoveFindsLazyListeners, testPriorityFindsLazyListeners as it fails and I don't understand what it's actually testing to fix them. Maybe @nicolas-grekas can provide some guidance here 🙏
  • I've reverted updates on the ErrorHandler component as it breaks a lot of tests and there's too much dark magic going on to make the modernizing effort worth it.
  • It seems \Symfony\Component\HttpKernel\Controller\ArgumentResolver\ServiceValueResolver::resolve doesn't support $request->attributes->get('_controller') returning a Closure. TBC.

Ready to be reviewed again. Test failures are not related.

@tigitz tigitz requested review from chalasr and removed request for xabbuh and yceruto September 25, 2022 23:37
@tigitz tigitz requested review from stof and removed request for chalasr September 25, 2022 23:37
Copy link
Member

@nicolas-grekas nicolas-grekas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mainly I've been reminded that

$this->foo(...) === $this->foo(...) // false
[$this, 'foo'] === [$this, 'foo'] // true

Note this also: $this->foo(...) == $this->foo(...) // true, see #46262

As stated by @stof \Symfony\Component\DependencyInjection\Definition::setFactory doesn't support closures.

It might but we first need to teach PhpDumper how to dump such closures. There might be an issue with closures created out of non-public methods though.

I refrained from applying this in \Symfony\Component\EventDispatcher\EventDispatcher::addSubscriber

You did right, this would badly break BC.

I've reverted updates on EventDispatcherTest::testGetLazyListeners

We test lazy-listeners there: those are not native php callables so they cannot use first-class callable syntax (they are [\Closure, string] tuples.)

I've reverted updates on the ErrorHandler component as it breaks a lot of tests and there's too much dark magic going on to make the modernizing effort worth it.

No dark magic here, just regular php error handling ;) Yes, adopting a new syntax should not lead to invasive changes.

It seems ServiceValueResolver::resolve doesn't support $request->attributes->get('_controller') returning a Closure.

It does: it skips them. That's expected: controllers-as-services are never dumped as closures anyway.

@tigitz tigitz force-pushed the first-class-callable-syntax branch from 34532a1 to 26d9ce9 Compare September 30, 2022 20:35
@tigitz
Copy link
Contributor Author

tigitz commented Sep 30, 2022

@nicolas-grekas Thanks for your thorough review, very motivating :)

Ready to be reviewed again. 👍

@nicolas-grekas
Copy link
Member

Thank you @tigitz.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants