WEBVTT

NOTE Created by CaptionSync from Automatic Sync Technologies www.automaticsync.com

00:00:01.066 --> 00:00:04.506 align:middle
Because this service is instantiated
on every request...

00:00:04.806 --> 00:00:10.266 align:middle
it means that all four of the objects in its
constructor also need to be instantiated.

00:00:10.846 --> 00:00:12.796 align:middle
That's not a huge deal...

00:00:13.036 --> 00:00:19.346 align:middle
except that two of these services probably
wouldn't be instantiated during a normal request

00:00:19.776 --> 00:00:25.236 align:middle
and aren't even used unless the
current request is a login form submit.

00:00:26.086 --> 00:00:29.396 align:middle
In other words, we're always
instantiating these objects...

00:00:29.526 --> 00:00:31.516 align:middle
even though we don't need them!

00:00:32.246 --> 00:00:33.346 align:middle
How can we fix this?

00:00:33.826 --> 00:00:38.486 align:middle
By using a service subscriber:
it's a strategy in Symfony

00:00:38.716 --> 00:00:40.946 align:middle
that allows you to get a service you need...

00:00:41.186 --> 00:00:48.726 align:middle
but delay its instantiation until - and
unless - you actually need to use it.

00:00:49.616 --> 00:00:51.116 align:middle
It's great for performance.

00:00:51.356 --> 00:00:56.136 align:middle
But, like many things, it comes
at a cost: a bit more complexity.

00:00:56.916 --> 00:01:01.236 align:middle
Start by adding an interface to this
class: ServiceSubscriberInterface.

00:01:01.946 --> 00:01:05.746 align:middle
Then I'll move to the bottom of the
file, go to the "Code -&gt; Generate" menu -

00:01:05.776 --> 00:01:09.636 align:middle
or Command + N on a Mac - and
select "Implement Methods"

00:01:09.746 --> 00:01:15.016 align:middle
to generate the one method this interface
requires: getSubscribedServices().

00:01:16.006 --> 00:01:17.536 align:middle
What does this return?

00:01:18.106 --> 00:01:21.816 align:middle
An array of type-hints for
all the services we need.

00:01:21.816 --> 00:01:24.336 align:middle
For this class, it's these four.

00:01:29.386 --> 00:01:36.256 align:middle
So, return EntityManagerInterface::class,
UrlGeneratorInterface::class,

00:01:36.636 --> 00:01:42.486 align:middle
CsrfTokenManagerInterface::class
and OtherLongInterfaceName::class.

00:01:42.926 --> 00:01:46.556 align:middle
Uh, UserPasswordEncoderInterface::class.

00:01:47.746 --> 00:01:51.236 align:middle
By doing this, we can now
remove these four arguments.

00:01:55.336 --> 00:02:00.076 align:middle
Replace them with ContainerInterface -
the one from Psr\Container - $container.

00:02:02.006 --> 00:02:07.766 align:middle
When Symfony sees the new interface and
this argument, it will pass us a, sort of,

00:02:07.996 --> 00:02:11.606 align:middle
"mini-container" that holds
the 4 objects we need.

00:02:12.316 --> 00:02:18.006 align:middle
But it does this in a way where those 4
objects aren't created until we use them.

00:02:18.006 --> 00:02:21.006 align:middle
Finish this by removing the old properties...

00:02:21.286 --> 00:02:23.486 align:middle
and having just one: $container.

00:02:24.436 --> 00:02:26.886 align:middle
Set it with $this-&gt;container = $container.

00:02:28.146 --> 00:02:32.076 align:middle
Because those properties are gone, using
the services looks a bit different.

00:02:32.076 --> 00:02:39.906 align:middle
For example, down here for CsrfTokenManager,
now we need to say $this-&gt;container-&gt;get()

00:02:39.906 --> 00:02:46.186 align:middle
and pass it the type-hint
CsrfTokenManagerInterface::class.

00:02:47.046 --> 00:02:50.416 align:middle
This will work just like before except

00:02:50.546 --> 00:02:56.366 align:middle
that the CsrfTokenManager won't be
instantiated until this line is hit...

00:02:56.826 --> 00:03:00.566 align:middle
and if this line isn't hit,
it won't be instantiated.

00:03:00.566 --> 00:03:08.436 align:middle
For entityManager, use $this-&gt;container
-&gt;get(EntityManagerInterface::class),

00:03:08.436 --> 00:03:16.566 align:middle
for passwordEncoder, $this-&gt;container
-&gt;get(UserPasswordEncoderInterface::class)

00:03:17.126 --> 00:03:19.816 align:middle
and finally, for urlGenerator,

00:03:20.186 --> 00:03:27.826 align:middle
use $this-&gt;container-&gt;get
-&gt;(UrlGeneratorInterface::class).

00:03:29.026 --> 00:03:33.146 align:middle
I'll copy that and use it
again inside getLoginUrl().

00:03:34.306 --> 00:03:36.976 align:middle
So, a little bit more complicated...

00:03:37.136 --> 00:03:40.966 align:middle
but it should take less resources
to create this class.

00:03:41.586 --> 00:03:47.496 align:middle
The question is: did this make enough
difference for us to want this added complexity?

00:03:47.986 --> 00:03:48.696 align:middle
Let's find out.

00:03:48.696 --> 00:03:55.436 align:middle
First, clear the cache: And
warm it up: Move back over...

00:03:56.016 --> 00:03:59.036 align:middle
I'll close some tabs and...

00:04:03.156 --> 00:04:08.506 align:middle
refresh. Profile again: I'll call this one:
[Recording] Homepage service subscriber:

00:04:10.906 --> 00:04:18.606 align:middle
https://bit.ly/sf-bf-service-subscriber.

00:04:18.606 --> 00:04:19.596 align:middle
View the call graph.

00:04:19.876 --> 00:04:21.446 align:middle
Excellent!

00:04:23.136 --> 00:04:26.076 align:middle
Go back to the "Memory" dimension
and search for "login".

00:04:26.076 --> 00:04:29.066 align:middle
The call is still here but it's taking
a lot less memory and less time.

00:04:29.066 --> 00:04:30.366 align:middle
Let's compare this to be sure though.

00:04:30.916 --> 00:04:35.066 align:middle
Click back to the homepage and go
from the previous profile to this one:

00:04:37.536 --> 00:04:41.896 align:middle
https://bit.ly
/sf-bf-service-subscriber-compare.

00:04:41.896 --> 00:04:43.826 align:middle
Nice! The wall time is down by 4%...

00:04:43.826 --> 00:04:45.996 align:middle
CPU is down and memory also decreased...

00:04:45.996 --> 00:04:47.056 align:middle
but just a little bit.

00:04:47.056 --> 00:04:48.576 align:middle
So was this change worth it?

00:04:49.086 --> 00:04:55.306 align:middle
Probably. But this doesn't mean you should run
around and use service subscribers everywhere.

00:04:56.016 --> 00:04:59.986 align:middle
Why? Because they add complexity
to your code and,

00:05:00.196 --> 00:05:05.496 align:middle
unless you have a specific situation,
it won't help much or at all.

00:05:06.216 --> 00:05:09.606 align:middle
Use Blackfire to find the real
problems and target those.

00:05:09.606 --> 00:05:15.856 align:middle
For example, we also could have made this
same change to our AgreeToTermsSubscriber.

00:05:16.446 --> 00:05:20.086 align:middle
This class is also instantiated
on every request...

00:05:20.626 --> 00:05:22.996 align:middle
but rarely needs to do its work.

00:05:23.836 --> 00:05:29.426 align:middle
That means we are causing the FormFactory
object to be instantiated on every request.

00:05:30.516 --> 00:05:32.726 align:middle
But, go back to the latest profile...

00:05:34.936 --> 00:05:36.786 align:middle
click to view the memory dimension...

00:05:37.766 --> 00:05:39.506 align:middle
and search for "agree".

00:05:40.056 --> 00:05:40.596 align:middle
There it is!

00:05:40.996 --> 00:05:46.786 align:middle
It took 1.61 milliseconds and 41
kilobytes to instantiate this.

00:05:47.516 --> 00:05:50.786 align:middle
That's... a lot less than
the login authenticator.

00:05:51.646 --> 00:05:55.196 align:middle
So, is making this class a
service subscriber worth it?

00:05:55.196 --> 00:05:56.666 align:middle
For me, no.

00:05:56.916 --> 00:06:00.666 align:middle
I'd rather get back to writing features
or fixing bigger performance issues.

00:06:01.726 --> 00:06:08.396 align:middle
Next, we can take a lot more control of the
profiling process, like profiling just a portion

00:06:08.396 --> 00:06:14.246 align:middle
of our code or automatically triggering
a profile based on some condition,

00:06:14.476 --> 00:06:17.546 align:middle
instead of needing to manually
use the browser extension.

00:06:18.106 --> 00:06:20.956 align:middle
Let's talk about the Blackfire SDK next.

